anthropics / anthropics/claude-agent-sdk-typescript

Non-interactive unsupported slash commands return non-resumable session_id

未关闭
#302 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
bug
主要语言
Shell
星标
1.8k
派生
226
PR 合并指标
30 天内没有已合并 PR

描述

## Summary

When running Claude Agent SDK / Claude Code in non-interactive mode, an unsupported built-in slash command such as `/status` emits a `system/init` message with a `session_id`, then returns a successful synthetic result:

```text
/status isn't available in this environment.
```

However, no transcript JSONL file is created for that `session_id`. If a client stores the emitted `session_id` and later tries to resume it, resume fails with:

```text
No conversation found with session ID:
```

This is surprising for SDK consumers because `system/init.session_id` and `result.session_id` look like a valid resumable session.

## Environment

- `@anthropic-ai/claude-agent-sdk`: observed with `0.2.31`
- Claude Code executable: `2.1.119`
- Platform: macOS arm64
- Mode: non-interactive / `--print --output-format stream-json`
- `CLAUDE_CONFIG_DIR`: temporary directory for reproduction

## Minimal reproduction

This can be reproduced without any external wrapper:

```bash
tmp="$(mktemp -d)"
workdir="/tmp/claude-sdk-session-repro"
mkdir -p "$workdir"

cd "$workdir"

CLAUDE_CONFIG_DIR="$tmp" \
AGENTRIX_CLAUDE_HOME="$tmp" \
claude --print --verbose --output-format stream-json "/status" \
> "$tmp/first.jsonl" 2> "$tmp/first.err"

session_id="$(node -e '
const fs = require("fs");
const first = fs.readFileSync(process.argv[1], "utf8").trim().split(/\n/)[0];
console.log(JSON.parse(first).session_id);
' "$tmp/first.jsonl")"

echo "session_id=$session_id"

find "$tmp/projects" -name "${session_id}.jsonl" -print 2>/dev/null

CLAUDE_CONFIG_DIR="$tmp" \
AGENTRIX_CLAUDE_HOME="$tmp" \
claude --print --verbose --output-format stream-json --resume "$session_id" "hello" \
> "$tmp/resume.jsonl" 2> "$tmp/resume.err"

cat "$tmp/resume.jsonl"
cat "$tmp/resume.err"
```

## Actual behavior

The first command emits a valid-looking session id:

```json
{"type":"system","subtype":"init","session_id":"1f692c5e-512f-40af-8739-7e7e0eea722f", "...":"..."}
{"type":"assistant","message":{"model":"","content":[{"type":"text","text":"/status isn't available in this environment."}]},"session_id":"1f692c5e-512f-40af-8739-7e7e0eea722f", "...":"..."}
{"type":"result","subtype":"success","is_error":false,"result":"/status isn't available in this environment.","session_id":"1f692c5e-512f-40af-8739-7e7e0eea722f", "...":"..."}
```

But no transcript file exists for that session id under `CLAUDE_CONFIG_DIR/projects/**`.

A later resume fails:

```json
{
"type": "result",
"subtype": "error_during_execution",
"is_error": true,
"errors": [
"No conversation found with session ID: 1f692c5e-512f-40af-8739-7e7e0eea722f"
]
}
```

stderr also prints:

```text
No conversation found with session ID: 1f692c5e-512f-40af-8739-7e7e0eea722f
```

## Expected behavior

One of the following would be much easier for SDK consumers to handle:

1. Do not emit a resumable `session_id` for synthetic unsupported slash-command results that are not persisted; or
2. Persist a minimal transcript for the emitted `session_id`, so `--resume ` succeeds; or
3. Mark the result/init metadata to indicate the session is not resumable.

## Why this matters

SDK clients commonly treat `system/init.session_id` or `result.session_id` as the authoritative id to store for future resumes. In this case, the SDK/CLI reports success and provides a session id, but the id cannot be resumed.

This can happen in real integrations when the first user message is a built-in slash command that is filtered out of headless mode, e.g. `/status` or similar commands. The client stores the session id from `system/init`, the process exits normally, and the next user message fails immediately on resume.

## Additional notes

The emitted response appears to be synthetic:

- assistant `message.model` is `""`
- token usage is all zero
- `duration_api_ms` is zero
- result text is `/ isn't available in this environment.`

That suggests this path returns before a normal model turn and before a transcript is materialized, while still exposing a `session_id` through the SDK stream.

贡献指南

这个仓库没有索引到贡献指南

评估

这个 Issue 还没有评估数据。

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。