feat(agent): unify MCP tools and adopt Responses delivery
Move project and host queries into native MCP with host-owned OAuth/context, while retaining memory, skills, actions and publication plugins. Add nearby-model queries and explicit chat/task/learning model defaults. Adopt Responses HTTP/SSE and native steer/queue inbox delivery, preserving scoped session ownership, pending input edits and investigation communication. Disable local-provider discovery: Server /health allowed native vLLM to probe /v1/models on port 8000. A native before/after regression prevents recurrence. Validation: 170 focused Bun tests; service/plugin typechecks; native discovery, provider-discovery and input-inbox smoke checks; no paid model inference.
This commit is contained in:
@@ -14,7 +14,7 @@ Read [README.md](README.md) for setup, configuration, and operational behavior.
|
||||
- `src/uiEnvelope/` owns the `agent-ui@1` compatibility protocol and registry.
|
||||
- `src/runtime/` owns OpenCode lifecycle, readiness, and workspace binding.
|
||||
- `src/sandbox/` and `scripts/landlock_sandbox.py` own Shell enforcement.
|
||||
- `src/sessions/`, `src/results/`, `src/memory/`, and `src/learning/` retain their
|
||||
- `src/sessions/`, `src/memory/`, and `src/learning/` retain their
|
||||
respective persistence responsibilities.
|
||||
- `.opencode/` contains trusted service instructions, plugins, and tools.
|
||||
- `.opencode/agent-plugin.json` describes agents, plugins, Skill storage, and MCP
|
||||
@@ -35,7 +35,11 @@ from the process working directory. `agent-models.local.json` is ignored by Git
|
||||
and the Docker build.
|
||||
|
||||
- Define provider IDs, `api_url`, API key references, models, aliases, capabilities,
|
||||
limits, and chat/task/learning role defaults in that file.
|
||||
limits, and role defaults in that file. Group role defaults under `defaults`:
|
||||
`chat`, `task` and `learning_gate` are all required explicit nonempty model
|
||||
references, with no role inheritance. Keep model definitions under
|
||||
`providers.<id>.models` and preserve public `provider/model` references.
|
||||
Legacy top-level role keys are rejected.
|
||||
- Generate OpenCode definitions and the public chat model menu from it through
|
||||
`src/chat/modelConfig.ts` and `src/runtime/opencode2-config.ts`.
|
||||
- Do not add independent model defaults in `opencode.json`, agent frontmatter,
|
||||
@@ -67,8 +71,12 @@ OpenCode configuration and plugins.
|
||||
|
||||
## Runtime and Security
|
||||
|
||||
Production chat requests require Bearer authorization and `X-Project-Id`, verified
|
||||
by TJWater Server. Preserve actor/project/user ownership checks on session create,
|
||||
Production chat always requires Server-verified Bearer authorization. Personal
|
||||
chat uses `/api/v1/access-context` without a project; project chat also requires
|
||||
`X-Project-Id` and `/api/v1/agent-auth-context`. Personal chat must never acquire
|
||||
project business credentials or fall back from failed verification to local
|
||||
identity. Use a user-specific personal key for memory and chat storage. Preserve
|
||||
actor/scope/user ownership checks on session create,
|
||||
read, actions, and MCP status. Development-only local context does not grant
|
||||
business-data access. Never accept a tool-supplied identity, project scope,
|
||||
authorization header, or arbitrary Server URL.
|
||||
@@ -89,37 +97,113 @@ the external OpenCode server password, and trusted assets loaded through
|
||||
the Agent workspace root. Prefer `bun run start:integration:isolated` when an
|
||||
existing user service must remain available. Stop only processes started for the
|
||||
current task; do not terminate unrelated services.
|
||||
The isolated integration launcher must pin `OPENCODE_DB` under its own data
|
||||
root rather than inherit a caller's database override. After that environment
|
||||
stops, its XDG cache may be regenerated; preserve native data, snapshots,
|
||||
chat workspaces and audit records unless their deletion is explicitly requested.
|
||||
|
||||
Preserve static sensitive-path denials in `opencode.json`, explicit approval for
|
||||
Shell/file edits, and disabled subagents. Do not replace enforcement with prompt
|
||||
Shell/file edits, and disabled subagents for ordinary chat, task collaboration,
|
||||
and learning. Only the trusted active `task_execution` coordinator may launch
|
||||
`investigation-reader`, at most two foreground children and one level deep.
|
||||
Readers inherit only task-scoped query access, never report/action publication,
|
||||
Shell, file, or recursive delegation permissions. Do not replace enforcement with prompt
|
||||
instructions. The Shell replacement must retain Landlock/seccomp, credential
|
||||
isolation, cancellation, process-group cleanup, and denied alternate host Shell
|
||||
entry points. Code Mode must not bypass these controls.
|
||||
|
||||
## Workspaces and Persistence
|
||||
|
||||
`CONVERSATION_WORKSPACE_ROOT` defaults to `.agent-workspaces/`, separate from
|
||||
protected `data/` and `logs/`. `src/runtime/conversationWorkspace.ts` creates one
|
||||
`conversation-<uuid>` per native session, with writable `files/`, `tmp/`, and
|
||||
`.cache/`; the location root is read-only and Shell starts in `files/`.
|
||||
`CONVERSATION_WORKSPACE_ROOT` defaults to `data/session-workspaces/`.
|
||||
`src/runtime/conversationWorkspace.ts` owns validated directory paths and native
|
||||
bindings. Persistent sessions use `actor-*/personal/session-<sha256>/` or
|
||||
`actor-*/project-*/session-<sha256>/`. Each contains host-owned `chat/` and a
|
||||
`workspace/` child with writable `files/`, `tmp/`, and `.cache/`.
|
||||
|
||||
`src/sessions/workspace-store.ts` owns chat directories and immutable ownership
|
||||
files. Inject the same store into metadata, UI state and transcript stores in
|
||||
`src/server.ts`. Keep `data/session-metadata/` as the owner/history index; new
|
||||
messages, transcripts and learning state go only to `chat/`. Preserve full identity checks on
|
||||
reads and lists, session filename collision rejection, and serialized ownership
|
||||
creation. Scope changes in the frontend start a new conversation and use
|
||||
independent history caches; they do not silently reassign existing sessions.
|
||||
|
||||
Bind OpenCode only to `workspace/`. Its file tools must check the native session
|
||||
hash as well as canonical paths; Shell cannot reach sibling `chat/`. Chat
|
||||
directories are `0700`, record files `0600`; never place transcripts or bearer
|
||||
credentials in model-writable directories. Unscoped `conversation-<uuid>`
|
||||
directories are retained for temporary probes/generation and legacy migration.
|
||||
|
||||
Keep canonical-path and symlink checks, per-session access restrictions, native
|
||||
session directory bindings, and empty independent workspaces for new branches.
|
||||
Do not copy source code, credentials, or other sessions into a workspace.
|
||||
|
||||
Generate scoped native read/edit permissions for managed workspaces without
|
||||
opening all of `data/`. Preserve sensitive-path denials and later administrator
|
||||
rules; the plugin must still limit file access to the current session. Keep Shell
|
||||
execution approval and kernel restrictions. Prefer session-relative file paths.
|
||||
|
||||
Legacy `.agent-workspaces/`, integration `conversation-workspaces/`, and flat
|
||||
conversation directories are moved before continued execution, preserving files, then rebound
|
||||
through the native Session API. Failed binding updates must be retryable after a
|
||||
filesystem move, and existing destination directories must never be overwritten.
|
||||
Read-only MCP status queries may resolve moved files without moving sessions.
|
||||
|
||||
At startup copy legacy UI states into the indexed owner's chat directory and
|
||||
transcripts into their recorded actor/scope directory, and indexed learning state
|
||||
into `chat/learning.json`. Archive original bytes under
|
||||
`PERSISTENCE_BACKUP_DIR/legacy-chat/` only after verifying the backup. Keep a
|
||||
versioned migration manifest; never overwrite new records during repeated migration or
|
||||
guess an owner for an unindexed UI state. Legacy UI/transcript/learning storage
|
||||
environment variables select migration sources, not a second active record store.
|
||||
Verified migration backups may be removed when explicitly requested; preserve
|
||||
the migration receipt and active scoped records. Do not recreate empty legacy
|
||||
UI/transcript/learning directories when workspace storage is configured.
|
||||
|
||||
Workspaces contain persistent session files. They currently have no expiration
|
||||
cleanup, and deleting chat metadata does not remove their directories. Do not
|
||||
clean them as build artifacts or describe them as automatically disposable.
|
||||
Startup probes, warmup, and failed creation clean their own temporary workspaces.
|
||||
cleanup. Deleting a session marks its index and host-owned chat directory before
|
||||
cancelling work, then removes native history, chat content, learning state,
|
||||
calculation files and that session's legacy records/backups. Keep minimal owner
|
||||
and deletion markers; queued writes and migration must not revive deleted chats.
|
||||
Cleanup errors must return a retryable response, never success with unfinished
|
||||
cleanup. Archived chats retain their records. Session lists use a scoped
|
||||
in-process index updated by the owning store; one Agent process owns writes to
|
||||
each data root. Do not mutate index files behind that cache.
|
||||
Do not clean session files as build artifacts or describe them as automatically
|
||||
disposable. Startup probes, warmup, title and learning helpers, and failed creation
|
||||
clean their own native sessions and temporary workspaces. Cleanup must validate
|
||||
scope, canonical paths and session hash and wait for native execution to stop.
|
||||
Changing the root requires preserving directory bindings and associated native
|
||||
session data; do not silently move or delete existing user files.
|
||||
|
||||
Deployment must preserve the workspace, Agent data, Skill files, and OpenCode
|
||||
session database. Mounting only `/app/data` does not preserve session files.
|
||||
Result-reference TTL cleanup is separate from workspace retention.
|
||||
Deployment must preserve Agent data, Skill files, and the OpenCode session
|
||||
database. With the default root, mounting `/app/data` also preserves session files;
|
||||
custom workspace roots require their own persistent mount.
|
||||
|
||||
Independent result-reference storage, its TTL loop, and the result-ref read API
|
||||
have been retired after checking that no business producer or consumer uses them.
|
||||
Store file results in a session workspace and reference them by session ID plus
|
||||
relative path. Do not replace scoped access checks with arbitrary host paths or
|
||||
reintroduce a separate result-reference store without an actual consumer.
|
||||
|
||||
## MCP and Business Boundaries
|
||||
|
||||
Project and host read-only query tools use the native `mcp_tjwater` MCP connection.
|
||||
Public web search uses OpenCode's native `websearch`; do not restore a Server
|
||||
search endpoint, Bocha adapter, or duplicate MCP web-search tool.
|
||||
Native `browser_*` automation tools are disabled. Preserve the separate TJWater
|
||||
presentation tools, frontend action receipts, task presentation events, and
|
||||
the complete `memory_manager` / `skill_manager` plugin interfaces.
|
||||
Do not restore standalone plugin query registrations, legacy typed query tools,
|
||||
or custom internal HTTP query routes. `memory_manager` and `skill_manager` retain
|
||||
their complete read/write plugin interface; publication, actions, messaging writes,
|
||||
map presentation and `todowrite` also remain plugins. OpenCode supplies native
|
||||
session metadata on MCP calls; authenticate the private loopback channel before
|
||||
resolving host ownership or verified direct task readers. Keep product OAuth
|
||||
credentials and context handles in the Agent host. Project queries fail explicitly
|
||||
when the upstream Server MCP is disabled; never fall back to legacy query bridges.
|
||||
|
||||
|
||||
Keep the `.opencode/agent-plugin.json` descriptor and package descriptions aligned
|
||||
with actual IDs and paths when agent/plugin assets change. The descriptor is a
|
||||
documentation index, not a runtime configuration file or native OpenCode plugin
|
||||
@@ -130,11 +214,23 @@ per user or project, and preserve the existing validated persistence workflow.
|
||||
|
||||
Configure external MCP only through administrator-owned `mcp.servers` in
|
||||
`opencode.json` or `OPENCODE_CONFIG_CONTENT`; server names use the `mcp_` prefix.
|
||||
Preserve exact read-only tool allow rules, interactive approval outside that
|
||||
allowlist, read-only background task access, and disabled MCP in learning review.
|
||||
Preserve exact read-only tool allow rules and approval outside that allowlist.
|
||||
Interactive chat follows the selected round mode: `request` asks the user;
|
||||
`always` automatically answers pending native permission requests, including
|
||||
Shell, file edits and MCP, with `once`. Do not persist automatic grants into later
|
||||
rounds or bypass explicit denials, sandboxing, business authorization, read-only
|
||||
background task access, or disabled MCP in learning review.
|
||||
Broad wildcard allows and server `readOnlyHint` values are not read-only grants.
|
||||
Apply the same policy to Code Mode and generic MCP resource access.
|
||||
|
||||
First-party product MCP OAuth discovers protected-resource and OAuth/OIDC
|
||||
metadata, pins the configured resource and issuer, and sends the canonical
|
||||
`resource` on both grants. Keep public discovery credential-free, bounded and
|
||||
redirect-free. Send client secrets only to a validated issuer's advertised token
|
||||
endpoint; preserve Basic/post authentication, metadata invalidation on 401, and
|
||||
explicit failure for an incompatible resource indicator. Do not restore a
|
||||
hardcoded Keycloak token path or an audience-only fallback.
|
||||
|
||||
Local stdio MCP is a trusted host process, not a sandbox Shell process. Preserve
|
||||
its explicit environment filtering and never forward Agent/OpenCode credentials.
|
||||
Return only sanitized server status and actual tool IDs to the browser.
|
||||
@@ -175,7 +271,7 @@ verification; configuration/catalog checks must not invoke model inference.
|
||||
## Repository Hygiene and Delivery
|
||||
|
||||
Never commit secrets, private environment files, generated runtime data, logs,
|
||||
dependencies, `.agent-workspaces/`, session dumps, or result references. Avoid
|
||||
dependencies, session workspaces, session dumps, or generated result files. Avoid
|
||||
printing private configuration contents while inspecting a workspace.
|
||||
|
||||
Preserve unrelated dirty and untracked work. Keep `README.md` useful to people:
|
||||
|
||||
Reference in New Issue
Block a user