Align all DI service contracts on _serviceBrand first, a blank line, methods and properties, then hooks last when present.
Co-authored-by: Cursor <cursoragent@cursor.com>
Turn no longer carries or emits the triggering message id; prompt and goal
callers keep message identity in context memory instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
- move todo from agent scope (`IAgentTodoListService`) to session scope
(`ISessionTodoService`); the list is now shared across every agent in a
session instead of per-agent.
- persist every change as a `todo.set` record on the main agent's wire, which
is the single source of truth and a replayable timeline; drop the agent
tool-store `'todo'` key and the atomic-doc persistence store.
- bind `TodoListTool` and the stale reminder into every agent via
`IAgentLifecycleService`, and register the `todo.set` resume resumer on the
main agent.
- migrate `fullCompaction` to read `ISessionTodoService`; register the `todo`
domain at L4 with a `todo>agentLifecycle` layer exception; refresh the DI
scope/domain diagram.
- remove the ISessionAgentFileSystem service and its node implementation
- extend IHostFileSystem with readText decode options and stat mtimeMs/ino
- route SessionFsService, profile context, media, and plan through IHostFileSystem
- drop the unused agentFs:* session REST endpoints from server-v2/server-e2e
- route read/write/grep/glob through host fs and process services
- add TextModel/EditService with an os-backed FileEditService
- update file tool tests, exports, layer rules, and DI docs
- add app/cron barrel re-exporting the cron task record, persistence contract/service, and dependency-free algorithm lib (cron-expr, jitter, clock, format)
- move cronTask persistence files from app/cronPersistence into app/cron and drop the old cronPersistence barrel
- register the cron config section (KIMI_CRON_* env bindings) via configSection
- repoint cron tests from #/agent/cron and #/app/cronPersistence to #/app/cron
- move Read/Write/Edit/Grep/Glob tools and line-endings helper from agent/fileTools to os/backends/node-local/tools
- re-export tools from the node-local backend barrel
- drop the fileTools domain barrel and its domain-layer entry
- update test imports to the new paths
- add runSubagent/resumeSubagent to IAgentLifecycleService
- move spawn/profile/prompt-prefix/record/telemetry/observe composition out of the Agent tool
- turn the Agent tool into a thin adapter over the lifecycle service
- stub the two methods in gateway and sessionActivity tests
- spawn git/gh via IHostProcessService instead of node:child_process
- probe path existence via IHostFileSystem instead of node:fs/promises
- normalize git porcelain paths without node:path
- resolve IGitService through the container in gitService.test.ts
- Move the `web` domain from src/agent/web to src/app/web; it now owns only
the auth-independent FetchURL (tool, UrlFetcher contract, and the local and
Moonshot fetch providers).
- Move WebSearch (tool, WebSearchProvider contract, MoonshotWebSearchProvider)
into the KimiOAuth auth domain under src/app/auth/webSearch, since it needs
an authenticated backend.
- Replace the Agent-scope IAgentWebService registrar with registerTool
contributions fed by new App-scope seams (IWebFetchService,
IWebSearchProviderService), because the tool registry is Agent-scoped.
- Add documented auth>tool / auth>toolRegistry layer exceptions and update the
DI scope-domain graph.
* feat(agent-core): strengthen the language-matching rule in the default system prompt
* chore: refine changeset wording
* fix(kaos): enrich PATH from the user's login shell at startup
When kimi-code is launched from a context that skipped the user's shell
profile (GUI launchers, non-login parent shells), process.env.PATH misses
entries like /opt/homebrew/bin, so commands spawned by the Bash tool
cannot find user-installed tools such as gh.
LocalKaos.create() now probes the user's login shell once
($SHELL -l -c env, 5s timeout, memoised) and appends the missing PATH
entries to process.env.PATH. Existing entries keep their order and
priority; probe failures silently leave PATH untouched. Windows is
skipped: the problem is specific to POSIX login-shell profiles.
* fix(kaos): fall back to the account login shell when $SHELL is unset
launchd/daemon launches can leave $SHELL unset or blank — the very
contexts whose PATH is impoverished — so the login-shell PATH probe
would give up exactly where it matters most. Resolve the shell from the
OS user database (os.userInfo().shell) before giving up; lookups that
throw (uid without a database entry) or yield nologin shells degrade
silently as before.
* fix(kaos): preserve empty PATH components when merging login-shell PATH
POSIX command lookup treats an empty PATH component (leading colon,
trailing colon, or double colon) as the current directory. The merge
previously filtered those out of the current PATH and rewrote the value
even when nothing was appended, silently dropping cwd lookup for users
who rely on it.
Keep the current PATH string verbatim as the prefix, append only the
missing login-shell entries, and skip the env write entirely when the
login shell contributes nothing — an unset PATH stays unset, a set PATH
is never rewritten. Empty login-shell components are still never
imported.
* fix(kaos): only import absolute login-shell PATH entries
A `.` or relative component in the login-shell PATH is cwd-dependent
lookup with another spelling, and LocalKaos runs commands from arbitrary
workspace directories — importing one would let a command name resolve
from an untrusted project cwd. Tighten the merge's skip condition from
"empty" to "not absolute", which subsumes the empty-component check.
* fix(kaos): invoke the login-shell probe's env by absolute path
A bare `env` inside `$SHELL -l -c` resolves through the inherited PATH
from the workspace cwd. If that PATH carries a cwd-dependent component
(which the merge deliberately preserves), a repo-planted `env` binary
would run automatically at session startup and could feed the probe an
arbitrary PATH. /usr/bin/env is guaranteed on mainstream POSIX systems
and also bypasses profile function shadowing.
* feat(agent-core): guide the model away from repeating denied or failed tool calls
- system.md: add a diagnose-before-retrying paragraph next to the existing
permission-denial guidance, covering failed tool calls
- permission: when the user rejects an approval on the main agent, tell the
model not to re-attempt the exact same call (sub agents already had an
equivalent hint)
* fix(agent-core): close abandoned tool exchanges and dedupe duplicate tool_use ids
A turn that dies between a recorded tool.call and its paired tool.result
(e.g. a transcript write failure mid-batch) used to leave
pendingToolResultIds open forever: every later message was stranded in
deferredMessages and user input was silently swallowed.
- runOneTurn now defensively closes any dangling tool calls when a turn
ends (completed, cancelled, or failed), synthesizing an error result
that names the cause, with a warn log and a tool_exchange_abandoned
telemetry event
- the projector drops assistant tool calls whose id already appeared
earlier (first occurrence wins): a duplicate id is wire-invalid on
strict providers and not repairable by the strict resend; reported via
the existing projection-repair log and telemetry
- resume-side closePendingToolResults now logs what it closes (warn for
a mid-history gap, info for the routine trailing interruption)
* chore: add changesets for tool exchange fixes
* fix(agent-core): scope duplicate tool_use id dedup to the strict resend
Unconditional dedup regressed providers that emit per-response counter
ids (e.g. call_0 in every step) and accept their own duplicates: later
tool exchanges silently vanished from the projected history, and a
duplicate call's own recorded result was left dangling.
- the dedupe pass is now opt-in via dedupeDuplicateToolCalls and enabled
only in strictMessages, so the normal projection keeps the history the
provider produced
- the pass also drops every tool result after the first for an id, so no
dangling tool message survives; when the kept call has no result of
its own, the surviving one is reattached by the adjacency repair
- kosong now classifies the Anthropic "tool_use ids must be unique" 400
as a recoverable request-structure error so it triggers the strict
resend