Commit Graph

59 Commits

Author SHA1 Message Date
Tianyi Cui
53680ee6bc Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts:
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	packages/context/time-context/tests/time-context.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/session/README.md
#	packages/core/session/src/types.ts
#	packages/core/session/tests/surface.spec.ts
#	packages/examples/acp-demo/tests/acp-agent.spec.ts
#	packages/examples/stdio-demo/tests/stdio-agent.spec.ts
#	packages/hooks/hooks-claude/tests/coverage.spec.ts
#	packages/hooks/hooks-codex/tests/coverage.spec.ts
#	packages/session-query/session-query/tests/session-query.spec.ts
#	packages/support/invariants/tests/invariants.spec.ts
#	packages/ui/acp/tests/harness.ts
2026-07-17 21:56:10 +08:00
Yichen Jiang
d3b959389a test(support): add shared AgentLoop testkit 2026-07-16 17:39:53 +08:00
Yichen Jiang
75331f03a6 Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-15 13:30:40 +08:00
imccyu
31f4441fd4 pkg: update vendor dep 2026-07-15 11:28:45 +08:00
Yichen Jiang
815365dbbe Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
#	examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/skill-load/session.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/session.jsonl
#	examples/sandbox-acp-agent/cordis.yml
#	examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/mode-switching/session.jsonl
#	packages/compact/compact-basic/README.md
#	packages/compact/compact-basic/src/index.ts
#	packages/compact/compact-basic/tests/compact-basic.spec.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent-loop/tests/properties.spec.ts
#	packages/core/session/README.md
#	packages/core/session/src/types.ts
#	packages/core/session/tests/derived-cache.spec.ts
#	packages/llm/llm-deepseek/src/index.ts
#	packages/llm/llm-pi-ai/README.md
#	packages/llm/llm-pi-ai/src/adapter.ts
#	packages/llm/llm-pi-ai/src/convert.ts
#	packages/llm/llm-pi-ai/tests/adapter.spec.ts
#	packages/llm/llm/README.md
#	packages/llm/llm/src/call-config.ts
#	packages/llm/llm/src/index.ts
#	packages/ui/acp-agent/src/index.ts
#	packages/ui/acp/tests/harness.ts
#	packages/ui/jsonrpc/README.md
#	packages/ui/jsonrpc/src/server.ts
#	packages/ui/stdio-agent/README.md
#	packages/ui/stdio-agent/src/index.ts
#	python/sdk/README.i18n.yaml
2026-07-14 22:17:50 +08:00
Yichen Jiang
e547980d77 feat(llm): route adapters by provider 2026-07-14 21:57:52 +08:00
Tianyi Cui
8590ba00a4 Merge remote-tracking branch 'origin/master' into codex/trim-ai-prose
# Conflicts:
#	docs/AGENTS.md
#	docs/config-catalog.md
#	packages/bash/bash-sandbox/src/index.ts
#	packages/bash/bash/src/session-mode.ts
#	packages/bash/tool-bash/README.md
#	packages/code-runtime/code-runtime-worker/README.md
#	packages/compact/compact/src/index.ts
#	packages/core/agent-core/README.md
#	packages/hooks/hooks-claude/src/config.ts
#	packages/hooks/hooks-claude/src/index.ts
#	packages/hooks/hooks-codex/src/config.ts
#	packages/hooks/hooks-codex/src/index.ts
#	packages/llm/llm/README.md
#	packages/session-persistence/session-persistence-jsonl/README.md
#	packages/session-persistence/session-persistence/README.md
#	packages/skill/skill-local/README.md
#	packages/support/acp-snapshot/README.md
#	packages/support/invariants/src/index.ts
#	packages/ui/acp/README.md
#	packages/ui/jsonrpc-agent/README.md
#	packages/ui/jsonrpc/README.md
#	packages/ui/permission/README.md
#	packages/ui/user-approval/README.md
#	packages/ui/user-interaction/README.md
#	packages/web/web-search-deepseek/README.md
2026-07-14 14:37:16 +08:00
Tianyi Cui
eed43abe66 docs: address final model experience review 2026-07-14 00:22:52 +08:00
Tianyi Cui
148046b9c8 docs: rebalance prose cleanup and add trimming skill 2026-07-13 23:27:00 +08:00
Tianyi Cui
d77f797d89 docs: replace model experience tables with sections 2026-07-13 22:26:33 +08:00
Tianyi Cui
646f3d2d0c docs: apply verbatim model experience guidance repo-wide 2026-07-13 21:33:23 +08:00
Tianyi Cui
c45d7927cf docs: tighten prose audit after master retarget 2026-07-13 16:24:32 +08:00
Tianyi Cui
7b539a0f8b docs: align model experience with runtime visibility 2026-07-13 15:00:47 +08:00
Tianyi Cui
8ee569d6bf Merge remote-tracking branch 'origin/codex/package-readme-limitations-audit-20260712' into codex/model-experience-readmes-20260712
# Conflicts:
#	packages/core/tools/README.md
2026-07-13 13:48:43 +08:00
Tianyi Cui
7499fb677a Merge commit '09d5549b92f9aa9752c480a2bfaa0fcc24e05e91' into codex/package-readme-limitations-audit-20260712 2026-07-13 13:22:05 +08:00
Tianyi Cui
e04ec07345 refactor(core): remove owner-final assembly machinery 2026-07-13 13:09:41 +08:00
Tianyi Cui
331734526c Merge branch 'codex/package-readme-limitations-audit-20260712' into codex/model-experience-readmes-20260712 2026-07-13 12:07:00 +08:00
Tianyi Cui
5f944d6254 Merge remote-tracking branch 'origin/worktree-agent-scope-design' into codex/package-readme-limitations-audit-20260712 2026-07-13 12:06:54 +08:00
Tianyi Cui
f32cfafa1a refactor: narrow synchronous extension contracts 2026-07-13 11:58:55 +08:00
Tianyi Cui
23850b4ad9 docs: align model experience with scoped runtime 2026-07-12 23:59:05 +08:00
Tianyi Cui
5158cc3e0b Merge remote-tracking branch 'origin/codex/package-readme-limitations-audit-20260712' into codex/model-experience-readmes-20260712
# Conflicts:
#	packages/AGENTS.md
2026-07-12 23:54:00 +08:00
Tianyi Cui
6967c584d1 Merge remote-tracking branch 'origin/worktree-agent-scope-design' into codex/package-readme-limitations-audit-20260712
# Conflicts:
#	packages/core/scope/README.md
#	packages/session-persistence/session-persistence-jsonl/README.md
#	packages/session-persistence/session-persistence-sqlite/README.md
#	packages/subagent/subagent-acp/README.md
#	packages/subagent/subagent-fork/README.md
#	packages/subagent/subagent-inprocess/README.md
#	packages/subagent/subagent/README.md
#	packages/subagent/tool-subagent/README.md
#	packages/support/invariants/README.md
#	packages/support/subagent-mock/README.md
#	packages/workflow/workflow-workerthread/README.md
#	packages/workflow/workflow/README.md
2026-07-12 23:35:47 +08:00
Tianyi Cui
bb3f6bd736 refactor(subagent): unify async readiness and cancellation 2026-07-12 22:41:59 +08:00
Tianyi Cui
cb03c8c284 fix(scope): align trust and input boundaries
Rewrite the agent-scope RFC with executable examples and an explicit security non-goal. Harden subagent scalar and depth validation, and pin live tool-filter semantics across code, tests, and generated docs.
2026-07-12 11:17:57 +08:00
Tianyi Cui
d427478c44 fix(subagent): validate direct depth boundaries 2026-07-12 10:48:20 +08:00
Tianyi Cui
c5b1a7941f fix(scope): harden lifecycle ownership foundation
Make Cordis construction and teardown ownership reentrancy-safe, then carry caller and provider ownership through reservation, setup, publication, quiescence, and sentinel retirement.

Stabilize registry carriers and factory/workflow boundaries, add adversarial lifecycle regressions, and align the rewritten RFC plus generated contracts with the enforced behavior.
2026-07-12 08:57:05 +08:00
Tianyi Cui
a9cb70d896 fix(scope): harden final ownership boundaries 2026-07-12 05:13:17 +08:00
Tianyi Cui
36b8370027 fix(scope): close remaining ownership boundaries 2026-07-12 03:51:55 +08:00
Tianyi Cui
b5cd511f35 docs: address model experience review 2026-07-12 02:55:26 +08:00
Tianyi Cui
a08485fc80 Merge remote-tracking branch 'origin/codex/package-readme-limitations-audit-20260712' into codex/model-experience-readmes-20260712
# Conflicts:
#	docs/cookbook/adding-a-package.md
#	docs/rfc/INDEX.md
#	package.json
#	packages/AGENTS.md
#	packages/bash/bash-sandbox/README.md
#	packages/sandbox/sandbox-local/README.md
#	packages/sandbox/sandbox/README.md
#	packages/session-persistence/session-persistence-sqlite/README.md
#	packages/support/acp-snapshot/README.md
#	packages/ui/app-boot/README.md
#	packages/ui/user-approval/README.md
#	packages/workflow/tool-workflow/README.md
2026-07-12 02:48:49 +08:00
Tianyi Cui
027970043c docs: document package model experience 2026-07-12 02:12:36 +08:00
Tianyi Cui
41a7c70cb1 docs: audit package limitations on current stack 2026-07-12 02:08:35 +08:00
Tianyi Cui
ecb8aa5b8e Add a gated Known Limitations and Deferred Work section to every package README
Every packages/*/* README now carries a canonical '## Known Limitations and
Deferred Work' section: condensed, evidence-backed bullets for consumer-visible
gaps (unimplemented features, platform caveats, MVP cuts) and consciously
postponed work (TODO/FIXME/XXX markers, RFC deferrals still open). The ten
pre-existing ad-hoc variants ('What is NOT here (TODO)', 'Deferred',
'Limitations (MVP)', 'Known limitations (tracked TODOs)', ...) are normalized
into the canonical heading.

A new doc-sync gate, scripts/verify-readme-limitations.ts, enforces the shape:
exactly one limitations-like heading per package README, byte-equal to the
canonical h2, with at least one bullet; near-miss headings fail so variants
cannot creep back. Packages with genuinely nothing to declare (dsh-brand,
dsh-timeout, dsh-subagent-mock, dsh-app-boot) are whitelisted in the script and
must NOT carry the section; whitelist entries are validated against the scanned
package set so a rename fails loud.

Wired into the doc-sync chain (package.json) and the run-gates doc-sync leaf
set; the standing rule lands in packages/AGENTS.md and the adding-a-package
cookbook; decision record in
docs/rfc/implemented/process/2026-07-10-readme-known-limitations-gate.md
(RFC index regenerated).

Also fixes two stale '(deferred)' markers claiming dsh-compact-basic is
unimplemented (the dsh-compact seam README's package table and the seam's
module doc comment).
2026-07-12 01:46:34 +08:00
Tianyi Cui
3529b3c166 fix(scope): close final ownership races
Drain idle injection flushes before agent teardown, snapshot approval and subagent provider inputs, and gate subagent lifecycle events on real child readiness. Align the RFCs and generated contracts with the hardened behavior.
2026-07-12 00:31:46 +08:00
Tianyi Cui
36c94fbe3e docs: align the agent-scope contracts 2026-07-11 22:55:40 +08:00
Tianyi Cui
3263dab822 fix(core): enforce agent-scoped ownership boundaries 2026-07-11 22:55:26 +08:00
Tianyi Cui
6091c0a3dc docs: rewrite the agent-scope RFC 2026-07-11 14:01:49 +08:00
Tianyi Cui
fd2c682477 docs(subagent): state the re-assert placement guarantee precisely
Reviewer-agent C1 on the audit delta: "byte-identical" overstated the
untampered-path guarantee — a 190-order section registered AFTER the
structured runtime sorts before the instruction in the registry's stable
sort but after it in the re-assert's band insertion. Intra-band section
order carries no contract, so the behavior is right and unchanged; the
module doc and both in-code comments now say exactly that instead of
claiming byte identity.
2026-07-09 16:42:26 +08:00
Tianyi Cui
7c5133488a refactor(core): every registry register-method returns the exact effect disposer
The exact-disposer fix (5fbac8be B1) repaired agents.register but left the
same wrapper (return () => void dispose()) at seven sibling sites:
tools.register, tools.restrict, systemPrompt.section/tools/variable,
agents.setFactory, and subagents.registerProvider. A wrapper makes correct
composite usage unrepresentable — the exact disposer cannot be recovered, so
a generator effect yielding it leaves the inner effect disposing as a
CONCURRENT SIBLING on owner unload, silently reproducing B1's ordering
corruption. The exact disposer serves both usages (composite-nestable AND
fire-and-forget callable); all seven now return it, typed
() => Promise<void> | void, with the convention pinned by a discriminating
test: an async-link composite probe that passes with the exact disposer and
observes the sibling unregistration firing mid-drain with a wrapper.

Re-auditing also surfaced that B1 itself SHIPPED a full-lint failure: it
changed register()'s return type without updating cross-file consumers
(agent.spec.ts dispose() statements, tool-bash's disposer list), which the
staged-scoped pre-commit lint never saw — pnpm run lint was red at HEAD.
Those three sites and this change's own fallout are fixed together: tests
now await disposers (stronger — they observe the full unwind), sync
paths void them, and the two annotation sites carry the honest union type.
agents.register's README line had drifted the same way (B1 updated the
JSDoc, not the README) — all seven README signatures now match; services
catalog regenerated.
2026-07-09 13:05:44 +08:00
Tianyi Cui
6f4ea8a260 refactor(subagent): stage structured captures in a WeakMap keyed by execution
Supersedes the single-slot staging the execution-identity fix (06c5f17e)
kept: the one pending slot needed a mismatch-drop branch plus a defensive
coverage-ignored finally to manage orphans, and it carried a latent trap —
under the loop's documented parallel-execution TODO, two in-flight capture
trips would overwrite the slot and BOTH be dropped.

Staging in a WeakMap<ToolExecution, {value}> makes the stale-stage class
structurally impossible instead of managed: an entry orphaned by an outer
short-circuiting listener can never match a different execution's lookup
(whatever call id that execution carries), needs no drop bookkeeping (the
map reclaims it with the execution object), and staging cannot cross-clobber
under parallel execution. Staging is the only layer this future-proofs — a
parallel cut would still owe its own single-accept rule for the captured
value, which is documented rather than claimed. Behavior is pinned by the
existing orphan/call-id-reuse regression tests, which pass unchanged; the
commit listener loses two branches and the v8-ignore.
2026-07-09 12:30:27 +08:00
Tianyi Cui
96c3c94f85 fix(subagent): make the structured re-assert placement-preserving
Re-auditing the review-fix commits surfaced a regression the REPLACE
re-assert (825cbab3) introduced: unconditionally rebuilding both arrays as
filter(...)+append moved structured_output to the END of the model-visible
tool list on every untampered assembly (overriding the registry's
toolOrder/lexicographic contract) and moved the instruction section to the
absolute array end — renderPrompt reads ARRAY order, so any section above
order 190 would render before the trailing instruction, violating the
sections-sorted-ascending contract. The presence-check version it replaced
touched neither array when the entries were intact.

The re-assert keeps its REPLACE content semantics but is now
placement-preserving: the tool is replaced IN PLACE (duplicates collapse,
append only when stripped); the section is re-inserted at its
ascending-order position (the first entry above 190 — exactly where the
registry's stable sort put it, so the untampered path reaches the model
byte-identical). Pinned by two regression tests that fail against the
filter+append form: untampered placement (tool before a lexicographically
later tool, instruction before an order-200 section) and tamper recovery
(stripped section re-enters its band; an added duplicate collapses to one
right-schema entry).
2026-07-09 12:27:08 +08:00
Tianyi Cui
e5093244fb fix(subagent): declare the dsh-scope dependency; make the re-assert REPLACE conflicting entries
ds-review-bot round-2 findings: (1) dsh-subagent's runtime import of
@deepseek-ai/dsh-scope was undeclared in its manifest and tsconfig
references (the root paths map masked it; the emitted package would import
an undeclared dependency) — wired as peer+dev with the project reference,
module graph regenerated. (2) The structured re-assert only ensured
PRESENCE, so a downstream listener injecting a same-named entry with the
wrong schema kept it model-visible while validateStructuredValue enforced
the real one; it now REPLACES any same-named tool/section with the run's
own. Pinned by a wrong-schema-injection test asserting exactly one entry
carrying the run's schema.
2026-07-09 05:21:06 +08:00
Tianyi Cui
db6aed0459 fix(subagent): key the structured stage by execution identity, not call id
Codex confirmation-round finding: an OUTERMOST prepend pre-execute deny
skips the runtime's own pre-execute clear, and the denied call still
reaches post-execute — so a reused adapter-minted call id could promote an
orphaned stage on the default accept path. The stage is now keyed by the
ToolExecution OBJECT identity, the one token that provably ties a stage to
one pipeline trip: only the execution whose own body staged can commit,
whatever any call id says. The pre-execute clear is gone (one mechanism);
the commit's mismatch drop is now the reachable primary guard. Repro test:
orphaned stage + outer pre-execute deny with the same call id never
promotes; a fresh valid call still captures.
2026-07-09 05:03:44 +08:00
Tianyi Cui
547aacee2f fix: honor the teardown order on owner unload; make the structured commit unconditional
Adversarial-review findings (own reviewer agent), each verified and pinned:

B1: agents.register() returned a wrapper lambda, so the factory composite's
yield could not identity-nest it — on OWNER unload the unregistration (and
agent/disposed) disposed as a concurrent sibling, firing mid-drain while
the final turn was still closing (pre-existing on master; this branch's
docs re-assert the order, so it must be true). register() now returns the
EXACT cordis effect disposer (the Scope.rawDispose move); the composite
nests it and owner unload runs stop/drain -> unregister -> detach -> scope
like every other path. Regression test pins turn-end before disposed
before detach on owner unload.

B2: the structured two-phase commit could promote a stale stage when a
later capture call REUSED the orphaned stage's call id with a body that
never staged (denied downstream, or invalid args throwing pre-stage). The
runtime's pre-execute listener now clears any stale stage unconditionally
when a new capture call enters the pipeline — only a call's own body can
stage for its commit; the call-id mismatch guard becomes a defensive
second layer. Repro test: blocked capture then same-id invalid call.

C1: an explicit empty toolFilter config now fails at plugin LOAD (the
check is self-contained) instead of killing every delegation at child
setup. C2: Scope.dispose/ScopeHost.dispose @returns state the single-shot
repeat-call semantics honestly.
2026-07-09 04:48:52 +08:00
Tianyi Cui
e7b712453a test: close the per-file coverage gaps for the scoping surface
Every subject-extractor row of the invariants carrier table is exercised
with a matching and a foreign-keyed carrier; the HMR re-apply seed path
(sessions of agents that predate the plugin are marked started) is pinned;
the scoped tool-provider disposal, plural restrict() validation, singular
scopeHost absentee, tool-subagent passthrough, stale-stage drop, and
disposing-parent spawn (INACTIVE_EFFECT, no orphan) each gain their test.
Two genuinely defensive branches carry justified v8-ignore markers.
2026-07-09 03:41:37 +08:00
Tianyi Cui
cc24e79cd2 docs: agent-scope RFC, CONTEXT.md glossary, architecture scope section, README sync
The agent-scope-contexts RFC (implemented) records the decision tree:
the dsh-scope primitive over cordis extend/Context.filter/no-op fibers,
two-level flat scope with shadowing, restriction/grant semantics, the
scoped-dispatch rule with fused helpers, the setup window, and the
alternatives (explicit scope params, isolate, event-filtering-only,
vendored support) with why each lost. CONTEXT.md pins the glossary.
architecture.md gains the Agent Scope section, the dsh-scope spine row,
the scoped turn-flow line, and an extension-table row (ceiling 1640→1790:
the two-layer registration model is a new architectural axis; additions
are condensed to pointers). READMEs of every touched package re-state
their scoped facts; the stale structured-runtime README section is
replaced by the scoped-registration description.
2026-07-09 03:01:11 +08:00
Tianyi Cui
15f4d1cd03 feat(subagent): persona + toolFilter become real; structured runtime collapses to scoped registrations
SubagentStartRequest gains persona (capability-gated like toolFilter); the
in-process driver composes the child's scoped world in the factory's setup
window — persona as a scoped shadowing deployment:persona section,
toolFilter as a scoped tools.restrict() (loud unknown-name validation),
outputSchema as the scoped structured runtime. spawn/fork now advertise
every start-time capability; ACP stays all-false. A parent-scope teardown
effect links each child to its parent through the memoized handle, so a
disposed parent reaches its whole subtree even if the delegating tool's
finally never runs; subagent/start|end dispatch in the delegating parent's
scope.

structured.ts loses the placeholder schema, the final-assembly swap/strip,
the refcounted root runtime, and the WeakMap state: each child registers
its OWN capture tool (real schema), instruction section, and enforcement
listeners on child.ctx, riding the child's fiber. The commit listener is
call-keyed (a stale stage from a short-circuited post-execute chain is
dropped, never promoted on a later call), and one scoped prepend re-assert
listener preserves the final-assembly guarantee against a stripping global
listener.

tool-subagent gains persona/toolFilter/maxDepth passthrough config —
deny-listing the delegation tool (or maxDepth) is how a deployment bounds
recursion; the omitted-toolFilter schema key is forced absent (a
materialized {} would mean an empty allow-list, i.e. deny-everything).
2026-07-09 02:10:06 +08:00
Tianyi Cui
a1c01cda52 Merge remote-tracking branch 'origin/master' into structured-output-subagent-seam
# Conflicts:
#	docs/config-catalog.md
2026-07-07 21:40:07 +08:00
Tianyi Cui
0e0f3b2f19 review: acquire the structured runtime per run, not per backend
The Codex simplification concern plus the duplication comment on the spawn
apply, resolved by deletion: the backend-lifetime holds are gone, so the
runtime registers at the first structured run and disposes when the last
settles — a deployment that never passes outputSchema carries no always-on
global state, and there is no per-backend acquisition block left to extract.

The driver spec now drives an INLINE spawn-shaped provider over
startInProcessRun, which removes the spawn/fork devDependencies (the
test-only workspace cycle); plugin-level structured coverage moves to the
backends' own specs (capture through the shipped plugin, mid-run backend
unload, seeded fork capture). tools.md, the driver README, and both backend
READMEs describe the run-scoped lifetime; the module-graph regenerates
without the cycle edges.
2026-07-07 21:09:02 +08:00
Tianyi Cui
280233ba78 fix review finding: the capture commits only on the final post-execute accept
The cross-seam blocker: structured_output recorded its value in the tool
BODY, before tools/post-execute could block the call — a PostToolUse hook's
block turned the logged result into isError while readResult still returned
structured success and the continuation veto ended the turn.

Two-phase commit: the body validates and STAGES (RunState.pending); a fourth
runtime listener on tools/post-execute — prepend, so await next() returns the
composed final decision — promotes the stage to captured only on an accepted
call, and clears it on every path. A block now yields a consistent pair: the
model and log see the isError feedback, the run settles error with no
structured value, and the turn continues so the model can react. Regressions:
block denies the capture end-to-end; accept-with-replacement still commits.
2026-07-07 21:08:12 +08:00