Commit Graph

1313 Commits

Author SHA1 Message Date
Tianyi Cui
8db99d36e8 Merge branch 'structured-output-subagent-seam' into worktree-dynamic-workflows
# Conflicts:
#	examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-policy-reject/stdout.golden.jsonl
2026-07-07 22:21:44 +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
imccyu
b149a040d0 docs: fix catalog and budgets 2026-07-07 21:39:48 +08:00
imccyu
eeeadd7bef Merge remote-tracking branch 'origin/master' into worktree-llm-tool-order 2026-07-07 21:35:28 +08:00
Yichen Jiang
731ae2443c Merge remote-tracking branch 'origin/master' into agent-request-messages
# Conflicts:
#	docs/cordis-catalog/events.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
2026-07-07 21:03:07 +08:00
imccyu
709bb5912d fix: cordis-catalog 2026-07-07 20:49:50 +08:00
imccyu
adbba0deb2 fix(system-prompt): reject a toolOrder that names an unregistered tool
Review follow-up (#196): a listed name with no registered tool was silently
ignored; misconfiguration must block work instead. The check lives in the
assembly — the earliest moment the registered tool set exists (tool plugins
register after the service constructs) and the only universal one (cordis has
no "all plugins loaded" event; registrations change at any time). assemble()
is now async so the throw surfaces as a rejection rather than a synchronous
escape from a Promise-returning method.

Blast radius, pinned by a loop-level test: the rejection reaches the turn's
outer catch — the turn closes balanced with an `error` reason, agent/error
mirrors it, no step opens, no request/header is logged, no request reaches
the adapter, and the agent returns to idle; every turn fails identically
until the config is fixed. A boot-time validation pass was considered and
rejected (recorded in the RFC). The general principle — misconfiguration
fails loud, never a silent skip — is added to AGENTS.md.
2026-07-07 20:49:42 +08:00
Tianyi Cui
5e4ac5e472 fix review findings: CI leaf-gate wiring, heritage return surface, AGENTS.md self-containedness
- run-gates.ts docSyncLeafGates() gains verify-export-jsdoc — CI lanes
  and the pre-push hook execute this leaf list, not the doc-sync npm
  script, so the gate was previously unenforced there (proven by
  SessionForkErrorCode landing undocumented via a master merge while
  checks stayed green; now documented). Same wiring gap fixed for
  master's verify-config-catalog, which was also missing from the list.
- The heritage exemption now recovers the base's return surface: a void
  base return carried no @returns duty, so an override returning a
  concrete result documents it itself (annotated overrides run the
  standard check; unannotated ones are classified by the checker so
  faithful void overrides need no boilerplate annotation). Three new
  negative-path tests pin it; RFC and module doc updated.
- AGENTS.md states each principle inline instead of citing RFCs (eight
  citations removed; high-level doc links kept) and the editing section
  now carries the self-containedness rule.
- Generated catalogs/graphs regenerated for the shifted line pointers.
2026-07-07 20:30:34 +08:00
Yichen Jiang
17bd71e530 feat(agent): add the agent/request-messages request-only message seam
A new waterfall near request construction lets plugins contribute
request-ONLY messages framing the derived history: RequestMessages
{ before, after } with a frozen empty seed, fired inside the open step
after the agent/request config waterfall, so the step/start boundary
snapshot and its same-sync-frame invariant are untouched. The request
becomes messagePrefix + boundary snapshot + messageSuffix.

Contributions never enter session history — deriveMessages() is
unchanged — so the request header is their durable record:
EpochHeader gains messagePrefix/messageSuffix (canonical absence for
empty arrays), request/header-delta replaces either array whole with
an empty array encoding the transition back to absence, and the
dev-mode reconstruction cross-check now expects the folded header's
framing around the boundary derivation.

This is the seam for per-request advisory context that must be
model-visible now without becoming durable history (a skills catalog,
an environment reminder), keeping the base system prompt
workspace-independent and provider prefix caches stable. The docs
carry the channel cost model: session-frozen content belongs in
before, low-frequency change notices belong in durable history via
inject() (paid once, prefix-cached thereafter), and after is reserved
for small frequently-refreshed state snapshots re-paid on every
request they ride. No shipped producer yet, so ACP snapshot fixtures
are byte-identical.
2026-07-07 19:42:30 +08:00
Yichen Jiang
7065b32e0b Merge branch 'master' into codex/ask-user-question 2026-07-07 19:42:25 +08:00
Tianyi Cui
9296411ea1 Merge remote-tracking branch 'origin/master' into worktree-export-jsdoc-gate
# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
2026-07-07 17:17:03 +08:00
Tianyi Cui
e930dd328a Merge branch 'master' into worktree-llm-tool-order 2026-07-07 17:01:32 +08:00
Yichen Jiang
b8327bc0e8 Merge remote-tracking branch 'origin/master' into codex/ask-user-question
# Conflicts:
#	examples/acp-agent/tests/snapshots/cancel/session.jsonl
#	examples/acp-agent/tests/snapshots/error-finish/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-edit/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-read-window/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-read/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-terminal-card/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-write-overwrite/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-write/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-promptsubmit-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-stop-continue/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-promptsubmit-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-stop-continue/session.jsonl
#	examples/acp-agent/tests/snapshots/multi-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-fork/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-fork/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.2.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.2.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-spawn/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-spawn/session.jsonl
#	examples/acp-agent/tests/snapshots/todo-plan/session.jsonl
#	examples/acp-agent/tests/snapshots/tool-call-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/workspace-edit/session.jsonl
2026-07-07 15:22:07 +08:00
Yichen Jiang
cebf781d69 fix review findings: polish ask-user question 2026-07-07 14:57:06 +08:00
imccyu
42e7a2f691 fix: add tools reorder to system prompt 2026-07-07 11:03:11 +08:00
Tianyi Cui
10533da8bf Merge branch 'structured-output-subagent-seam' into worktree-dynamic-workflows
# Conflicts:
#	examples/acp-agent/tests/snapshots/cancel/session.jsonl
#	examples/acp-agent/tests/snapshots/error-finish/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-edit/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-read-window/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-read/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-terminal-card/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-write-overwrite/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-write/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-promptsubmit-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-stop-continue/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-pretool-block/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-promptsubmit-context/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-stop-continue/session.jsonl
#	examples/acp-agent/tests/snapshots/multi-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-fork/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-fork/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.2.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.2.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/session.jsonl
#	examples/acp-agent/tests/snapshots/subagent-spawn/session.1.jsonl
#	examples/acp-agent/tests/snapshots/subagent-spawn/session.jsonl
#	examples/acp-agent/tests/snapshots/todo-plan/session.jsonl
#	examples/acp-agent/tests/snapshots/tool-call-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/workspace-edit/session.jsonl
2026-07-07 10:00:58 +08:00
Tianyi Cui
08ff3e404f Merge remote-tracking branch 'origin/master' into structured-output-subagent-seam
# Conflicts:
#	packages/hooks/hooks-claude/tests/bridge.spec.ts
2026-07-07 09:41:14 +08:00
Tianyi Cui
6d6b554fdf Merge remote-tracking branch 'origin/master' into worktree-export-jsdoc-gate
# Conflicts:
#	docs/cordis-catalog/services.md
#	docs/persistence-catalog.md
#	docs/rfc/INDEX.md
#	package.json
#	scripts/gen-cordis-catalog.ts
2026-07-07 09:34:12 +08:00
Hypatia May
4f55c15cf8 Merge remote-tracking branch 'origin/master' into session-fork 2026-07-07 09:06:00 +08:00
Hypatia May
c7fba41ba9 Inline session fork parameters 2026-07-07 09:04:49 +08:00
Tianyi Cui
74502fa8c2 Structured output on the subagent seam: schema subset, capture runtime, spawn/fork support
Carved out of #170 per review feedback — the foundation the workflow tool
builds on, now standing alone on master:

- dsh-tools: the structured-output JSON Schema subset (StructuredOutputSchema,
  assertSupportedOutputSchema, validateStructuredValue) — rejects loud outside
  the enforced subset, listing every violation
- dsh-subagent: SubagentStartRequest.outputSchema / SubagentResult.structured
  become a real capability; the service rejects a schema'd request whose
  provider lacks it
- dsh-subagent-inprocess: the shared structured runtime — one global
  structured_output capture tool, a prepend final-assembly listener that
  strips the placeholder for plain agents and swaps in the run's own schema
  (plus the calling instruction as a trailing section) for structured
  children, an agent/turn-continuation veto once captured, and the
  capture/nudge loop in the run driver (structuredNudgeRetries, cancellation
  honored mid-nudge); lifetime refcounted by backends and live runs
- subagent-spawn / subagent-fork flip outputSchema: true

One deliberate divergence from the #170 revision: the backends do NOT add
'tools' to their plugin inject. Doing so deferred their apply past the todo
plugin, and the delegation tool mirrors provider lifecycle — so the
model-visible tool order of every existing prompt changed, invalidating every
recorded snapshot fixture. The runtime now gates its capture-tool registration
on tools availability itself (sync when live, a scoped inject fiber when the
Loader starts the backend first), keeping this PR byte-invisible to existing
transcripts: all 35 snapshot scenarios pass against master's fixtures
unchanged.
2026-07-06 23:29:08 +08:00
Tianyi Cui
ea58bdf1e8 Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows
Master's reconstructable-requests overhaul (#179) meets the workflow tool:
- subagent-inprocess structured-output nudge becomes a system-prompt section
  plus logged context (the injected-request waterfall shape is gone upstream)
- snapshot fixtures re-recorded on the merged tree so every request/header
  carries the workflow tool; authored error-finish/cancel headers patched to
  the merged tool list and system text
- architecture.md condensed back under its word ceiling; module graph regenerated
2026-07-06 22:28:57 +08:00
Tianyi Cui
cd9737d569 Gate JSDoc completeness on every package export
New doc-sync gate verify-export-jsdoc walks every module-level exported
name under packages/*/*/src and requires description prose everywhere,
plus @param per parameter and @returns on non-void annotated returns for
function-like exports, public class methods, properties, and accessors.
The parsing + check helpers move out of gen-cordis-catalog.ts into a
shared scripts/jsdoc.ts so 'documented' means one thing on both gated
surfaces.

Deliberate exemptions (documented in the RFC): heritage-declared class
members (the seam declaration is the doc's one home — the one checker
query in an otherwise pure-AST walk), cordis plugin-protocol slots
(name/inject/reusable/Config/apply, top-level and static), constructors,
overload implementations, declare-module augmentation bodies, and
re-export statements (checked at the defining module).

The 203 under-documented exports the gate found at adoption are filled
in this change, so the gate lands green; generated catalogs/graphs are
regenerated for the shifted line pointers.

RFC: docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md
2026-07-06 22:09:30 +08:00
Tianyi Cui
b0c7eadd23 feat: generated plugin config catalog (docs/config-catalog.md)
scripts/gen-config-catalog.ts walks every packages/<group>/<pkg> entry with
the TypeScript compiler API and emits docs/config-catalog.md: per loadable
plugin, the verbatim config declaration (JSDoc included) its apply/constructor
receives in a ts config-catalog fence, the inject requirements, resolved links
for every referenced type (package-local types pasted transitively, other
plugins' config types as intra-page anchors, LINK_MAP names to
core-data-structures, workspace types to source), and terse classification
lists for config-free plugins, abstract seams, and libraries — classification
is total, so a new package cannot go undocumented.

The walk enforces per-field JSDoc prose on every pasted declaration and
statically cross-checks the schemastery schema (z.object keys, z.intersect
composition across packages): every schema-validated key must be a declared
member of the config type. One violation existed repo-wide — the agents[].id
field in dsh-agent-loop — fixed by adding its JSDoc (which shifts the
cordis-catalog services page's source pointers; regenerated).

verify-config-catalog (--check) joins doc-sync; doc-typecheck learns the
ts config-catalog fence; gen-cordis-catalog exports its JSDoc/pointer helpers
and LINK_MAP for reuse. Negative-path spec in
packages/core/agent-core/tests/gen-config-catalog.spec.ts mirrors the
gen-cordis-catalog spec. Decision record:
docs/rfc/implemented/process/2026-07-06-generated-config-catalog.md (includes
the deliberate acceptance of README ## Config overlap).
2026-07-06 21:57:17 +08:00
Tianyi Cui
db4a39b024 workflow: close the review-found cancellation and child-lifecycle gaps
Three review findings on the engine's child seam, one mechanism each:

- Cancellation now bridges to run.cancel() on every in-flight child, not
  just the shared request signal — the subagent seam leaves a provider
  free to honor either channel, so the consumer drives both (listener
  removed in the child finally).
- A child result REJECTION (an infrastructure fault the seam allows) now
  emits the paired workflow/agent-end before propagating, and propagates
  as a fatal WorkflowError with the new AGENT_RESULT code — previously it
  skipped agent-end (permanently open child for seq-matching observers)
  and dissolved to a per-item null inside parallel()/pipeline(), letting
  a broken provider read as an ordinary failed child. A rejection landing
  after cancel stays a cancellation (cancelled outcome + CANCELLED).
- Every hook now guards its entry with a shared throwIfCancelled():
  phase()/log() no longer emit observer events after a script caught an
  earlier cancelled rejection, and parallel()/pipeline() refuse entry —
  cancellation is the next HOOK boundary, not just the next agent().
2026-07-06 21:02:41 +08:00
Yichen Jiang
0ba14f4a3c Merge remote-tracking branch 'origin/master' into codex/skill-system
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-06 17:11:35 +08:00
Yichen Jiang
a3b0da0255 Merge origin/master into project instruction files 2026-07-06 15:44:42 +08:00
Hypatia May
aed594813b Merge remote-tracking branch 'origin/master' into session-fork
# Conflicts:
#	docs/architecture.md
#	docs/cordis-catalog/services.md
2026-07-06 14:30:36 +08:00
Yichen Jiang
929e6f21e9 Merge branch 'master' into codex/ask-user-question 2026-07-06 14:22:53 +08:00
Hypatia May
37aac7f313 fix: collapse session fork to one api 2026-07-06 13:57:59 +08:00
Yichen Jiang
901315d8ab Preserve instruction symlink guard through fs seam 2026-07-06 13:55:20 +08:00
Hypatia May
0bf8749128 fix: fold session fork into session store 2026-07-06 12:35:34 +08:00
Hypatia May
cf036299f3 Merge remote-tracking branch 'origin/master' into session-fork
# Conflicts:
#	docs/architecture.md
#	docs/cordis-catalog/events-and-services.md
#	docs/core-data-structures/core.md
#	docs/module-graph.md
#	docs/rfc/README.md
#	packages/README.md
#	tsconfig.base.json
2026-07-06 12:20:00 +08:00
Yichen Jiang
545b2775db Merge remote-tracking branch 'origin/master' into codex/skill-system
# Conflicts:
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	docs/rfc/README.md
#	packages/core/agent-core/package.json
#	packages/core/agent-core/src/index.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/index.ts
#	packages/ui/acp-agent/src/index.ts
#	packages/ui/acp-agent/tests/acp-agent.spec.ts
#	packages/ui/stdio-agent/README.md
#	packages/ui/stdio-agent/src/index.ts
#	packages/ui/stdio-agent/tests/stdio-agent.spec.ts
2026-07-06 10:09:26 +08:00
Yichen Jiang
7d7c4a3c16 Merge remote-tracking branch 'origin/master' into codex/ask-user-question
# Conflicts:
#	docs/rfc/README.md
#	packages/ui/acp-agent/src/index.ts
2026-07-06 10:08:58 +08:00
Tianyi Cui
8bd80e5e9b fix review findings: one frozen seed through the waterfall; stale agent/request docs
Codex diff review, round 1, two (A) findings:

- The agent/request fallback resolved the RAW seed object — on later
  steps the session's cached header fold — so a delegating listener
  (await next(), mutate, return) could rewrite the fold in place and
  the change would compare as already-baseline: no delta logged, the
  persisted log unable to reconstruct the request (the dev invariant
  would fire on the divergence, but the log would still lie). One
  structuredClone'd, deep-frozen seed now serves both the listener
  chain and the fallback — in-place shaping after delegation throws —
  and Session.requestHeader() freezes its fold on update, so the leak
  class is unrepresentable from either side. Pinned by a loop-level
  delegating-mutator test.
- Doc sweep for the old contract: agent README's event row (mutate
  GenerateOptions / tool filtering → frozen config seed, replacement
  out, logged header), compact-basic's module JSDoc (summarize routed
  through agent/request → direct one-shot at llm/stream), and
  architecture.md's event-domain line (request mutation → call-config
  shaping).
2026-07-06 04:17:29 +08:00
Tianyi Cui
c0808d5126 docs: the governing principle — every LLM request is reconstructable from the session log
The reconstructability RFC is the principle's home: model-visible ⟺
logged in both forms, the mechanism (boundary derivation + header
fold), the enforcement (write-time round-trip guard, the dev
invariant), the corollaries ranked (prefix-cache stability first), the
MiniCode lineage with the provenance arrow inverted, and the
alternatives it beat — including the stateful transmission client
whose three-design archaeology lives in PR #162.

Placements per the one-home-per-fact taxonomy: a standing-order line in
root AGENTS.md (with displacement trims to stay inside the 1,575-word
ceiling), the principle statement in architecture.md § Session Log and
its Turn Flow lines (condensed to the ratcheted 1,630 ceiling), the
request-envelope section in core-data-structures/core.md with the
LlmCallConfig paste, both review-requested FIXMEs
(FIXME(call-config-shape) beside the type, FIXME(catalog-verbs) at the
catalog's drift-gate note), cookbook rows redirected off agent/request
(tool filtering → system-prompt/assemble, plan-mode prompt → sections/
inject()), and the llm/stream JSDoc stating the frozen-request
contract. RFC index and all generated catalogs regenerated.
2026-07-06 03:49:35 +08:00
Tianyi Cui
a8986c2c8a Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows
Beyond the mechanical conflicts (provider capability lines vs master's new
inheritsParentContext field; generated catalogs regenerated rather than
hand-merged; knip/lockfile), three master-side reworks required semantic
adaptation of this branch:

- The persona rework removed AgentOptions.systemPrompt, which was the
  structured-output instruction's channel. The instruction now rides the
  SAME final-request enforcement listener that injects the schema'd tool:
  appended per request to final.system (per-request wire state, not agent
  prompt state). Tests assert the wire request (adapter.requests) instead
  of child.options; the bare-direct-dispatch test pins the no-system arm.
- Tool guidance moved out of deployment prompts into per-tool prompt
  sections; the examples' workflow paragraph became a tool:<toolName>
  section contributed by dsh-tool-workflow (explicit-ask-only policy),
  and both example personas resolve to master's minimal identity+behavior
  form. tool-workflow gains inject: systemPrompt (+ peer dep, tsconfig
  ref); the export-shape guard updated.
- The uniform-RFC-format gate: the dynamic-workflows RFC restructured to
  the implemented/ skeleton (bare Status line; Proposal -> Decision;
  What-was-rejected -> Alternatives considered; new Consequences), and
  the overall-run-timeout deferral is now recorded in the RFC's Deferred
  list. The doc-graphs atlas classification gains the workflows seam
  (workflow-vm implementation, tool-workflow consumer).

Master's harness-identity section made "empty assembled prompt" states
unreachable through the loop, so the instruction-append is a plain
undefined-ternary and the structured tests assert append-not-replace.
All snapshot goldens (including workflow-run) replay unchanged. Full
local CI-equivalent gate sequence green on the merged tree.
2026-07-06 03:14:07 +08:00
Tianyi Cui
2093a8898b loop: every request is built from the log — boundary snapshot, header events, config-only waterfall
The loop is now transmission-stateless; a request is a pure function of
(session log, this step's rendered assembly, current AgentOptions):

- The reconstruction boundary is step/start: the messages snapshot is
  taken in the same synchronous frame immediately before the step/start
  append, so the request's messages are exactly the derivation over
  events[0..stepStartSeq) — an inject() from an agent/request listener
  (or any concurrent task) lands after the boundary and joins the NEXT
  request. This changes behavior for a synchronous step/start
  session/event listener that appends content (master derived after the
  append, so such a listener could reach the current request):
  agent/pre-step is the sanctioned seam for current-request content.
- agent/request is re-typed to config-only: (agent, turn, step,
  config: LlmCallConfig, next) → LlmCallConfig. The frozen seed comes
  from AgentOptions on a loop instance's first request (explicit options
  beat the logged baseline — fork overrides and resume reconfiguration
  stay correct) and from the log's folded header afterwards; listeners
  return a replacement to switch. Content shaping through the request is
  no longer expressible — model-visible content flows through the log
  channels.
- recordRequestHeader appends whatever header event the request owes the
  log before dispatch: an 'initial'/'resume' snapshot anchoring each
  loop instance, a round-trip-verified delta on change, a 'fallback'
  snapshot when the encoding cannot express it. Session.requestHeader()
  is the log's incrementally-folded baseline.
- Requests are deep-frozen before dispatch (deepFreeze exempts the
  AbortSignal — freezing one breaks AbortController.abort() outright);
  frozen + sessionId is the loop-built marker the dev invariant keys on.

Ported from #162 and re-anchored on the log: the append-extension /
frozen-end-to-end / compaction-resend / prompt-change property tests,
plus new specs for the boundary semantics, resume anchoring, and the
end-to-end theorem (every recorded request rebuilds byte-equal from the
log alone). Live cache-hit e2e (request-cache.e2e.ts) verified against
the real DeepSeek API. Snapshot goldens intentionally stale until the
single re-record after the compact/summary envelope lands.
2026-07-06 03:07:34 +08:00
Tianyi Cui
a4f7e757fa session: cache the derived history — one projection per node, frozen and shared
deriveMessages() no longer re-derives and re-clones the whole surface
per call: each node is projected exactly once, when first seen (O(new
nodes) per access), through the now-public deriveEventMessage — the
per-node pure function external reconstructors and the dev invariant
fold over a log prefix, so no two paths can disagree about a request's
messages. A surface rewrite (replace, invalidate) rebuilds, signalled
by SurfaceManager.replaceGeneration — monotonic, bumped by every folded
replace and by invalidate(), never reset. Callers get a fresh array
snapshot per call over SHARED deep-frozen messages: isolation of the
append-only log moves from per-call cloning to unrepresentability
(mutation throws), which the two isolation tests now pin directly.
2026-07-06 02:51:20 +08:00
Tianyi Cui
a7b569850b session: the request header becomes logged state — request/header events + fold/diff/apply
Every conversation request's non-content half (system prompt, tool
schemas, call config — the EpochHeader) is now recorded in the session
log: a 'request/header' full snapshot (reason 'initial' | 'resume' |
'fallback') anchors the fold at conversation birth and process
boundaries, and 'request/header-delta' events (system line-trim,
name-keyed tools delta, whole config) encode mid-run changes. The pure
trio — foldRequestHeader / diffHeader / applyHeaderDelta — reconstructs
the header any request was built under from the log alone; the writer
contract round-trip-verifies every delta with a 'fallback' snapshot
when the encoding cannot express a change (pure tool reordering), so a
well-formed log always folds cleanly. Canonical absence: empty system
and empty tools normalize to absent fields, matching request builds.

Persistence and cordis catalogs regenerated; SessionEventMap paste and
EpochHeader added to the core-data-structures session page.
2026-07-06 02:42:51 +08:00
Tianyi Cui
8510986909 compact: summarize is a direct one-shot llm/stream call, not a loop step
The summarization request no longer dispatches agent/request — that seam
shapes the loop's conversation requests; a hand-built one-shot's
interception surface is llm/stream, like every other direct call. The
model comes from summarizationModel falling back to the agent's own. The
turn/step parameters existed on the compact seam only to feed the
agent/request dispatch and leave compactIfNeeded/compactRegion.

Groundwork for making every conversation request a pure function of the
session log (reconstructability RFC, this branch): the seam split keeps
the loop's request path as the single thing the log must explain.

Ported from worktree-prompt-prefix-stability (PR #162) where it was
review-converged; catalog and producer/consumer graphs regenerated.
2026-07-06 02:16:11 +08:00
Tianyi Cui
2ba4964aba docs: regenerate the services catalog for the seam-contract JSDoc 2026-07-06 00:54:21 +08:00
Tianyi Cui
3633cf90c8 fix(review): contain provider-removed listener failures; pin the model-via-request path
ds-review-bot round 2, both warnings:

- subagent/provider-removed now routes through emitLifecycle (per-listener
  containment, the subagent/start|end precedent) instead of raw ctx.emit,
  whose dispatch halts on the first throw: a throwing subscriber can no
  longer starve a later mirror into keeping a stale tool, nor disrupt the
  backend fiber's teardown mid-disposer. provider-added deliberately keeps
  propagation (register-time rollback semantics, like the system-prompt
  registries); the asymmetry is documented on emitLifecycle, the event
  JSDoc, and the provider-lifecycle RFC.

- The documented model-via-agent/request fallback composes with a
  {{model}} persona via the ownership rule itself: the plugin supplying
  the model late states it early on the system-prompt/assemble waterfall.
  Declined re-ordering render after agent/request — it would break the
  agent/pre-step contract (compaction must measure the prompt the model
  sees). New loop test pins the supply path end-to-end; the RFC's
  {{model}} consequence bullet now covers supply as well as switch.
2026-07-06 00:34:47 +08:00
Tianyi Cui
3f83a4ee96 review: the persona becomes the system-prompt plugin's deployment config
Review round 2 (tianyicui inline comments):

- dsh-system-prompt itself registers the harness:identity (-100) and
  deployment:persona (0) sections — they must survive a swapped loop
  plugin, so they leave dsh-agent-loop; the persona text is the plugin's
  own validated 'persona' config. The model/cwd variables STAY on the
  loop: runtime facts of the agents it drives.
- AgentOptions.systemPrompt is deleted with all its forwarding plumbing:
  the app configs' systemPrompt keys become 'persona' routed through
  dsh-agent-core (schema = z.intersect of the owners'), the ACP bridge
  and tool-subagent stop carrying persona configuration, and subagent
  children now render the deployment persona like every other agent.
- Example personas drop transport/interface trivia (ACP, CLI) — facts
  irrelevant to the model.
- Root CONTEXT.md removed (not idiomatic); its persona definition was
  wrong under the new ownership anyway.
- Docs, READMEs, the prompt-variables RFC, and generated catalogs
  updated; new loop test pins the assemble-waterfall escape valve
  (an emptied assembly sends NO system field).
2026-07-05 23:23:46 +08:00
Yichen Jiang
c2b0278185 Merge remote-tracking branch 'origin/master' into codex/skill-system
# Conflicts:
#	docs/architecture.md
2026-07-05 21:38:26 +08:00
Yichen Jiang
c7a833a893 fix: simplify skill config wiring 2026-07-05 21:05:43 +08:00
Tianyi Cui
2304f7a245 Merge origin/master: adopt the DeepSeek Harness SDK product name
Reconciliations beyond textual conflicts:
- product rename (DeepSeek Code -> DeepSeek Harness SDK) applied to the
  PR-added assertion in system-prompt.spec.ts that master's rename
  commit could not reach
- architecture.md: master's rewrite kept; this PR's prompt-assembly
  semantics re-added in the new doc's voice (Turn Flow footnote +
  service-spine row), within the 1630-word ceiling
- cordis catalog regenerated into master's split events.md/services.md
  (events-and-services.md deleted); module graph and doc graphs
  regenerated to pick up this PR's new events and dependency edges
2026-07-05 20:54:48 +08:00
Tianyi Cui
d899333cde docs: split cordis primer from architecture map 2026-07-05 19:07:34 +08:00
Tianyi Cui
e264a106fd workflow, subagent: fix Codex code-review round-1 blockers
Six verified A-findings from the code-stage review, each with a regression test:

- parallel()/pipeline() resolved to HOST arrays inside the vm realm, exposing
  host Array.prototype to scripts; combinator results are now realm-built
  (in-realm Array.from bound at context setup).
- materializeFromRealm ran proxy traps (ownKeys/getOwnPropertyDescriptor/
  getPrototypeOf) during the descriptor walk — realm code on the host stack,
  outside the vm timeout, escaping as raw errors; proxies (root, nested, and
  in the prototype position) are now rejected trap-free via util.types.isProxy
  before any inspection.
- an already-aborted signal or an immediate cancel() no longer reports
  'completed' for a hook-free script: drive() checks cancellation before
  running the body and again when the script settles.
- dispose() now waits (bounded by disposeGraceMs) for stray agent() children
  to FINISH disposing, not just for the script to settle: every agent() call
  is tracked and quiesce() drains the in-flight set.
- workflow/* event payloads were live mutable aliases shared across emissions;
  emitWorkflowEvent now hands each listener its own structural clone.
- the structured-output turn-continuation veto is now prepend: true, so an
  earlier-registered force-continue listener cannot short-circuit it.

Docs updated in the same change (READMEs, core-data-structures/workflow.md,
the dynamic-workflows RFC, regenerated cordis catalogs).
2026-07-05 19:04:38 +08:00