Skip to content

--resume-id is silently ignored for v2/v3 engine sessions, breaking headless multi-turn #11069

Description

@okajun35

Before opening, please confirm:

Operating System

Ubuntu 24.04.3 LTS on WSL2 (kernel 6.6.87.2-microsoft-standard-WSL2)

Kiro Version

2.19.2

Bug Description

kiro-cli chat --resume-id <ID> silently fails to resume sessions created on the v2 or v3 agent engine. Instead of restoring the conversation, it starts a brand-new session with a new ID, and reports no error or warning. Sessions created on the default (classic) path resume correctly, so the defect is specific to v2/v3 session lookup.

Feature used: headless CLI (kiro-cli chat --no-interactive) with --output-format stream-json, which was added in 2.19.2 (requested in #9066).

Intended task: use kiro-cli as a conversation engine from an orchestration tool, running a multi-turn flow (plan → implement → review → fix) as a series of separate processes. Each step captures its session ID from the stream-json output and passes it to --resume-id on the next step so context carries forward.

This is currently impossible, because the two halves are mutually exclusive:

  • --output-format stream-json — the only machine-readable way to obtain a run's session ID — requires --agent-engine v2 or v3. It refuses to run on v1.
  • --resume-id only resolves sessions in the classic (v1) store.

So the only path that returns a usable session ID produces IDs that cannot be resumed, and the only path whose IDs can be resumed cannot tell you what its ID is.

Impact on workflow: the silence is the damaging part. A multi-turn pipeline exits 0 on every step and produces plausible-looking output, while in reality every turn starts from an empty context. There is nothing to detect — no error, no warning, no non-zero exit. The only way to notice is to inspect the emitted sessionId and observe that it differs from the one you passed in, or to catch the agent contradicting earlier turns.

Steps to Reproduce

Run each turn in a clean, empty directory. This matters: if the reproduction script is on disk in the working directory, the agent may read the passphrase out of the file and appear to "remember" it, masking the bug.

  1. Create an empty working directory and define two prompts:

    WORK=/tmp/clean-9066
    mkdir -p "$WORK" && cd "$WORK"
    P1="The passphrase is BLUE-SEVEN. Remember it. Reply OK only."
    P2="What is the passphrase? Answer in one line. Do not use any tools."
  2. Turn 1 — start a headless conversation on the v2 engine and capture its session ID from the stream-json output:

    SID=$(kiro-cli chat --agent-engine v2 --output-format stream-json --trust-tools= "$P1" \
      | jq -r 'select(.type=="runFinished").data.sessionId')
    echo "$SID"
  3. Turn 2 — resume that session and ask for the passphrase back:

    kiro-cli chat --agent-engine v2 --resume-id "$SID" --output-format stream-json --trust-tools= "$P2" \
      | jq -r 'select(.type=="runFinished").data | .sessionId, .finalText'
  4. Observe that the sessionId printed in step 3 is different from $SID, and that finalText shows the agent has no knowledge of the passphrase. No error, warning, or non-zero exit accompanies this.

  5. Repeat steps 2–4 with --agent-engine v3. Same failure (IDs are sess_-prefixed).

  6. Control case — the default engine resumes correctly. Note this path cannot use stream-json, so the ID has to be scraped from --list-sessions:

    kiro-cli chat --trust-tools= "$P1"
    CSID=$(kiro-cli chat --list-sessions -f json | jq -r '.[0].sessions[0].sessionId')
    kiro-cli chat --wrap never --resume-id "$CSID" --trust-tools= \
      "Repeat the passphrase exactly. One line only."

    This answers BLUE-SEVEN.

  7. Confirm that stream-json cannot be used on the engine that does resume:

    kiro-cli chat --agent-engine v1 --output-format stream-json "hi"
    

Expected Behavior

Two separate expectations, in priority order.

  1. --resume-id should resolve session IDs regardless of which store holds them. Passing an ID obtained from runFinished.sessionId back into --resume-id should restore that conversation and continue it — the same behavior the classic path already has. In the reproduction above, step 3 should print the same sessionId it was given and finalText: BLUE-SEVEN.

    If cross-store lookup is undesirable, then at minimum expose a selector for it. --delete-session already accepts --session-source <v1|v2>, but that flag is hard-wired to --delete-session and cannot be combined with --resume-id (see Additional Context), so a caller has no way to say which store to search.

  2. An unresolvable --resume-id must fail loudly. Silently substituting a new session is the worst possible outcome for automation: the pipeline reports success while every turn runs with no context. Expected instead:

    • a runError event on the stream-json stream, e.g.
      {"type":"runError","data":{"stage":"session","message":"session <ID> not found"}}
    • a non-zero exit code

    This is how the engine/format mismatch is already handled, and it works well:

    {"type":"runError","data":{"sessionId":null,"stage":"engine","message":"--output-format stream-json is not supported on the v1 engine. Pass --agent-engine v2 (or v3)."}}
    error: --output-format stream-json is not supported on the v1 engine. Pass --agent-engine v2 (or v3).
    

    Session-not-found should behave the same way.

Note that even if (1) is deferred, fixing (2) alone would make this survivable — the failure would at least be detectable by the calling tool.

Conversation ID

Not applicable — this is a CLI issue, not raised from the IDE, so no conversation ID was auto-populated. The relevant identifiers are the session IDs from the reproduction run:

Engine Turn 1 session ID (passed to --resume-id) Turn 2 session ID (actually used)
v2 8255c6fc-4bd8-460d-9e7c-794500e0805f 32a6525a-2c18-467d-8319-e3f13620d95d
v3 sess_12cdc4b5-166e-4222-8b4c-0a08b8ca4e64 sess_8a87a715-6bd6-48d8-b232-d66ddcc06539
classic (control, works) 7b7d00f2-2195-498c-a590-0ad27fc0c674 same ID — resumed correctly

Additional Context

Actual output from the reproduction

### kiro-cli 2.19.2  (Ubuntu 24.04.3 LTS on WSL2)

===== engine = v2 =====
turn 1:
  sessionId : 8255c6fc-4bd8-460d-9e7c-794500e0805f
  finalText : OK
turn 2  (--resume-id 8255c6fc-4bd8-460d-9e7c-794500e0805f):
  sessionId : 32a6525a-2c18-467d-8319-e3f13620d95d
  finalText : I don't have a passphrase in my context — nothing in this conversation or my instructions contains one.

===== engine = v3 =====
turn 1:
  sessionId : sess_12cdc4b5-166e-4222-8b4c-0a08b8ca4e64
  finalText : OK
turn 2  (--resume-id sess_12cdc4b5-166e-4222-8b4c-0a08b8ca4e64):
  sessionId : sess_8a87a715-6bd6-48d8-b232-d66ddcc06539
  finalText : I'm not sure — there's no context indicating what "passphrase" refers to. Which passphrase are you asking about?

===== control: default engine, no stream-json =====
  sessionId (via --list-sessions): 7b7d00f2-2195-498c-a590-0ad27fc0c674
turn 2  (--resume-id 7b7d00f2-...):
> BLUE-SEVEN

===== v1 engine + stream-json =====
{"type":"runError","data":{"sessionId":null,"stage":"engine","message":"--output-format stream-json is not supported on the v1 engine. Pass --agent-engine v2 (or v3)."}}
error: --output-format stream-json is not supported on the v1 engine. Pass --agent-engine v2 (or v3).

The session data is written correctly — only the lookup fails

--list-sessions -f json after the v2 run shows two independent sessions rather than one extended session, and turn 1's session is fully persisted:

{"sessionId": "32a6525a-2c18-467d-8319-e3f13620d95d", "source": "v2", "messageCount": 2, "title": "What is the passphrase? Answer in one line. Do not use any tools."}
{"sessionId": "8255c6fc-4bd8-460d-9e7c-794500e0805f", "source": "v2", "messageCount": 2, "title": "The passphrase is BLUE-SEVEN. Remember it. Reply OK only."}

By contrast, the classic control session was extended in place — messageCount went 2 → 4 → 6 over three turns on the same ID, with no duplicate session created:

{"sessionId": "7b7d00f2-2195-498c-a590-0ad27fc0c674", "source": "classic", "messageCount": 6, "title": "The passphrase is BLUE-SEVEN. Remember it. Reply OK only."}

Summary of the catch-22

Path source in --list-sessions Can emit its session ID? --resume-id works?
default engine, no stream-json classic No Yes
--agent-engine v2 + stream-json v2 Yes No
--agent-engine v3 + stream-json v3 Yes No

Suspected cause

A session-store resolution gap rather than a resume bug — --resume-id appears to search only the classic/v1 store while the v2/v3 engines write to their own stores. Supporting evidence:

Also worth noting that --session-source only offers v1 and v2 — there is no v3 value — while --list-sessions reports source: "v3" for sessions created with --agent-engine v3. The store enumeration appears to have fallen behind the engine list.

Workarounds attempted

1. Point --resume-id at the right store with --session-source. Not possible — the flag is hard-wired to --delete-session:

$ kiro-cli chat --agent-engine v2 --session-source v2 \
    --resume-id 8255c6fc-4bd8-460d-9e7c-794500e0805f \
    --output-format stream-json --trust-tools= "test"
error: the following required arguments were not provided:
  --delete-session <SESSION_ID>

Usage: kiro-cli-chat chat --delete-session <SESSION_ID> --agent-engine <ENGINE> --session-source <v1|v2> --resume-id <SESSION_ID> --output-format <OUTPUT_FORMAT> --trust-tools <TOOL_NAMES> <INPUT>

2. Replay the full conversation history in the prompt on every invocation, keeping all state on the caller's side. This works, but costs tokens linearly in turn count and forfeits the benefit that #9066 was asking for. It is what I am doing now.

Related

Environment notes

  • kiro-cli 2.19.2, confirmed latest via kiro-cli update ("2.19.2 is the latest version").
  • kiro-cli chat --help documents --agent-engine as defaulting to v2, but on this install --output-format stream-json fails with the v1-engine error unless --agent-engine v2 is passed explicitly, so the effective default appears to be v1. Minor, but it makes the feature look broken on first use.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions