Rename RFCs to Agent Notes
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# Agent Note: Persist assembled assistant messages, not stream chunks
|
||||
|
||||
Status: rejected — high-fidelity chunk replay, partial failed streams, and snapshot replay currently depend on persisted `assistant/chunk` events. Dropping chunks is only viable with a no-information-loss replay/artifact replacement.
|
||||
|
||||
## Problem
|
||||
|
||||
The canonical session log currently persists every `assistant/chunk` exactly as streamed by the model. The [session persistence Agent Note](../../implemented/architecture/2026-06-14-session-persistence.md) chose this for token-level replay fidelity and contiguous `seq`, but the cost has grown: JSONL fixtures are dominated by tiny delta records, snapshot scenarios replay the model by grouping chunk events, ACP load reconstructs prior assistant output from chunks, and any future log reader must distinguish durable message history from token-level trace.
|
||||
|
||||
For successful steps that assemble completed content, the loop already appends an `assistant/message`. That is the event `deriveMessages()` uses for the next model request. In other words, the normal resumable conversation state is already present without the chunks; chunks are a live rendering and deterministic-test artifact, not required conversation history. Failed or aborted streams are different: partial assistant output may exist only as chunks, and empty max-token steps may produce no `assistant/message` at all.
|
||||
|
||||
## Proposal
|
||||
|
||||
Stop storing `assistant/chunk` in the canonical session log. The durable log keeps `assistant/message`, `tool/call`, `tool/result`, `usage` if retained, and turn boundaries. Live UIs can still receive token deltas through a deliberately transient stream event. Snapshot replay should move its model script into an explicit fixture sidecar or derive it from a recorded adapter artifact, rather than treating the canonical user session as a token tape. Scenarios that need partial failed-stream output must record that output in the replay fixture.
|
||||
|
||||
ACP `session/load` can replay prior assistant messages as complete content blocks instead of simulating the original token stream. A loaded transcript need not reproduce every historical delta; it must show the same completed assistant content and resume with a valid provider history.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `SessionEventMap` drops `assistant/chunk`, or marks it as non-persisted if a transitional live event is needed.
|
||||
- [Session persistence docs](../../../../packages/session-persistence/session-persistence/README.md) no longer require every stream chunk to be stored verbatim.
|
||||
- `llm-replay` and ACP snapshots use an explicit replay fixture format or sidecar for model chunks.
|
||||
- `session/load` renders completed assistant messages from `assistant/message`.
|
||||
- Stored logs get much smaller and remain `seq`-contiguous without chunk holes.
|
||||
- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy.
|
||||
|
||||
## What we give up
|
||||
|
||||
The canonical user session no longer reconstructs the exact token stream of an old turn. It also loses partial assistant output from failed or aborted streams unless another event or fixture records it. That is too much information loss for the current resume, load, and snapshot contracts. Tests that need exact deterministic streams should own that fixture directly only if the production session log keeps enough fidelity for user-visible recovery.
|
||||
|
||||
## Related
|
||||
|
||||
This supersedes the chunk-persistence choice in [session persistence](../../implemented/architecture/2026-06-14-session-persistence.md) and affects [ACP snapshot tests](../../implemented/testing/2026-06-19-acp-snapshot-tests.md), whose current replay plugin derives its script from `assistant/chunk` events.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: Drop ACP session/load until resume has a product shape
|
||||
|
||||
Status: rejected — Zed is the current target ACP client, advertises and exercises load-capable sessions, and keeps pending-load state for concurrent `session/load`. The bridge should keep `session/load` and make the resume contract solid.
|
||||
|
||||
## Problem
|
||||
|
||||
ACP advertises `loadSession: true` and implements `session/load` by injecting persistence into the bridge, validating cwd against stored metadata, reconstructing an agent from the persisted log, and replaying prior transcript updates to the client. That path has its own race handling, loading-id guard, replay presenter logic, and tests. It also depends on the canonical log retaining enough UI data to reconstruct old chunks and tool presentations.
|
||||
|
||||
Durable persistence remains foundational, but editor-visible resume is not yet a designed product flow. There is no session picker, no title/preview metadata, and no clear UX for failed or partial loads. The bridge is paying complexity for a feature that is exercised by tests, documentation, and the current target client's session model.
|
||||
|
||||
## Proposal
|
||||
|
||||
For now, ACP starts fresh sessions only. `initialize` advertises `loadSession: false` or omits the capability, and `session/load` is unsupported. Persistence remains available to the agent loop and tests; resume can still exist as a lower-level factory if another consumer needs it. The editor bridge should reintroduce `session/load` alongside a real session-selection UX and a stable load transcript contract.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- ACP no longer injects `sessionPersistence` solely for `session/load`.
|
||||
- `initialize` does not advertise load support.
|
||||
- The `session/load` handler, loading-id tracking, cwd preflight for loaded sessions, and load replay tests are removed.
|
||||
- Snapshot fixtures no longer rely on load replay presentation.
|
||||
- [ACP docs](../../../../packages/ui/acp/README.md) describe fresh-session support only.
|
||||
|
||||
## What we give up
|
||||
|
||||
An editor cannot reopen a prior persisted session through ACP. That is a real product feature, but the current implementation is ahead of the UX and ties the bridge to token-level log replay. Keeping persistence while dropping editor load narrows the bridge to the workflow it can currently present cleanly.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,29 @@
|
||||
# Agent Note: Drop ACP terminal `_meta` rendering
|
||||
|
||||
Status: rejected — Zed is the current target client, and the terminal `_meta` convention is intentional Zed UX with a plain ACP fallback for other clients.
|
||||
|
||||
## Problem
|
||||
|
||||
The ACP bridge implements a Zed-specific terminal-card convention through `_meta.terminal_info`, `_meta.terminal_output`, and `_meta.terminal_exit`. The implemented [rich ACP bash rendering Agent Note](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) deliberately avoided ACP's client-side `terminal/create` because bash execution belongs in the harness, but still adopted the reference agents' display-only `_meta` convention. That gives a nicer Zed card at the cost of bridge state, capability negotiation, terminal ids, special update mapping, text fallback tests, and exit-pill parsing in `dsh-tool-bash`.
|
||||
|
||||
The fallback path already exists: render the tool call and completed output as normal ACP content blocks. Non-Zed clients rely on that path anyway, but the Zed terminal card is a current target-client feature rather than speculative decoration.
|
||||
|
||||
## Proposal
|
||||
|
||||
Ignore `clientCapabilities._meta.terminal_output` and render bash results through the plain ACP content path. Keep execution agent-side through `dsh-bash`; only the display-specific terminal metadata is removed. A terminal card can return later if ACP standardizes agent-executed terminals or if the product decides Zed-specific display is worth the maintenance cost.
|
||||
|
||||
This proposal is narrower than [collapsing tool-owned UI presentation](2026-06-20-generic-tool-rendering.md): it keeps generic `presentCall`/`presentResult` if those survive, but removes the terminal sub-shape and `_meta` mapping.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- ACP no longer reads or stores `_meta.terminal_output` capability state.
|
||||
- `TerminalRendering`, terminal ids, terminal cwd resolution, and `_meta.terminal_*` update mapping disappear from `@deepseek-ai/dsh-acp`.
|
||||
- `ToolTerminal` disappears from `@deepseek-ai/dsh-tools`, or is unused and deleted with the presentation cleanup.
|
||||
- Bash result presentation no longer parses exit status for terminal pills.
|
||||
- The implemented [rich ACP bash rendering Agent Note](../../implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md) stays in `implemented/` as shipped history and is cross-linked from this proposal if superseded.
|
||||
|
||||
## What we give up
|
||||
|
||||
Zed users lose the dedicated terminal card: no cwd header, terminal display, or exit pill. They still see the command and output as plain content. That is a reasonable simplification while the ACP bridge is still unreleased and the `_meta` keys are a convention rather than a standard.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,29 @@
|
||||
# Agent Note: Drop bash full-output spill files
|
||||
|
||||
Status: rejected — full-output recovery is a real bash behavior. A future artifact/blob service may generalize it, but dropping spill files before that replacement would lose useful command output.
|
||||
|
||||
## Problem
|
||||
|
||||
`dsh-bash-local` keeps bounded in-memory output and spills large stdout/stderr streams into private temp files. That requires a private directory, random owner-only file creation, close-failure handling, byte-offset incremental reads, lossy read reporting, path rendering in model-facing text, and cleanup discipline. The tool then tells the model to read a local spill path when output was truncated.
|
||||
|
||||
This solves a real problem, but in a narrow and leaky way. A spill path is a process-local filesystem artifact exposed to model output, not a durable harness artifact with scoped access, retention, or UI affordances. It also complicates background-task reads because a lossy incremental read has to point at one or two spill files.
|
||||
|
||||
## Proposal
|
||||
|
||||
Keep tail truncation, drop full-output spill files. A bash result contains the bounded tail plus a clear truncation marker; no path is emitted. If users need full-output recovery, add a generic artifact/blob service with explicit ownership, cleanup, and UI rendering, then let bash attach large outputs to that service.
|
||||
|
||||
This proposal can land independently of [a generic long-running tool runtime](../../implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md). If background tasks stay, `bash_output` should still report that output was dropped, but without advertising a spill path.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `CollectedOutput` no longer carries spill paths.
|
||||
- `OutputCollector` keeps bounded buffers only and deletes the temp-file machinery.
|
||||
- `renderResult()` reports truncation without a filesystem path.
|
||||
- Tests cover tail truncation and no longer assert full-output file contents.
|
||||
- Security guidance in [docs/defensive-patterns.md](../../../../docs/defensive-patterns.md) stops treating private spill files as a model-visible interface.
|
||||
|
||||
## What we give up
|
||||
|
||||
A model or user cannot recover the omitted prefix of a huge command output from a temp file. That is acceptable until there is a real artifact service. The current spill path is too much bespoke machinery for a feature whose lifecycle and permissions are not designed.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,30 @@
|
||||
# Agent Note: Drop durable step boundary events
|
||||
|
||||
Status: rejected — `step/end` is the durable indication that a model step finished, and keeping the symmetric `step/start` / `step/end` pair makes crash repair, invariants, and transcript inspection clearer than inferring completion from adjacent step-scoped events.
|
||||
|
||||
## Problem
|
||||
|
||||
The session log stores `step/start` and `step/end` events even though every step-scoped event already carries `{ turn, step }`: assistant chunks, assistant messages, tool calls, tool results, usage, and errors. `deriveMessages()` ignores step boundaries, ACP ignores them for UI, and the main consumers are invariants, tests, snapshot expected outputs, and crash repair.
|
||||
|
||||
The rejected argument was that boundary events make the log more ceremonial than informative. In practice, `step/end` is concrete information: a reader can tell whether a model request finished, crashed, or is being repaired without deriving that state from the next event. A bare `step/start` is likewise useful for a model request that began but produced no chunks before failing.
|
||||
|
||||
## Proposal
|
||||
|
||||
Make the turn the only durable boundary. Remove `step/start` and `step/end` from `SessionEventMap`; keep the numeric `step` field on events that need grouping. The loop increments the step counter and records step-scoped events with that number, but it no longer appends open/close boundary events. Consumers infer step groups from contiguous events sharing `(turn, step)`.
|
||||
|
||||
The invariants plugin should enforce that step-scoped events have valid positive step numbers within an open turn, not that separate boundary records surround them. Crash repair should not synthesize `step/end`; if an interrupted turn is preserved, the repair path can still close the turn without inventing step boundary records.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `SessionEventMap` no longer includes `step/start` or `step/end`.
|
||||
- The loop has no `closeStep()` finalization path.
|
||||
- ACP snapshots and persistence contract fixtures stop expecting step-boundary lines.
|
||||
- `deriveMessages()` and replay derive the same message history from step-scoped events.
|
||||
- The [event taxonomy docs](../../../../docs/architecture.md) describe turns as the durable boundary and steps as a field on step-scoped records.
|
||||
- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy.
|
||||
|
||||
## What we give up
|
||||
|
||||
The log no longer records "a model request started but produced no event before the process died" as a durable fact, and no longer has an explicit "this step completed" marker. That loss is not acceptable while the session log is the durable replay and audit surface.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,29 @@
|
||||
# Agent Note: Drop unused session lineage metadata
|
||||
|
||||
Status: rejected — `parentSession` is part of the documented fork/sub-agent seam and is already preserved by the agent/session resume path. The field is future-facing, but it is not accidental dead state.
|
||||
|
||||
## Problem
|
||||
|
||||
`SessionHeader.parentSession` records the session a new session was forked from. It is defined in `dsh-session`, preserved by persistence backends, copied through resume, documented as lineage metadata, and covered by round-trip tests. The repo has no production fork UI or sub-agent flow that reads it. The planned sub-agent/fork seam is still a TODO, so the field is currently stored future shape.
|
||||
|
||||
The cost is small per file but broad across the format: every backend schema and metadata serializer preserves a value that no completed feature reads yet. Because the header is an on-disk contract, even a placeholder field becomes something future refactors must either maintain, migrate, or deliberately break.
|
||||
|
||||
## Proposal
|
||||
|
||||
Remove `parentSession` from `SessionHeader` until a real fork/resume feature needs lineage. Forking can still seed a new session with prior events if such an API exists, but the durable parent pointer should be introduced alongside the feature that reads it and the UX that explains it.
|
||||
|
||||
If lineage returns, decide then whether it belongs in the immutable header, a session graph index, or a first-class event. The current field should not pre-commit that design.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `SessionHeader` contains version, id, createdAt, and optional cwd only.
|
||||
- JSONL and SQLite metadata schemas stop storing parent-session ids.
|
||||
- Resume and list APIs no longer round-trip `parentSession`.
|
||||
- Docs and tests remove fork-lineage claims that are not backed by a production consumer.
|
||||
- The session format version, backend schema versions, and recorded fixtures are refreshed as needed; non-current stored data is rejected per the pre-release format policy, with no migration path.
|
||||
|
||||
## What we give up
|
||||
|
||||
The codebase loses a ready-made lineage hook for future fork/sub-agent UX. That is intentional. The field is easy to reintroduce when the feature exists, and the unreleased stance lets the format change without migrations.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,29 @@
|
||||
# Agent Note: Fold the persistence interface into dsh-session
|
||||
|
||||
Status: rejected — the separate persistence interface package is the intended modular capability seam for durable backends. Folding it into `dsh-session` would reduce package count at the cost of a cleaner backend boundary.
|
||||
|
||||
## Problem
|
||||
|
||||
`dsh-session-persistence` is an interface package whose main concepts are already owned by `dsh-session`: `SessionHeader`, `SessionEvent`, `SessionId`, `session/event`, and `session/flush`. The package adds the abstract `SessionPersistence` service, the shared write coordinator, and contract helpers. Backend packages depend on it, and `agent-loop` has to optionally find a sibling service for resume.
|
||||
|
||||
The capability-seam split made sense when persistence was a new swappable backend design. After the mutable summary was removed, the interface package mostly wraps the session log's own storage concern. Keeping it separate may be more ceremony than clarity.
|
||||
|
||||
## Proposal
|
||||
|
||||
Move the abstract `SessionPersistence` service, the coordinator, and persistence contract helpers into `dsh-session`. Keep JSONL and SQLite as separate backend packages that register the session-owned service. This preserves backend swappability while deleting one support package and one cross-package seam.
|
||||
|
||||
The implementing PR should update the [capability seams](../../implemented/architecture/2026-06-13-capability-seams.md) guidance with the exception: persistence is not like bash or LLM because its vocabulary and lifecycle events are already the session package's core domain.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `@deepseek-ai/dsh-session-persistence` is removed as a package.
|
||||
- `dsh-session` exports the persistence service type, coordinator, and contract helpers.
|
||||
- JSONL and SQLite backend packages depend on `dsh-session` directly.
|
||||
- `agent-loop` resume uses the session-owned service key.
|
||||
- [Session persistence](../../implemented/architecture/2026-06-14-session-persistence.md), [shared persistence write coordinator](../../implemented/architecture/2026-06-18-shared-persistence-write-coordinator.md), and [package docs](../../../../packages/session-persistence/session-persistence/README.md) explain why backend implementations remain separate.
|
||||
|
||||
## What we give up
|
||||
|
||||
`dsh-session` becomes heavier: it owns both the in-memory log and the persistence interface. That is the trade. If third-party persistence backends were already a public ecosystem, the separate interface package would be a cleaner SDK boundary; pre-release, the extra package looks like abstraction before there is an external consumer.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,33 @@
|
||||
# Agent Note: Collapse tool-owned UI presentation
|
||||
|
||||
Status: rejected — tool-owned presentation should wait for more real tools before being generalized or deleted. Bash and ACP currently need the existing richer presentation path.
|
||||
|
||||
## Problem
|
||||
|
||||
Tools can define `presentCall()` and `presentResult()` callbacks that return `ToolCallPresentation`, `ToolResultPresentation`, and optional `ToolTerminal` fields. The code itself flags the design as muddy: title, kind, raw input, content, terminal cwd, terminal output, exit code, and signal grew incrementally into a bag of optional fields. ACP then maintains pending call state to pair a result with the original args, creates replay-only presenters on `session/load`, and maps terminal subfields into Zed-specific `_meta`. `dsh-tool-bash` even parses exit status back out of rendered text because the pure replay-safe presenter no longer has the structured `BashRunResult`.
|
||||
|
||||
The real first-party use is bash presentation for ACP. That is too little evidence to freeze a cross-package UI presentation API.
|
||||
|
||||
## Proposal
|
||||
|
||||
Remove tool-owned UI presentation callbacks for now. The canonical tool events already carry the tool name, raw argument string, result content, and error state. UIs render a generic tool card from those fields. Tool-specific rich rendering can return later as a tagged render-intent union after there are at least two real tools and two real consumers to validate the vocabulary.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
As a smaller alternative, replace the current optional-field bag with one explicit union in a single PR; but if the goal is simplification, the stronger move is to delete the callbacks and keep the generic path.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `ToolDefinition` drops `presentCall` and `presentResult`.
|
||||
- `ToolCallPresentation`, `ToolResultPresentation`, `ToolTerminal`, and `ToolCallKind` disappear unless a minimal generic UI type still needs one.
|
||||
- ACP no longer keeps presenter pending state or calls tool callbacks during live streaming/load replay.
|
||||
- `dsh-tool-bash` no longer parses rendered text to recover exit status for a UI pill.
|
||||
- Snapshot expected outputs show generic tool cards and text results.
|
||||
|
||||
## What we give up
|
||||
|
||||
Bash loses its custom terminal-looking card and model-written description placement. The fallback remains reasonable: the command appears as tool input, and the output appears as text. Rich rendering should be designed when the product has enough UI/tool variety to justify a stable presentation contract.
|
||||
|
||||
## Related
|
||||
|
||||
This is the broad version of [dropping ACP terminal metadata](2026-06-20-drop-acp-terminal-meta.md). If this Agent Note is accepted, that narrower Agent Note becomes unnecessary.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Agent Note: Retire mid-turn steering
|
||||
|
||||
Status: rejected — mid-turn steering is an intentional agent capability for between-step user/plugin input and future goal/loop workflows. It is complexity with a product direction, not an accidental duplicate of `send()`.
|
||||
|
||||
## Problem
|
||||
|
||||
The agent exposes two user-message paths that look close but have different lifecycle semantics: `send()` queues a normal user turn, while `steer()` injects a message between steps of the currently running turn and falls back to `send()` when idle. That distinction leaks through the whole stack: `Agent.steer()` is public API, the session log has a durable `steering/message` event, the agent event taxonomy has `agent/steering`, the loop maintains a steering FIFO beside the queued-message FIFO, cancellation clears both queues, and `deriveMessages()` has to render steering as a tagged synthetic user message rather than a normal prompt.
|
||||
|
||||
The continuation seam amplifies the cost. `agent/turn-continuation` defaults to `hadToolCalls || steeringInjected`, so a same-turn steering message can force the loop to call the model again even if the model did not ask for tools. The comments name future `/goal`, `/loop`, and budget-guard uses, but the current repo has no production listener; only tests register the waterfall. Separately, the only production UI that calls `steer()` is the stdio demo. ACP already sends prompts through the ordinary queue while a turn is running.
|
||||
|
||||
## Proposal
|
||||
|
||||
Delete mid-turn user steering for now. `Agent.send()` becomes the single public way to submit user content; when the agent is running, the content waits for the next turn. The loop continues within a turn only for tool calls, not because a user typed while a step was running. A caller that wants to interrupt the current turn uses `cancel()` and then `send()`.
|
||||
|
||||
Remove `Agent.steer()`, the steering FIFO, `steering/message`, `agent/steering`, steering-derived continuation, and the cancellation logic that distinguishes queued messages from steering messages. Remove `agent/turn-continuation` in the same change unless the implementing PR discovers a production listener; without steering, the current repo has no concrete continuation consumer left. If a real budget or goal plugin later needs forced continuation, it should reintroduce a narrower seam with that plugin as the concrete consumer.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `Agent` exposes one user-message entry point, `send()`.
|
||||
- The durable session event vocabulary no longer contains `steering/message`.
|
||||
- `deriveMessages()` renders normal user messages and context injections, with no steering tag path.
|
||||
- The loop has one queued-message FIFO and no same-turn user-message continuation path.
|
||||
- `agent/turn-continuation` is removed or narrowed to a named production consumer.
|
||||
- The stdio UI and docs describe input while running as queued next-turn input.
|
||||
- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy.
|
||||
|
||||
## What we give up
|
||||
|
||||
A user cannot add same-turn steering content while a model is between tool steps. That behavior is useful in theory for "while you are already working, also consider X", but it is not the behavior ACP exposes today and it makes the turn boundary much harder to reason about. The simpler behavior is reasonable: user input becomes the next prompt, and cancellation remains the explicit tool for replacing in-flight work.
|
||||
|
||||
## Related
|
||||
|
||||
This pairs naturally with [dropping durable step boundaries](2026-06-20-drop-durable-step-boundaries.md), because removing same-turn steering and `agent/turn-continuation` leaves tool calls as the only reason a turn contains multiple model steps.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,29 @@
|
||||
# Agent Note: Return the ACP bridge to one live session per connection
|
||||
|
||||
Status: rejected — Zed is the current target ACP client and its ACP implementation is explicitly multi-session: it stores live sessions in a `HashMap<SessionId, AcpSession>`, tracks `pending_sessions`, joins concurrent loads for the same id, and tests close-during-load behavior.
|
||||
|
||||
## Problem
|
||||
|
||||
The ACP bridge now supports multiple live sessions on one JSON-RPC connection. That capability brings multi-entry session maps, reverse session/agent lookups, per-session prompt state, loading ids, demux for every event, cross-session teardown, and isolation concerns for future permission prompts and background tasks. The older [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) still tracks the unfinished permission-ownership piece; this Agent Note is the competing simplification path.
|
||||
|
||||
The product target has proven it needs concurrent editor conversations over one harness process: Zed's ACP connection owns multiple sessions and load states. The snapshot replay tier still avoids concurrent model streams because its replay entries are positional; that is a test-fixture limitation, not a reason to remove bridge multiplexing.
|
||||
|
||||
## Proposal
|
||||
|
||||
Scope ACP back to one live session per connection. `session/new` or `session/load` creates the only session record; a second live session request is rejected until the existing session is disposed or the connection closes. If editors need multiple chat tabs, they can launch multiple agent subprocesses until the bridge has a concrete multi-session UX and permission model.
|
||||
|
||||
Remove the multi-session maps and demux where a single `SessionRecord | undefined` is enough. The bridge can still keep the agent/session lifecycle seams that make disposal correct; the simplification is only about multiplexing more than one active session through the same transport.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- ACP has one active session record per connection.
|
||||
- `session/new` and `session/load` reject while that record exists.
|
||||
- Event handlers no longer demux across a `Map<sessionId, record>`.
|
||||
- Multi-session tests are removed or moved under the proposal that continues to defend multiplexing.
|
||||
- The existing [multi-session ACP proposal](../../implemented/feature/2026-06-14-acp-multi-session.md) is updated to link this Agent Note and remains the live direction.
|
||||
|
||||
## What we give up
|
||||
|
||||
An ACP client cannot host several concurrent conversations on one server process. That is a meaningful capability cut. The simpler model is still reasonable for an unreleased harness: one editor conversation maps to one agent process, and cross-session permission/background-task isolation stops being a live correctness burden.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,34 @@
|
||||
# Agent Note: Truncate interrupted final turns on load
|
||||
|
||||
Status: rejected — a single turn can contain substantial real work, including many steps and large tool output. Preserving interrupted turns is preferable to silently dropping that tail on load.
|
||||
|
||||
## Problem
|
||||
|
||||
The current persistence contract preserves a final turn that was durably written but never closed. On load, `interruptedTurnClosers()` scans the tail, synthesizes error `tool/result` events for unanswered tool calls, appends a `step/end` when a step is open, appends `turn/end { kind: 'interrupted' }`, and asks the backend to durably commit that repair. The coordinator, JSONL backend, SQLite backend, session event vocabulary, invariants, docs, and tests all model this synthetic close path.
|
||||
|
||||
This is a lot of machinery to preserve partial work from the last crashed turn. It also invents events that never happened. A synthetic tool result is useful because it makes provider history valid, but it also means the resumed log contains model-visible text that no tool produced. The current design optimizes for maximum tail preservation before there is a released product or a real resume UX that proves partial-turn recovery matters.
|
||||
|
||||
## Proposal
|
||||
|
||||
On load, keep only the last completed turn. A backend still tolerates and truncates a torn final record, but if the parsed durable prefix ends after an open `turn/start`, the canonical repair is to drop every event after the previous `turn/end`. No synthetic `tool/result`, no synthetic `step/end`, no `turn/end { interrupted }`, and no `interrupted` turn-end reason.
|
||||
|
||||
This makes the persisted turn boundary simple: a completed `turn/end` is the checkpoint. Anything after the last checkpoint is crash tail. The next prompt resumes from the last known-valid provider transcript, not from a partially reconstructed final turn.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `TurnEndReasonMap` drops the `interrupted` variant.
|
||||
- `interruptedTurnClosers()` and its tests disappear.
|
||||
- The persistence coordinator's repair hook truncates backend-specific torn/open tail state without appending closers.
|
||||
- [Session persistence docs](../../../../packages/session-persistence/session-persistence/README.md) say load returns the last completed turn, plus no partial final turn.
|
||||
- Snapshot and contract tests update together with the behavior they pin.
|
||||
- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy, with no migration path.
|
||||
|
||||
## What we give up
|
||||
|
||||
A crash can lose real work from the final turn: assistant text, tool calls, and tool output appended after the previous `turn/end`. That is the deliberate simplification. The product is unreleased, the final-turn recovery semantics are not user-proven, and a clean completed-turn checkpoint is much easier to explain, test, and implement. A future "recover partial crashed work" feature should be designed as an explicit user-facing recovery view, not as synthetic events silently inserted into the canonical transcript.
|
||||
|
||||
## Related
|
||||
|
||||
This is a direct simplification of [session persistence](../../implemented/architecture/2026-06-14-session-persistence.md) and [turn enclosure](../../implemented/architecture/2026-06-15-turn-enclosure-invariant.md). It also removes much of the motivation for durable step boundary events, making [drop durable step boundary events](2026-06-20-drop-durable-step-boundaries.md) smaller.
|
||||
|
||||
<!-- agent-note-format: alternatives-not-recorded (pre-format Agent Note) -->
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: Prune the unimplemented subagent seam vocabulary
|
||||
|
||||
Status: rejected — the deferred capability vocabulary (`outputSchema`/`structured`, `toolFilter`, `sendMessage`/`resume`) is intentionally reserved surface: the seam advertises the full intended contract ahead of its implementations by design, so providers and consumers grow into a stable shape rather than re-negotiating it per capability. The consumer-evidence analysis below records the decision-time state.
|
||||
|
||||
## Problem
|
||||
|
||||
The [subagent seam](../../implemented/feature/2026-06-21-subagent-capability-seam.md) shipped a two-tier capability design: start-time capability flags checked by the service, and optional runtime methods on `SubagentRun`. Three start-time features and both optional runtime methods have zero implementations and zero callers:
|
||||
|
||||
- **`outputSchema`/`structured` and `toolFilter`** (`SubagentCapabilities`, `SubagentStartRequest`, `SubagentResult` in `packages/subagent/subagent/src/types.ts`): at the decision point, every real provider declared `outputSchema: false, toolFilter: false` (`packages/subagent/subagent-spawn/src/index.ts`, `packages/subagent/subagent-fork/src/index.ts`, `packages/subagent/subagent-acp/src/index.ts`); the sole production `ctx.subagents.start` caller (`packages/subagent/tool-subagent/src/index.ts`) built `{ prompt, parent, signal?, agentOptions? }` and structurally could not set either; `structured` appeared only in the scripted test fixture. The service's capability check carried two assert rows whose only exercisers were the rejection tests.
|
||||
- **`SubagentRun.sendMessage` / `SubagentRun.resume`** (same file): implemented by NO provider — not even the mock; the spawn spec asserts their *absence*.
|
||||
|
||||
The only reason `dsh-subagent` depends on `dsh-tools` at all is `outputSchema`'s `SchemaSpec` type. Three subsequent subagent workstreams (per-session snapshot replay, the fork seed boundary, the ACP backend) landed around this surface without growing a single consumer.
|
||||
|
||||
## Proposal
|
||||
|
||||
Remove `outputSchema`/`structured`, `toolFilter`, `sendMessage`, and `resume` from the seam; shrink `SubagentCapabilities` to `{ depthLimit }`; drop the two capability-assert rows, the all-false flags on the three providers, the scripted fixture's structured branch and capability knobs, and the tests that exist to pin the removed surface. Drop the `dsh-tools` peer/dev dependency from `packages/subagent/subagent/package.json`. Update the [subagent.md](../../../../docs/core-data-structures/subagent.md) pastes and the type-equiv manifest, plus the affected provider READMEs. The implementing PR amends the seam Agent Note's capability catalog per [implemented/AGENTS.md](../../implemented/AGENTS.md).
|
||||
|
||||
**Keep** `depthLimit`/`maxDepth` and capability checks. The in-process backend enforces the limit, although the shipping tool does not yet set it. Recursion is a known seam risk, so the appropriate follow-up is to supply a tool default rather than delete working enforcement.
|
||||
|
||||
Adjacent surface examined and deliberately left alone: `SubagentService.getProvider()`/`list()` have test-harness consumers only, but the [prune-dead-seam-methods implementation note](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md) records precisely this shape being removed from the bash executor and reverted — a test harness IS a consumer for a one-line accessor over an already-tracked map. `SubagentRunEndInfo.lastAssistantMessage` is a recorded keep (the [subagent-observe-enrich Agent Note](../../implemented/feature/2026-06-30-subagent-observe-enrich.md)'s review dropped `agentType` and kept it deliberately, as the only final-message channel for out-of-process children); its currently-unwired bridge forwarding is a gap to close or a consumer to document, not surface for this Agent Note to cut.
|
||||
|
||||
This is the seam-vocabulary echo of [prune dead methods from the persistence seam](../../implemented/simplification/2026-06-20-prune-dead-seam-methods.md): members every implementation must declare for nobody — weaker even, since here zero implementations exist.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
### Why not keep it?
|
||||
|
||||
The two-kinds-of-capability design is the seam Agent Note's headline, and re-adding `outputSchema` later touches several files. But the design survives with `depthLimit` as its live example and the Agent Notes as its record, and the seam Agent Note itself concedes the shipped `toolFilter` shape is wrong (real enforcement needs a `tools/pre-execute` deny in the child's context, not schema filtering) — that deny primitive exists on the interception seams, so re-adding against a real implementing provider will pin a better contract than the current speculative one.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- The removed spellings appear only in this Agent Note and the amended seam Agent Notes; `SubagentCapabilities` is `{ depthLimit: boolean }`; the `dsh-tools` dependency edge is gone (`hygiene` green).
|
||||
- Depth-enforcement tests are unchanged and green.
|
||||
|
||||
## Risks
|
||||
|
||||
The subagent lifecycle events carry `lastAssistantMessage` on the end payload — that enrichment lives in the service module, not the seam vocabulary this Agent Note shrinks, and the observe-enrich Agent Note records dropping an `agentType` sibling for lacking a consumer: the judgment this Agent Note extends. The CC hooks bridge, the first outside consumer of those lifecycle events, reads only the event payloads and touches none of the surface removed here; the observe-enrich Agent Note's deferred control-flow redesign names implementing `resume` as its own future work — exactly the re-add trigger this Agent Note's pattern anticipates.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: Collapse workflows to the exercised foreground core
|
||||
|
||||
Status: rejected — Workflow progress is an intentional observation surface; make it useful through a consumer instead of deleting it.
|
||||
|
||||
## Problem
|
||||
|
||||
The workflow capability executes foreground JavaScript that composes subagents, but it also carries an unconsumed progress-observation system. No production listener subscribes to any of the six `workflow/*` events; listeners exist only in workflow tests. Nevertheless the seam defines run/phase/agent outcome payloads, the worker sends phase/log/agent lifecycle protocol messages, the host forwards them through a `liveAgents` pairing ledger, and the engine maintains run ids solely to correlate those notifications.
|
||||
|
||||
The progress vocabulary is not merely unused; it cannot serve its only named future owner without redesign. `WorkflowRunInfo` contains `{id, meta}` but no parent agent, session, or tool-call identity, while the model-facing tool never exposes the run id. A global ACP listener could not route an event to the correct client session. `meta.phases` is never consulted, `phase(title)` does not validate against it, phase `detail`/`model` and agent `label`/`phase` feed only events, and `whenToUse` is validated and copied but never rendered or selected. `phase()` and `log()` still cross the worker boundary despite having no receiver.
|
||||
|
||||
The live handle repeats event-era data after those observers disappear. `WorkflowRun.id` has no non-event consumer, while the tool reads `run.meta.name` only to render a value it already owns as `args.meta.name`; neither belongs on the execution/cancellation handle.
|
||||
|
||||
Cancellation also has two public channels for one synchronous start. `WorkflowStartRequest.signal` is passed to the worker host, while the sole production caller separately bridges the same signal to `WorkflowRun.cancel()`. Because `start()` returns the run before control can yield, there is no readiness window that requires request-time cancellation; the duplicate signal adds host listener/disarm state without closing a race.
|
||||
|
||||
`WorkflowError.fatal` is the same speculative branch in miniature: every production construction is fatal, `fatal: false` exists only in tests, and combinators already distinguish workflow failures with `instanceof`.
|
||||
|
||||
## Proposal
|
||||
|
||||
Keep the exercised core: `agent(prompt, { schema, model })`, `parallel`, `pipeline`, `args`, concurrency/agent caps, cancellation, bounded disposal, structured results, worker isolation, and foreground tool collection. Remove all `workflow/*` events and their event-only info/outcome types; remove `phase()`, `log()`, agent `label`/`phase`, phase declarations, `whenToUse`, and their worker messages/host observers; collapse workflow metadata to the name the tool actually uses; remove event-only run ids/meta snapshots and the synthesized agent-end ledger. Shrink `WorkflowRun` to `result`, `cancel()`, and `dispose()`; the tool renders the request-owned name. Remove `WorkflowStartRequest.signal` and the worker host's input-signal listener/disarm state, retaining the caller-owned bridge from its abort signal to `run.cancel()`. Make `WorkflowError` one fatal error class without a boolean mode or `isFatalWorkflowError()` helper.
|
||||
|
||||
Amend the implemented dynamic-workflow Agent Note and update the seam/tool/worker READMEs, tool schema, generated catalogs and package graph, worker type-equivalence records, unit tests, and workflow snapshot/header fixtures. Progress UI work, if commissioned, starts from a correlation contract that names the parent agent/session/tool call instead of reviving this protocol unchanged.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep the prebuilt observation vocabulary for a future UI.** The current shape resembles Claude Code dynamic-workflow metadata, and the host deliberately pairs each forwarded agent start with either the worker's end or a synthesized terminal end. Removing it gives up compatibility-by-shape and makes progress UI a new design task, but the existing payloads still lack routable ownership, so balanced lifecycles alone cannot make the named ACP owner viable without redesign.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- The workflow public seam contains only execution, cancellation, result, and disposal contracts with a production consumer.
|
||||
- No workflow event, phase/log protocol message, run-id generator, progress-only metadata, host pairing ledger, or fatal-mode branch remains.
|
||||
- The run handle has no id/meta echoes, and cancellation has one holder-owned channel after synchronous `start()` returns.
|
||||
- Parallel/pipeline behavior, caps, cancellation quiescence, worker containment, structured output, and the model-facing workflow scenarios retain coverage.
|
||||
- Typecheck, coverage, snapshots, doc-sync, module-graph verification, build, and hygiene pass.
|
||||
|
||||
## Risks
|
||||
|
||||
This is a compile-visible contraction of the workflow DSL, event taxonomy, handle, and start request. Existing workflow calls that supply descriptive metadata, and scripts that use `phase`, `log`, or labels, must shrink; programmatic callers bridge their own abort source to the returned handle; and a future observer must add a better-correlated seam. The execution semantics that make workflows useful do not change.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Agent Note: Prune unused skill registry surface
|
||||
|
||||
Status: rejected — Direct runtime skill registration is an intentional extension path for third-party plugins.
|
||||
|
||||
## Problem
|
||||
|
||||
The skill service's embedded-runtime subsystem has zero production caller of `ctx.skills.register()`. It adds a reserved `runtime` provider name, a runtime map/rank/source, duplicate policy, a second revision in cache keys, normalization, disposers, and tests alongside the provider seam every shipped skill already uses. `SkillSummary.whenToUse` and candidate/definition `path` are parsed and copied but never read by a production consumer: the model catalog renders name/description, resource loading uses `resourceBase`, and providers own their locator. The deliberately open `metadata` extension point stays.
|
||||
|
||||
## Proposal
|
||||
|
||||
Remove `SkillService.register()`, `SkillRegistration`, the runtime pseudo-provider and reserved-name rules, runtime revisions/cache branches, and runtime-only source/rank normalization. Tests that need an embedded skill register a small real provider. Retain `providerRevision` as the in-flight discovery epoch, but key completed catalogs by cwd alone: every provider mutation synchronously clears the cache, and the post-await revision comparison already prevents inserting stale work. Remove `whenToUse`, `SkillCandidate.path`, and `SkillDefinition.path` from the skill contract and local-provider copies while retaining provider locator/root paths; retain `metadata`, `disableModelInvocation`, `source`, `provider`, `locator`, and `resourceBase` as either deliberate extension vocabulary or production-consumed fields.
|
||||
|
||||
Amend the skill-system Agent Note, README, JSDoc, catalogs, and tests. Agent-scoped system-prompt sections, tool providers, and variables are explicitly outside this proposal: the [agent-scope contributor contract](../../implemented/architecture/2026-07-08-agent-scope-contexts.md) intentionally allows all three to be registered during `setup(agentCtx)` through the agent-owned context, so absence of a fixed in-repo scoped registration is not evidence of non-consumption.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep runtime skill registration for embedders.** It is a deliberate synchronous direct-definition convenience in the implemented skill Agent Note. A small provider wrapper can expose the same embedded data under effect-owned lifetime, but it must implement async `list()`/`get()`, carry provider identity, and accept provider duplicate semantics. The proposal chooses that one regular path over preserving a second ranking, validation, cache-invalidation, and lookup path.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- Skill collection has one provider-backed path, a cwd-only completed-cache key, and a revision epoch only for in-flight invalidation; retained skill fields have a production reader or a recorded deliberate extension contract.
|
||||
- Agent-scoped prompt sections, variables, tool providers, tool guards, and structured-output commit behavior in native and Code Mode remain unchanged.
|
||||
- Typecheck, coverage, snapshots, doc-sync, module-graph verification, build, and hygiene pass.
|
||||
|
||||
## Risks
|
||||
|
||||
This is a compile-visible contraction of the pre-release skill registry. External programmatic `list()`/`get()` consumers lose `whenToUse` routing hints and candidate/definition `path`; the shipped model catalog never renders them, and resource resolution keeps its explicit `resourceBase` plus provider-owned opaque locator, but those fields are not observationally identical. Skill-local frontmatter parsing must continue to preserve and validate the supported metadata schema, and external providers remain able to supply embedded, filesystem, remote, or other skill sources.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write
|
||||
2026-07-19-fold-compaction-package-split.md: 47c9feb6bb0dd06fec0f002b7c1e930b288abe5e
|
||||
2026-07-19-fold-compaction-package-split.zh.md: 53717ff10d1210bd2072f322d1936ac6c389afcd
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: Fold the single compaction backend into its service package
|
||||
|
||||
Status: rejected — More compaction backends are planned, so the interface and basic implementation packages remain separate.
|
||||
|
||||
English | [中文](2026-07-19-fold-compaction-package-split.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
Compaction is split between `@deepseek-ai/dsh-compact`, which owns an abstract two-method service and shared types, and `@deepseek-ai/dsh-compact-basic`, which owns the only complete implementation. Shipped configurations load only the basic package, and no production package independently consumes the interface package except that implementation.
|
||||
|
||||
The split adds a package manifest, README, project boundary, dependency edge, abstract forwarding class, generated catalog entries, and composition wiring without demonstrating backend substitution. The [capability-seam decision](../../implemented/architecture/2026-06-13-capability-seams.md) requires a real interface, implementation, and consumer rather than a preemptive split; the [compaction decision](../../implemented/feature/2026-06-18-compaction-capability-seam.md) records that its independent consumer was deferred.
|
||||
|
||||
## Proposal
|
||||
|
||||
Move the basic implementation into `@deepseek-ai/dsh-compact` and remove `@deepseek-ai/dsh-compact-basic`. Keep `ctx.compact`, `CompactionResult`, the shared transcript and tool-pairing helpers, the existing configuration, and the concrete compaction algorithm in one package.
|
||||
|
||||
Preserve `summarize()` as a protected customization hook. A deployment-specific summarizer can subclass or intercept the existing LLM call without requiring a second capability package. Reintroduce an interface package only when a second complete backend and an independent consumer need substitution.
|
||||
|
||||
Amend the implemented compaction decision and the [recallable-compaction proposal](../../proposed/feature/2026-07-06-recallable-compaction.md) if this proposal is accepted so package ownership has one durable description.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
**Keep the split because a remote or recall backend may arrive.** A possible future implementation does not justify the current package boundary. Recall adds a consumer of compaction results, not necessarily another implementation, and a remote summarizer can use the protected hook.
|
||||
|
||||
**Move the implementation package name onto the interface package.** Keeping `compact-basic` as the surviving name would make the product service appear to be one optional backend. `compact` is the stable service identity already used by `ctx.compact` and is the clearer single-package owner.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `@deepseek-ai/dsh-compact-basic` and its workspace/package metadata are removed.
|
||||
- `@deepseek-ai/dsh-compact` owns the current configuration, plugin class, algorithm, types, events, and shared helpers.
|
||||
- Existing deployments can load the surviving package with equivalent configuration and model-visible behavior.
|
||||
- Automatic and manual compaction preserve cancellation, locking, token accounting, tool pairing, durable events, provenance, retry convergence, and transcript rendering.
|
||||
- Loader composition, unit, runaway-turn, cancellation, snapshot, and real-model compaction tests pass; generated catalogs and module graphs are current.
|
||||
|
||||
## Risks
|
||||
|
||||
This is an intentional pre-release package-name contraction. Embedders loading `@deepseek-ai/dsh-compact-basic` must switch packages, and future backend substitution would require extracting a boundary again. The cost is acceptable only while one complete implementation exists; acceptance should be revisited if a second backend lands first.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Agent Note: 将唯一的压缩后端并入服务包
|
||||
|
||||
Status: rejected — 计划增加更多压缩后端,因此接口包与 basic 实现包继续分离。
|
||||
|
||||
[English](2026-07-19-fold-compaction-package-split.md) | 中文
|
||||
|
||||
## 问题
|
||||
|
||||
压缩(compaction)目前拆分在两个包中:`@deepseek-ai/dsh-compact` 拥有一个含两个方法的抽象服务和共享类型,`@deepseek-ai/dsh-compact-basic` 拥有唯一的完整实现。交付配置只加载 basic 包,除了该实现外,没有生产包独立消费接口包。
|
||||
|
||||
该拆分增加了一份包(package)manifest(元数据清单)、README、项目边界、依赖边、抽象转发类、生成目录项和组合接线,却没有体现后端替换需求。[能力服务边界决策](../../implemented/architecture/2026-06-13-capability-seams.md)要求接口、实现和消费方都必须真实存在,而不能预先拆分;[压缩决策](../../implemented/feature/2026-06-18-compaction-capability-seam.md)也记录了独立消费方仍被推迟。
|
||||
|
||||
## 提案
|
||||
|
||||
把 basic 实现移入 `@deepseek-ai/dsh-compact`,并删除 `@deepseek-ai/dsh-compact-basic`。`ctx.compact`、`CompactionResult`、共享 transcript(文本记录)和工具配对辅助方法、现有配置以及具体压缩算法都由一个包负责。
|
||||
|
||||
保留 `summarize()` 作为受保护的自定义钩子。部署专用的摘要器可以通过继承或拦截现有 LLM(大语言模型)调用完成定制,无需第二个能力包。只有在第二个完整后端与独立消费方确实需要替换实现时,才重新提取接口包。
|
||||
|
||||
如果本提案获准,应同步修订已实现的压缩决策与[可回忆压缩提案](../../proposed/feature/2026-07-06-recallable-compaction.md),使包所有权只有一处持久说明。
|
||||
|
||||
## 备选方案
|
||||
|
||||
**为可能出现的远程或回忆后端保留拆分。** 一种可能的未来实现不足以支撑当前包边界。回忆功能会增加压缩结果的消费方,但不一定增加另一种实现;远程摘要器也可以使用受保护钩子。
|
||||
|
||||
**让接口包并入实现包名。** 如果保留 `compact-basic` 作为最终名称,产品服务会看起来像一个可选后端。`compact` 已经是 `ctx.compact` 使用的稳定服务标识,更适合作为单包所有者。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 删除 `@deepseek-ai/dsh-compact-basic` 及其工作区和包元数据。
|
||||
- `@deepseek-ai/dsh-compact` 拥有当前配置、插件类、算法、类型、事件和共享辅助方法。
|
||||
- 现有部署可以使用等效配置加载保留的包,模型可见行为不变。
|
||||
- 自动压缩和手动压缩保留取消、锁、token 用量、工具配对、持久事件、来源、重试收敛和 transcript 渲染行为。
|
||||
- Loader 组合、单元、失控轮次、取消、快照和真实模型压缩测试全部通过;生成目录与模块图保持最新。
|
||||
|
||||
## 风险
|
||||
|
||||
这是一项有意实施的预发布包名收缩。加载 `@deepseek-ai/dsh-compact-basic` 的嵌入方必须切换包,未来的后端替换也需要重新提取边界。只有在仍然只有一个完整实现时,这项代价才可接受;如果第二个后端先行落地,应重新评估是否接纳本提案。
|
||||
Reference in New Issue
Block a user