mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
docs(spec): couple transcript-skip to per-run resume decision
Address review: keying skipTranscript on the static resumesSessionViaCli flag would skip the transcript on guard-fail turns (force-fresh, history edit, no --resume capability) even though --resume is omitted, producing a cold spawn with neither resume nor history and breaking the non-regression guarantee. Derive both --resume and skipTranscript from the single per-run resumeSessionId; add supportsSessionResume capability distinct from the per-turn decision; and assert full-transcript presence in every guard-fail test.
This commit is contained in:
parent
fb18bcd055
commit
278e7ebbcf
1 changed files with 34 additions and 10 deletions
|
|
@ -193,9 +193,22 @@ turn N+1: resolveResumeDecision(conv, agent, epoch, forceFresh, caps)
|
|||
|
||||
### Design Decisions
|
||||
|
||||
1. **Claude-only, capability-gated, opt-in per adapter.** Reuse the existing
|
||||
`resumesSessionViaCli` semantics so the transcript-skip seam and the resume
|
||||
flag travel together; other adapters are untouched.
|
||||
1. **Claude-only, capability-gated, opt-in per adapter.** Other adapters are
|
||||
untouched. Note the existing `resumesSessionViaCli` flag is a *static,
|
||||
per-adapter* skip-transcript switch (agy resumes on every follow-up or never).
|
||||
Claude resumes *conditionally per turn*, so it must NOT reuse that static flag
|
||||
to gate transcript-skipping — see Design Decision #1a.
|
||||
1a. **Transcript-skip is keyed to the per-run resume decision, never a static
|
||||
flag.** Both `--resume` and skip-transcript derive from the single per-run
|
||||
`resumeSessionId` returned by `resolveResumeDecision()`: present → emit
|
||||
`--resume` AND skip the transcript; null → omit `--resume` AND send the full
|
||||
transcript. They are coupled so a guard-fail / no-capability / force-fresh
|
||||
turn can never produce the broken state "cold spawn + no `--resume` + no
|
||||
transcript" (which would silently drop all prior context and break the
|
||||
non-regression guarantee in Design Decision #4). For Claude, leave the static
|
||||
`resumesSessionViaCli` flag unset; introduce `supportsSessionResume` as a
|
||||
*capability* (can this CLI resume at all?) distinct from the per-turn
|
||||
*decision* (should THIS turn resume?).
|
||||
2. **Store a pointer keyed on `(conversationId, agentId)`** — the OD analog of
|
||||
multica's per-(agent, issue) session. A dedicated small table avoids bloating
|
||||
`conversations` and makes the agent-switch guard a natural key miss.
|
||||
|
|
@ -232,13 +245,22 @@ per `AGENTS.md`:
|
|||
- **Resume happy path (red on main).** Two turns, same conversation, same agent:
|
||||
assert turn 2 spawns with `--resume <sid-from-turn-1>` and that turn 2's stdin
|
||||
prompt does **not** contain the full transcript (only `currentPrompt`).
|
||||
Every guard-fail case below asserts BOTH halves of the coupling (Design
|
||||
Decision #1a): no `--resume` AND the full transcript is present in the stdin
|
||||
prompt — this is the explicit non-regression proof that a fallback turn never
|
||||
loses prior context.
|
||||
- **Agent-switch guard.** Turn 1 Claude, turn 2 after switching agent → no
|
||||
`--resume`; transcript path used.
|
||||
- **Force-fresh.** Retry-from-message and `--fresh-session` → no `--resume`.
|
||||
- **History-edit epoch guard.** Editing a prior turn bumps epoch → no `--resume`.
|
||||
`--resume` AND turn 2's prompt contains the full transcript.
|
||||
- **Force-fresh.** Retry-from-message and `--fresh-session` → no `--resume` AND
|
||||
full transcript present.
|
||||
- **History-edit epoch guard.** Editing a prior turn bumps epoch → no `--resume`
|
||||
AND full transcript present.
|
||||
- **Runtime-rejection fallback.** Stub a `claude` that rejects `--resume` → the
|
||||
daemon retries with transcript and the run still succeeds.
|
||||
- **Capability probe.** A `claude --help` without `--resume` → flag never sent.
|
||||
daemon retries WITHOUT `--resume` AND WITH the full transcript, and the run
|
||||
still succeeds.
|
||||
- **Capability probe.** A `claude --help` without `--resume` → flag never sent
|
||||
AND every turn carries the full transcript (skip-transcript stays off because
|
||||
`resolveResumeDecision` returns null without the capability).
|
||||
- **Interactive intact.** An `AskUserQuestion` turn still resolves via
|
||||
`POST /api/runs/:id/tool-result` under resume.
|
||||
|
||||
|
|
@ -265,8 +287,10 @@ if (runtimeContext.resumeSessionId && caps.sessionResume) {
|
|||
args.push('--resume', runtimeContext.resumeSessionId);
|
||||
}
|
||||
|
||||
// prompt composition
|
||||
const skipTranscript = def.resumesSessionViaCli === true || resumeSessionId != null;
|
||||
// prompt composition — keyed ONLY to the per-run decision, NOT a static flag.
|
||||
// `--resume` (above) and skipTranscript share the same source of truth, so a
|
||||
// guard-fail turn (resumeSessionId == null) always sends the full transcript.
|
||||
const skipTranscript = resumeSessionId != null;
|
||||
|
||||
// on run success (mirrors multica PinTaskSession)
|
||||
if (finalSessionId) upsertConversationAgentSession(db, {
|
||||
|
|
|
|||
Loading…
Reference in a new issue