feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point - #2366
feat(agent-core-v2): introduce the Workspace domain and the agent-profile registry extension point#2366sailist wants to merge 19 commits into
Conversation
|
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cf3e93591f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| this.instructions.onDidChange(() => { | ||
| void this.refreshSystemPrompt(); |
There was a problem hiding this comment.
Refresh AGENTS prompts against the session cwd
When a default-bound agent receives this new instructions change event, refreshSystemPrompt() recomputes with this.cwd; normal bind paths do not pass a cwd, no caller configures ProfileServiceOptions.cwd, and the getter then falls back to '' instead of sessionContext.cwd. Editing AGENTS.md in a workspace can therefore refresh the system prompt by reading/listing the server process cwd rather than the session workspace, so the watched workspace instructions are dropped or replaced with unrelated ones; this event path should refresh with the session cwd/default context instead.
AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L7-L7
Useful? React with 👍 / 👎.
…ble cwd paths - Insert LifecycleScope.Workspace between App and Session - Delete session/workspaceCommand domain (addAdditionalDir) and node-sdk RPC - Remove profile cwd mutation; cwd is fixed at creation - Make ISessionWorkspaceContext read-only; seed additionalDirs at creation - Remove TUI and vscode /add-dir commands (to return workspace-scoped)
…ifecycle - Add IWorkspaceLifecycleService (App scope): handler registry, create-or-get handlerFor with inflight join - Add workspace/workspaceContext seed and workspace/workspaceHandler (session create/resume/fork as handler child scopes) - Delete App-level ISessionLifecycleService; callers compose index -> handlerFor -> handler via sessionLookup helpers - Slim IBootstrapService; persistence addressing via handler chain (disk layout byte-identical) - kap-server routes rewire internally; /api/v1 wire unchanged, debug surface gains workspace addressing - Pin red line in domain lint: session/agent must not import workspace domains
- Add Workspace-scope catalogs for skills and agent profiles, instructions service, and a shared MCP connection manager (built at materialization, refreshed by watch/plugin events) - Session catalogs keep their APIs but read seeded snapshots and refresh via change events; ISessionMcpService removed - Session create options carry no mcpServers; MCP sources are config file (wins on name conflicts) and plugins only - Agent profile/mcp consume the seeded providers
- Add workspace/workspaceDirs: shared additional-dir set with
addDir({path, persist}); persist=true writes .kimi-code/local.toml,
local.toml watch drives cross-process refresh
- ISessionWorkspaceContext becomes a live read view fed by the
ISessionWorkspaceInfo seed contract and change events
- Restore Session.addAdditionalDir in kimi-code-sdk 1:1, mapping to
the workspace service; restore TUI/vscode /add-dir verbatim
- Move fs service, fs watch (shared subscription fan-out), process runner, and a git facade to Workspace scope; sessionFs domain removed - Add IWorkspaceToolPolicy with workspace veto wired through tool activation, execution guard, composed evaluation, and profile prompt projection; injected via ISessionToolPolicyGate seed - kap-server fs routes and fs.watch bridge remap to the workspace services; wire unchanged
- Drop dead code: v2 mergeCallerMcpServers, the transitional ISessionContext.additionalDirs field, an unreachable guard - Fix stale domain references in comments; correct test names - Give the fs-watch refresh test a realistic wait budget under load - Document the four-scope model and workspace domain in AGENTS.md, agent-core-v2 docs, and the agent-core-dev skill
…ity list test v1 connects in the background after create resolves while v2 awaits it inside create, so an immediate list can catch either side still pending under CI load
… domain - add the pure findGitWorkTree probe in app/git/workTree and expose it as IGitService.findWorkTree - switch the git permission policies off the local findLocalGitWorkTreeMarker helper to the DI service - reuse findGitWorkTree for AGENTS.md project-root discovery in agent/profile/context.ts - add findWorkTree coverage to gitService.test.ts
- add WorkspaceServicesView rail view with a workspace picker on top; proxies resolve workspace-scope Services on the /workspace/:id route - extend ChannelScope, ServiceTarget, and ServicePanelDef scope with 'workspace', routed via client.workspace(id).service - wire the new view into NavRail and App
- move the scope-agnostic MCP connection layer (stdio/http/sse clients, connection manager, oauth, config schema, tool naming) from agent/mcp to the new mcpCore domain - move the [mcp] config section to app/mcpConfig and OAuth credential persistence to app/mcpConfig/oauthStore - introduce the workspace/workspaceMcpConfig domain owning the effective MCP server set (mcp.json files + plugin contributions, refreshed by fs watch); workspaceMcp keeps pure connection orchestration - update the plugin domain, session MCP handle, klient/node-sdk contracts, and tests accordingly
- delete the faultInjection domain (flag definition, IFaultInjectionService contract, FaultInjectionService implementation) - drop the requester-side take() injection point and the constructor dependency from llmRequester - remove the flag-gated test cases and the IFlagService stub they needed - regenerate the state manifest without the faultInjection state keys
…rust
Add the Workspace-scope IWorkspaceTrust service: an explicit, per-workspace
trust marker persisted under the home (IAtomicDocumentStore, keyed by
encodeWorkDirKey(root)) so a checked-out tree cannot pre-trust itself.
While a workspace is untrusted, workspaceMcpConfig skips the project-level
.mcp.json and .kimi-code/mcp.json files (user-level config and plugin
contributions still load); a trust flip reuses the reload path, so project
servers connect on trust and disconnect on untrust.
Expose the state over kap-server REST: GET /workspaces/{id}/trust,
POST /workspaces/{id}/trust, POST /workspaces/{id}/untrust.
…wser The Workspace Services view now keeps a server-side directory browser in a left sidebar (over IHostFolderBrowser) instead of a <select> of registered workspaces. Entries that are registered workspaces carry a workspace badge plus their IWorkspaceTrust trust state; selecting an unregistered folder registers it on demand via IWorkspaceService.createOrTouch.
A default-bound agent recorded no cwd in its profile.bind payload, and no caller configures ProfileServiceOptions.cwd, so the profile service's cwd getter fell through to '' and refreshSystemPrompt() rebuilt the prompt from the server process's cwd: an AGENTS.md edit dropped the workspace instructions (or swapped in unrelated ones). bind() now persists the resolved effective cwd (the input's, or the session's when the input omits it) into profile.bind — the Model's cwd stays creation-fixed and is always set. The getter's last resort is the session's own cwd (the value legacy bindings resolved against) instead of a bare ''.
…extension point for agent profiles - App-scope IAgentProfileRegistry: any scope can register an AgentProfileContribution keyed by (sourceId, workspaceKey); dedup per source id, change events drive catalog re-projection - workspaceAgentProfileLoader domain owns agent-file discovery end to end (parse / roots / SYSTEM.md / explicit runtime files) with five Workspace-scope loaders (workspace / user / plugin / extra / explicit) tagged with the handler's workspaceId; internals live under internal/ - SessionAgentProfileCatalog projects the registry directly (name dedup, priority adjudication, builtin override rule, inspect()); the workspace-catalog + sessionData seed relay is gone - builtin code contributions register as the 'builtin' entry via BuiltinAgentProfileLoader; plugin agent roots are provided by the plugin domain as PluginAgentRoot - remove cwd from the profile binding chain (BindAgentInput / ProfileBindingSnapshot / AgentConfigData / ProfileModelState / profile.bind op) — it is always the session's frozen cwd; legacy wire.jsonl records replay fine (the schema strips the field) - share markdown frontmatter parsing via _base/text/frontmatter
- restore the branch's klient workspaceId scope extension lost to a file-level conflict resolution (main had no further changes there) - stub the plugin system-prompt dependencies main added to the profile service in the profileOps / skillCatalog tests - correct PLUGIN_SKILL_SOURCE_ID to the App skillSource domain (Agent scope must not import the Workspace domain) - kap-server workspaceLayout test supplies the now-required hostIdentity - regenerate wire/state/config manifests
4802165 to
729c017
Compare
…nt CLI consumes The internal/ split kept parseAgentFileText / resolveAgentPath off the package entry, but apps/kimi-code's v2 print runner imports them from @moonshot-ai/agent-core-v2 for --agent-file. Export the two symbols by name; everything else under internal/ stays domain-private.
An empty fs:search query used to fail request validation (query had a minimum length of 1), so @-mention pickers had no starting set right after typing "@". The workspace fs service now answers an empty query with the workspace root's top-level entries — directories first, hidden entries excluded, gitignore and exclude_globs honored — mapped into the search-hit shape (score 1, empty match positions) and capped by limit. The mirrored protocol wire schema is relaxed in sync.
- agent-core-v2: e2e asserting a cron-fired steer turn carries earlier tool results (the CronCreate job id) into the provider request - klient: conformance case creating a titled session through implicit workspace materialization
Related Issue
No linked issue — the problem is explained below.
Problem
The v2 engine's scope tree had only App / Session / Agent tiers, so every
workspace-level concern (shared skill / agent-profile catalogs, AGENTS.md,
MCP connections, fs / process / git access, tool policy, trust) was either
re-created per session or threaded through App-level facades. On top of
that, agent profiles were merged inside a session-scoped catalog with the
source logic hard-coded into it, and the profile binding persisted a
cwdthat was always identical to the session's frozen workDir — redundant
state on the wire.
What changed
1. The Workspace domain (fourth lifecycle tier)
Problem: workspace-level resources had no owner; sessions reloaded
everything and an App-level session facade blurred scope boundaries.
What was done:
Workspacelifecycle scope between App and Session: onehandler per workspaceId (create-or-get + join, never closed), owning
session create/resume/fork/close as child scopes.
skill / agent-profile discovery, AGENTS.md instructions, one shared MCP
connection set, fs / fs-watch / process runner / git, the additional-dir
set, the os-level tool veto, and the per-workspace trust marker.
work-tree discovery into the git domain; sessions consume everything
through session-domain seed contracts with change events.
mcpCoreandworkspaceMcpConfig; project-level MCP config isgated behind workspace trust while a workspace is untrusted.
2. Agent profiles: Contribution / Registry / Catalog extension point
Problem: profile contributions were merged by a session-scoped catalog
with the source logic hard-coded into it — no registration API, no dynamic
contributors — and the binding persisted a redundant
cwd.What was done:
IAgentProfileRegistry: any scope can register anAgentProfileContributionkeyed by (sourceId, workspaceKey); theregistry dedups per source id and emits change events.
workspaceAgentProfileLoaderdomain owns agent-file discovery endto end (parse / roots / SYSTEM.md / explicit runtime files, internals
under
internal/); five Workspace-scope loaders (workspace / user /plugin / extra / explicit) register contributions tagged with the
handler's workspaceId, while code-defined profiles register through the
App-scope builtin loader.
SessionAgentProfileCatalogprojects the registry directly — namededup, priority adjudication, the builtin-override rule, and a new
inspect()for debugging — replacing the workspace-catalog +sessionData seed relay.
cwdfrom the profile binding chain and theprofile.bindwireop; it is always the session's frozen cwd. Legacy
wire.jsonlrecordsreplay unchanged (the schema strips the field).
_base/text/frontmatter.3. kimi-inspect workspace tooling
Problem: the inspector had no way to browse or register workspaces.
What was done:
and replace the workspace picker with a server-side directory browser
showing trust state and on-demand registration.
Checklist
gen-changesetsskill, or this PR needs no changeset. (engine-internal refactor; no user-facing behavior change)gen-docsskill, or this PR needs no doc update. (no user-facing behavior change)