mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-21 04:45:12 +00:00
fix/patch-cli-sync
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c07d3d95d4 |
feat: add sqlite drizzle persistence (#919)
* feat: add drizzle agent schema * feat: run sqlite drizzle migrations * refactor: remove old sql identity dependency * feat: store harness agents in sqlite * build: package db migrations * refactor: remove sqlite oauth token store * feat: restore oauth token storage * fix: handle empty install id * chore: ignore server runtime state * fix: address review feedback for PR 919 |
||
|
|
f2ac87d7c3 |
feat: show created agents in sidepanel (#865)
* feat(agent): list created agents in sidepanel target catalog * feat(agent): show created agents in sidepanel selector * feat(server): add sidepanel chat route for created agents * feat(agent): route sidepanel agent sends by agent id * chore(agent): retire virtual sidepanel acp targets * fix: address review feedback for PR #865 |
||
|
|
e2ec1991cf |
feat(agents): redesign the agent command center for multi-adapter use (#861)
* feat(agents): redesign agent rail to match the rest of the app
Reshape the `/agents` page so it reads as a sibling of `/scheduled`
and `/soul` and adapts to the multi-adapter world (OpenClaw, Claude
Code, Codex). Visual scaffolding only in this commit — per-agent
liveness state ships as `unknown` until the server-side activity
tracker lands.
- New `AgentsHeader` mirrors `SoulHeader`/`ScheduledTasksHeader`:
accent bot tile, title, descriptive subtitle, "+ New Agent"
button. Replaces the loose top toolbar that mixed page-level and
OpenClaw-lifecycle controls.
- New `GatewayStatusBar` collects the OpenClaw lifecycle pills
(running, control plane connected) plus the Terminal/Refresh
affordances into a single labeled bar that only renders when the
gateway is running AND there is at least one OpenClaw agent in
the merged list.
- New `AgentRowCard` per agent: adapter tile with liveness dot,
name + status badge, adapter/model/reasoning chips, last-used
relative time + truncated workspace path, primary "Chat" button,
overflow menu (Copy id / Rename* / Reset history* / Delete).
Rename + Reset are disabled with "coming soon" tooltips until
the corresponding endpoints ship; Delete is hidden for the
protected `main` agent.
- New `AgentsEmptyState` mirrors the scheduled-tasks empty card.
- New `AdapterIcon` + `LivenessDot` + `agent-display.helpers.ts`
keep the row card focused on layout; helpers cover display name
fallbacks for legacy `oc-<uuid>` titles, workspace label rules,
and a tiny relative-time formatter.
- `AgentList` now sorts by `lastUsedAt` desc with `null`s falling
to the bottom; the gateway's `main` agent is pinned to the top
only while it has zero turns so a fresh install has an obvious
starting point. The list also threads a per-agent activity map
so future commits can light up working/idle/asleep without
reshuffling the API.
- `AgentsPage` swaps to the standard `fade-in slide-in-from-bottom-5
animate-in space-y-6 duration-500` shell and threads a
`harnessAgentLookup` Map down to the row card so adapter chips
and reasoning effort render correctly without a re-fetch.
* feat(agents): wire per-agent liveness end-to-end into the rail
Closes the placeholder `unknown` dot from the redesign's first
commit. The rail now shows real working / idle / asleep / error
states per agent, with `lastUsedAt` driving the recency sort.
Server side:
- `AgentHarnessService` keeps an in-memory activity tracker keyed
by agentId. `notifyTurnStarted` flips an entry to `working`,
`notifyTurnEnded({ok})` either drops it (success) or pins it to
`error` (failure / error event).
- `send()` wraps the runtime stream so the lifecycle hook fires
exactly once on natural close, error event, downstream cancel,
or thrown setup. The runtime itself stays unchanged — fork is
contained at the harness layer.
- New `listAgentsWithActivity()` method enriches every agent with
`{ status, lastUsedAt }`. lastUsedAt is read from the acpx
session record's last persisted item via `runtime.getHistory`,
so it survives server restart even though the activity map
doesn't.
- Status derivation: `working`/`error` take precedence; otherwise
timestamp-based — `idle` until 15 min of silence, then `asleep`.
Never-used agents resolve to `idle` (asleep implies "was active,
went quiet").
- `GET /agents` returns the enriched shape.
Client side:
- `HarnessAgent` UI type extended with optional `status` +
`lastUsedAt` so older deployments still typecheck.
- `useHarnessAgents` flips on `refetchInterval: 5_000` (with
`refetchIntervalInBackground: false` so hidden tabs go quiet)
so the per-row dots and last-used copy stay fresh without a
websocket.
- `AgentsPage` builds an activity map from the harness listing
response and threads it into `AgentList` → `AgentRowCard`. The
sort by `lastUsedAt` desc (already in the row card) now has
real data to operate on.
Tests:
- New `marks an agent working while a turn streams and idle once
it ends` exercises the wrap; uses a held upstream stream so
the in-flight `working` state is observable.
- New `flips to error when a turn emits an error event`.
* fix(agents): dedupe agent rail when /claw/agents and /agents share an id
The agents page was rendering every OpenClaw agent twice — once from
the legacy `/claw/agents` listing (`useOpenClawAgents`) and once from
the harness `/agents` listing (`useHarnessAgents`). Post Step 9
backfill the harness store contains every gateway agent, so the
overlap is the rule, not the exception.
Mirror the dedup the chat-panel layout already does: when a gateway
agent's id appears in the harness listing, drop the legacy entry and
keep the harness one (it has adapter/model/reasoning/status/lastUsedAt
the chat path actually consumes).
* feat(agents): swap GatewayStatusBar refresh icon for a Restart Gateway button + tooltips
The manual refresh became redundant once `useHarnessAgents` and
`useOpenClawStatus` started polling on a 5s interval — every visible
field self-refreshes within seconds. The previous AgentsPageHeader
had a real Restart action that the redesign dropped; reinstate it on
the bar so a wedged gateway is one click away again.
- GatewayStatusBar: dropped the `RotateCcw` refresh icon and the
`onRefresh` prop. Added `onRestart` + `actionInProgress` props;
the button shows a spinner while a gateway lifecycle mutation is
in flight.
- Both Terminal and Restart Gateway buttons get tooltips explaining
what they do — Terminal as a power-user shell escape hatch,
Restart for unsticking a wedged gateway or after manual config
edits.
- AgentsPage: drop the now-unused `refreshAll` helper and the
`refetchStatus`/`refetchAdapters`/`refetchOpenClawAgents`
destructures it depended on. Wire `restartOpenClaw` (already
pulled from `useOpenClawMutations`) through
`runWithPageErrorHandling` like the legacy header did.
* feat(agents): consolidate gateway status into the /agents listing
Folds the gateway lifecycle snapshot into the harness listing so the
agents page polls one endpoint instead of two. Drops the dead
`/claw/status` call from the command center while keeping every UI
affordance the page already shipped (Running / Control plane
connected pills, GatewayStateCards setup/start prompts,
ControlPlaneAlert for degraded states).
Server side:
- `OpenClawProvisioner.getStatus()` (optional) — when wired, returns
the same `GatewayStatusSnapshot` shape `/claw/status` does.
- `AgentHarnessService.getGatewayStatus()` — best-effort wrapper
around the provisioner method; logs and swallows errors so a
transient gateway issue doesn't 500 the listing endpoint.
- `GET /agents` now returns `{agents, gateway}` in a single
`Promise.all`. Both fields are independent — agents enrichment
succeeds even if the gateway snapshot is null.
- `server.ts` wires `getOpenClawService().getStatus()` into the
provisioner accessor object alongside `createAgent` /
`removeAgent` / `listAgents`.
Client side:
- `useHarnessAgents` returns `{harnessAgents, gateway}` (plus the
legacy `agents` mapping). Same 5s `refetchInterval` as before —
one round-trip drives the per-row liveness AND the gateway pills.
- `AgentsPage` drops `useOpenClawStatus` entirely; `status` comes
from the harness query. Loader + error/lifecycle plumbing
rewired around the harness query's loading/error.
- `agents-page-utils.getInlineError` and `getAgentsLoading` lose
the now-redundant `statusError` / `statusLoading` /
`openClawAgentsEnabled` params.
The chat-panel layout (`agent-command-layout.tsx`) still consumes
`useOpenClawStatus(5000)` for now — left intact per the user's "only
the command center" scope. Folding that one in is a separate,
smaller pass once we're sure no regression slipped here.
* test(agents): teach the route fake service about the new listing shape
PR #861 CI surfaced two failures in tests/api/routes/agents.test.ts:
both call \`GET /agents\` and the route handler now invokes
\`service.listAgentsWithActivity()\` + \`service.getGatewayStatus()\`
which the fake created here didn't implement. Add both methods to
the fake (returning idle / null) and update the empty-list assertion
to expect the new \`{agents, gateway}\` envelope.
|
||
|
|
0c84547e8f |
feat(agents): migrate OpenClaw chat onto the unified harness/ACP path (#859)
* chore(acp): smoke-test ACP capabilities against running gateway
Adds apps/server/scripts/acp-smoke.ts which spawns `openclaw acp`
inside the gateway container and exercises every method we plan to
depend on: initialize, newSession, prompt (text + image), cancel,
listSessions, loadSession.
SDK pinned to 0.19.1 (Bun's minimum-release-age policy blocks 0.20+
which were released < 7 days ago).
Findings (full notes in plan outcomes):
- promptCapabilities advertises image:true but the model does NOT see
image bytes — silently dropped at the bridge.
- sessionCapabilities advertises {list:{}} but session/list throws
"Method not found": stale capability advertising.
- loadSession works; replays user/assistant/thought text and
session_info/usage/commands updates. No tool_call replay, as
documented.
- cancel works end-to-end: stopReason=cancelled.
- closeSession/resumeSession are not on ClientSideConnection in
0.19.1; kill child to close, use loadSession for rebind.
Plan revisions triggered by spike are recorded in
plans/browseros-ai/BrowserOS/features/2026-04-28-2310-claude-code-acp-implementation-roadmap.md.
* chore(acp): re-run smoke on SDK 0.21.0 and add mode/config/auth scenarios
After bypassing Bun's minimum-release-age and upgrading the SDK to
0.21.0, restore the previously-skipped resume/close paths and add
three new scenarios: mode (setSessionMode), config (setSessionConfigOption,
correct configId field), and auth (authenticate noop).
Findings, all bridge-side (independent of SDK):
- session/list, session/resume, session/close all throw -32601 on
OpenClaw 2026.4.12 — capability advertising is stale.
- Image content blocks silently dropped; model never sees the bytes.
- setSessionMode and setSessionConfigOption work; latter requires
`configId` (not `optionId`) per the schema.
- loadSession replays user/assistant/thought text + session_info +
usage + available_commands; no tool_call replay (documented).
- authenticate is a noop on OpenClaw (no authMethods advertised).
Plan outcomes updated with full method-support matrix.
* chore(deps): promote @agentclientprotocol/sdk to a runtime dependency
The smoke script in apps/server/scripts/acp-smoke.ts used the SDK as
devDependency. The upcoming ACP bridge (apps/server/src/api/services/acp/)
needs it at runtime, not just for tooling. Move the entry from
devDependencies to dependencies, alphabetically first under @a*.
Pinned to 0.21.0 — same version the smoke script validated against.
README gains a small Dependencies note pointing at the future bridge
location.
No code changes yet. The bridge wiring lands in subsequent commits.
* fix(openclaw): wire LlmProvider.supportsImages through to OpenClaw model config
When BrowserOS sets up a custom OpenAI-compat provider on the gateway,
the agent UI's "Supports Image" flag (LlmProviderConfig.supportsImages)
was being dropped on the floor. As a result the persisted model entry
had no `input` field, OpenClaw defaulted it to ['text'], and image_url
content parts were silently stripped before the model saw them.
Fix:
- Extend OpenClawSetupInput / OpenClawAgentMutationInput on the agent
side (useOpenClaw.ts) and the route body schema + SetupInput +
createAgent input on the server side with `supportsImages?: boolean`.
- AgentsPage forwards `llmOption?.supportsImages` from the selected
LlmProviderConfig in both handleSetup and handleCreate.
- provider-map.resolveSupportedOpenClawProvider emits
`input: ['text', 'image']` on the model entry when the flag is
truthy; otherwise emits the explicit `['text']` so the value is
always pinned (avoids relying on OpenClaw's implicit default).
- applyBrowserosConfig adds `tools.media.image.enabled = true` to the
bootstrap batch so the gateway's image-understanding pipeline is
always wired up — per-model `input` still gates which models see
images, this just enables the global path.
ACP image content blocks are still dropped by the OpenClaw bridge —
that's a separate bridge bug, not addressed here. This commit
restores image support for the OpenAI-compat /v1/chat/completions
path that the upcoming ACP chat panel will use as a carve-out for
image-bearing prompts.
Existing custom-provider configs are NOT auto-migrated; users will
re-acquire image support either by re-running setup or by editing
their model entries' `input` field manually. A migration pass for
legacy installs is not in scope for this commit because the
"supportsImages" intent isn't recoverable from the persisted config
alone — the source of truth is the LlmProvider record on the agent
side.
* feat(agents): add OpenClaw to AgentAdapter union and catalog
Extends AgentAdapter to 'claude' | 'codex' | 'openclaw' and adds the
OpenClaw entry to AGENT_ADAPTER_CATALOG. The new entry has:
- defaultModelId: 'default' — OpenClaw's ACP bridge does not surface
per-session model selection (verified during the ACP spike), so
models live in the OpenClawService config, not in the adapter
catalog. AgentDefinition.modelId carries the gateway-side model
name for display only.
- models: [] — empty list signals "no per-session model picker" in
the UI; isSupportedAgentModel('openclaw', undefined|'default')
returns true via the existing fallback path.
- reasoningEfforts mirror OpenClaw's session-level `thought_level`
config option (off / minimal / low / medium / high / adaptive).
Also extends:
- isAgentAdapter type guard recognizes 'openclaw'
- HarnessAgentAdapter union on the extension side
- agents.test.ts createAgent fake type
- agent-catalog.test.ts asserts on the new entry, empty model list
passthrough behavior, and OpenClaw's reasoning effort set
Lockfile delta is the workspace SDK pin reconciling 0.20.0 (taken
from dev's lock) up to our package.json's 0.21.0 (added in
|
||
|
|
cb32b8191d |
fix: show rich ACP harness history from ACPX (#852)
* fix: load ACP harness history from ACPX * fix: address ACP history review comments |
||
|
|
91d3285aa0 |
feat: add ACP agent harness (#849)
* feat: add acp agent runtime spike * feat: add agent harness catalog * feat: persist harness agents in json * feat: persist agent transcripts * feat: route harness service through agent records * feat: expose generic agent harness routes * feat: add harness agent frontend api * feat: create harness agents from agents page * feat: chat with persisted harness agents * chore: remove obsolete agent profile spike * chore: self-review fixes * fix: combine openclaw and harness agents UI * refactor: split agents page components * fix: hide persisted harness turns |