@tanstack/ai-claude-code 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/esm/adapters/policy-map.d.ts +8 -0
- package/dist/esm/adapters/policy-map.js +51 -0
- package/dist/esm/adapters/policy-map.js.map +1 -0
- package/dist/esm/adapters/projection.d.ts +14 -0
- package/dist/esm/adapters/projection.js +101 -0
- package/dist/esm/adapters/projection.js.map +1 -0
- package/dist/esm/adapters/text.d.ts +75 -0
- package/dist/esm/adapters/text.js +306 -0
- package/dist/esm/adapters/text.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/messages/prompt.d.ts +17 -0
- package/dist/esm/messages/prompt.js +37 -0
- package/dist/esm/messages/prompt.js.map +1 -0
- package/dist/esm/model-meta.d.ts +10 -0
- package/dist/esm/model-meta.js +14 -0
- package/dist/esm/model-meta.js.map +1 -0
- package/dist/esm/provider-options.d.ts +30 -0
- package/dist/esm/stream/sdk-types.d.ts +124 -0
- package/dist/esm/stream/translate.d.ts +44 -0
- package/dist/esm/stream/translate.js +368 -0
- package/dist/esm/stream/translate.js.map +1 -0
- package/package.json +62 -0
- package/src/adapters/policy-map.ts +83 -0
- package/src/adapters/projection.ts +226 -0
- package/src/adapters/text.ts +539 -0
- package/src/index.ts +21 -0
- package/src/messages/prompt.ts +68 -0
- package/src/model-meta.ts +21 -0
- package/src/provider-options.ts +30 -0
- package/src/stream/sdk-types.ts +135 -0
- package/src/stream/translate.ts +483 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import { EventType, normalizeSystemPrompts } from '@tanstack/ai'\nimport { toRunErrorRawEvent } from '@tanstack/ai/adapter-internals'\nimport { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport {\n SandboxCapability,\n approvalId,\n buildApprovalRequestedEvent,\n createBridgeEventChannel,\n getSandbox,\n getSandboxPolicy,\n getToolBridgeProvisioner,\n getWorkspaceProjection,\n mergeChunkStreams,\n nodeHttpBridgeProvisioner,\n resolveApproval,\n spawnNdjson,\n} from '@tanstack/ai-sandbox'\nimport { buildPrompt } from '../messages/prompt'\nimport { translateSdkStream } from '../stream/translate'\nimport { mapPolicyToClaudeFlags } from './policy-map'\nimport { projectClaudeWorkspace } from './projection'\nimport type { ClaudePolicyFlags } from './policy-map'\nimport type {\n BridgeEventChannel,\n HostToolBridge,\n PermissionToolResult,\n SandboxHandle,\n SandboxPolicy,\n} from '@tanstack/ai-sandbox'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type {\n DefaultMessageMetadataByModality,\n Modality,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\nimport type { ClaudeCodeModel } from '../model-meta'\nimport type { ClaudeCodeTextProviderOptions } from '../provider-options'\nimport type { AgentSdkMessage } from '../stream/sdk-types'\n\nexport type ClaudeCodePermissionMode =\n | 'default'\n | 'acceptEdits'\n | 'bypassPermissions'\n | 'plan'\n\nconst DEFAULT_WORKDIR = '/workspace'\n\nexport interface ClaudeCodeTextConfig {\n /**\n * Working directory inside the sandbox where `claude` runs. Defaults to\n * `/workspace` (the conventional sandbox workspace root).\n */\n cwd?: string\n /**\n * Claude Code permission mode passed via `--permission-mode`. Defaults to\n * `'bypassPermissions'` — a sandbox is isolated, so the agent is allowed to\n * edit files and run commands without prompting. Tighten via `defineSandboxPolicy`\n * / this option for less autonomy.\n */\n permissionMode?: ClaudeCodePermissionMode\n /** Built-in tools the harness may use (`--allowedTools`). */\n allowedTools?: Array<string>\n /** Built-in tools removed from the harness (`--disallowedTools`). */\n disallowedTools?: Array<string>\n /** Extra directories the agent may access (`--add-dir`). */\n addDirs?: Array<string>\n /** Maximum harness-internal turns (`--max-turns`). */\n maxTurns?: number\n /**\n * How `systemPrompts` from `chat()` are applied:\n * - `'append'` (default): `--append-system-prompt` on top of the preset.\n * - `'replace'`: `--system-prompt` as the entire system prompt.\n */\n systemPromptMode?: 'append' | 'replace'\n /** Path/name of the claude executable inside the sandbox. Defaults to `claude`. */\n claudeExecutable?: string\n /** Emit token-level deltas via `--include-partial-messages` (default true). */\n streamPartials?: boolean\n /** Extra environment variables for the claude process inside the sandbox. */\n env?: Record<string, string>\n /** Emit a `file.changed` CUSTOM event with the git diff after the run (default true). */\n emitDiff?: boolean\n}\n\n/** POSIX single-quote escape for embedding values in the `claude …` command. */\nfunction q(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\n/** Format a host tool-bridge as claude's `--mcp-config` JSON. */\nfunction bridgeToMcpConfig(bridge: HostToolBridge): string {\n return JSON.stringify({\n mcpServers: {\n [bridge.name]: {\n type: 'http',\n url: bridge.url,\n headers: { Authorization: `Bearer ${bridge.token}` },\n },\n },\n })\n}\n\nexport class ClaudeCodeTextAdapter<\n TModel extends ClaudeCodeModel,\n> extends BaseTextAdapter<\n TModel,\n ClaudeCodeTextProviderOptions,\n ReadonlyArray<Modality> & readonly ['text'],\n DefaultMessageMetadataByModality,\n ReadonlyArray<string>,\n unknown,\n never\n> {\n readonly name = 'claude-code' as const\n\n // Harness adapter: requires a sandbox to run the agent CLI inside.\n override readonly requires = [SandboxCapability] as const\n\n private readonly adapterConfig: ClaudeCodeTextConfig\n\n constructor(config: ClaudeCodeTextConfig, model: TModel) {\n super({}, model)\n this.adapterConfig = config\n }\n\n private sandboxFrom(\n options: TextOptions<ClaudeCodeTextProviderOptions>,\n ): SandboxHandle {\n const ctx = options.capabilities\n if (!ctx) {\n throw new Error(\n 'Adapter \"claude-code\" requires a sandbox. Add withSandbox(defineSandbox({ ... })) ' +\n 'to chat() middleware (e.g. with the local-process or docker provider).',\n )\n }\n return getSandbox(ctx)\n }\n\n private workdir(options: TextOptions<ClaudeCodeTextProviderOptions>): string {\n return (\n options.modelOptions?.cwd ?? this.adapterConfig.cwd ?? DEFAULT_WORKDIR\n )\n }\n\n /** Build the `claude` command line (prompt goes via stdin, not argv). */\n private buildCommand(\n options: TextOptions<ClaudeCodeTextProviderOptions>,\n resume: string | undefined,\n policyFlags: ClaudePolicyFlags,\n mcpConfigPath: string | undefined,\n permissionPromptTool: string | undefined,\n ): string {\n const config = this.adapterConfig\n const modelOptions = options.modelOptions\n const exe = config.claudeExecutable ?? 'claude'\n\n const args: Array<string> = [\n '-p',\n '--output-format',\n 'stream-json',\n '--verbose',\n '--model',\n q(this.model),\n ]\n\n if (config.streamPartials !== false) args.push('--include-partial-messages')\n if (resume !== undefined) args.push('--resume', q(resume))\n\n // Precedence: per-call modelOptions > adapter config > policy > sandbox default.\n const permissionMode =\n modelOptions?.permissionMode ??\n config.permissionMode ??\n policyFlags.permissionMode ??\n 'bypassPermissions'\n args.push('--permission-mode', q(permissionMode))\n\n const maxTurns = modelOptions?.maxTurns ?? config.maxTurns\n if (maxTurns !== undefined) args.push('--max-turns', String(maxTurns))\n\n for (const dir of config.addDirs ?? []) args.push('--add-dir', q(dir))\n\n const allowedTools = [\n ...(modelOptions?.allowedTools ?? config.allowedTools ?? []),\n ...policyFlags.allowedTools,\n ]\n if (allowedTools.length > 0) {\n args.push('--allowedTools', q([...new Set(allowedTools)].join(',')))\n }\n const disallowedTools = [\n ...(modelOptions?.disallowedTools ?? config.disallowedTools ?? []),\n ...policyFlags.disallowedTools,\n ]\n if (disallowedTools.length > 0) {\n args.push('--disallowedTools', q([...new Set(disallowedTools)].join(',')))\n }\n\n const systemPrompts = normalizeSystemPrompts(options.systemPrompts)\n .map((prompt) => prompt.content)\n .filter((content) => content.trim() !== '')\n if (systemPrompts.length > 0) {\n const joined = systemPrompts.join('\\n\\n')\n const flag =\n config.systemPromptMode === 'replace'\n ? '--system-prompt'\n : '--append-system-prompt'\n args.push(flag, q(joined))\n }\n\n if (mcpConfigPath !== undefined) args.push('--mcp-config', q(mcpConfigPath))\n if (permissionPromptTool !== undefined) {\n args.push('--permission-prompt-tool', q(permissionPromptTool))\n }\n\n return `${exe} ${args.join(' ')}`\n }\n\n /**\n * Build the permission-prompt resolver the host MCP bridge exposes to claude\n * (`--permission-prompt-tool`). Maps claude's permission request onto the\n * sandbox policy + client approvals; on an `ask` action with no decision yet,\n * records an approval-requested event and denies (the client re-runs to grant).\n */\n private buildPermissionResolver(\n policy: SandboxPolicy | undefined,\n approvals: ReadonlyMap<string, boolean> | undefined,\n scripts: Record<string, string> | undefined,\n sink: Array<StreamChunk>,\n threadId: string,\n runId: string,\n ): (input: { tool_name?: string; input?: unknown }) => PermissionToolResult {\n const writeTools = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit'])\n const networkTools = new Set(['WebFetch', 'WebSearch'])\n return (request) => {\n const toolName = request.tool_name ?? 'tool'\n const cmdInput = request.input\n const command =\n toolName === 'Bash' &&\n cmdInput !== null &&\n typeof cmdInput === 'object' &&\n 'command' in cmdInput &&\n typeof (cmdInput as { command?: unknown }).command === 'string'\n ? (cmdInput as { command: string }).command\n : undefined\n const capability = writeTools.has(toolName)\n ? 'fileWrite'\n : networkTools.has(toolName)\n ? 'network'\n : undefined\n const id = approvalId({\n provider: 'claude-code',\n kind: command !== undefined ? 'command' : (capability ?? 'tool'),\n target: command ?? toolName,\n })\n const outcome = resolveApproval({\n policy,\n approvals,\n id,\n scripts,\n ...(command !== undefined ? { command } : {}),\n ...(capability !== undefined ? { capability } : {}),\n })\n if (outcome.needsApproval) {\n sink.push(\n buildApprovalRequestedEvent({\n approvalId: id,\n title: `Approve ${toolName}${command !== undefined ? `: ${command}` : ''}`,\n threadId,\n runId,\n detail: { provider: 'claude-code', toolName },\n }),\n )\n return {\n behavior: 'deny',\n message:\n 'Awaiting client approval. Approve in the UI and re-run to continue.',\n }\n }\n return outcome.decision === 'allow'\n ? { behavior: 'allow' }\n : { behavior: 'deny', message: 'Denied by sandbox policy.' }\n }\n }\n\n async *chatStream(\n options: TextOptions<ClaudeCodeTextProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const { logger } = options\n let bridge: HostToolBridge | undefined\n let channel: BridgeEventChannel | undefined\n const approvalRequests: Array<StreamChunk> = []\n // Temp files written for the run (bridge MCP config, redirected prompt) that\n // carry the bearer token / prompt; removed in `finally` so they don't linger\n // in the sandbox after the run.\n let cleanupSandbox: SandboxHandle | undefined\n const tempFiles: Array<string> = []\n try {\n const sandbox = this.sandboxFrom(options)\n cleanupSandbox = sandbox\n const cwd = this.workdir(options)\n const runId = options.runId ?? this.generateId()\n const threadId = options.threadId ?? this.generateId()\n // Surfaces custom events from bridged tools (e.g. code mode console logs)\n // on this run's live output stream.\n channel = createBridgeEventChannel({ model: this.model, threadId, runId })\n\n // Idempotently project workspace skills/plugins/MCP into the sandbox in\n // claude's native format (guarded by the projection marker file).\n const projection = options.capabilities\n ? getWorkspaceProjection(options.capabilities, { optional: true })\n : undefined\n if (projection) await projectClaudeWorkspace(sandbox, projection)\n\n const policy = options.capabilities\n ? getSandboxPolicy(options.capabilities, { optional: true })\n : undefined\n\n // A permission-prompt tool gates the agent's native tools when a policy\n // can `ask`/`deny` (interactive approvals).\n const permission =\n policy !== undefined\n ? {\n toolName: 'approval_prompt',\n resolve: this.buildPermissionResolver(\n policy,\n options.approvals,\n projection?.scripts,\n approvalRequests,\n threadId,\n runId,\n ),\n }\n : undefined\n\n // Bridge chat()-provided server tools (and/or the permission tool) into\n // the sandbox over MCP.\n const hasTools = options.tools !== undefined && options.tools.length > 0\n if (hasTools || permission !== undefined) {\n const provisioner =\n (options.capabilities\n ? getToolBridgeProvisioner(options.capabilities, { optional: true })\n : undefined) ?? nodeHttpBridgeProvisioner\n bridge = await provisioner.provision(options.tools ?? [], {\n provider: sandbox.provider,\n context: options.context,\n emitCustomEvent: channel.emitCustomEvent,\n ...(permission !== undefined ? { permission } : {}),\n ...(options.abortController?.signal\n ? { signal: options.abortController.signal }\n : {}),\n })\n }\n\n const { prompt, resume } = buildPrompt(\n options.messages,\n options.modelOptions?.sessionId,\n )\n // The bridge MCP config carries the per-run bearer token. Write it to a\n // file and pass claude the PATH, so the token never appears in argv (where\n // any process in the sandbox could read it via `ps` / `/proc/<pid>/cmdline`).\n let mcpConfigArg: string | undefined\n if (bridge) {\n // Pass claude a path RELATIVE to its cwd (the real workdir the handle\n // runs the process in). An absolute VIRTUAL path like `/workspace/…` is\n // wrong wherever claude runs outside a sandbox that literally uses\n // `/workspace` — e.g. local-process on Windows, where git-bash resolves\n // `/workspace` to `C:\\Program Files\\Git\\workspace` and the file is \"not\n // found\". The bare filename resolves correctly on every provider.\n const mcpConfigFile = `.tanstack-mcp-bridge-${runId}.json`\n const mcpConfigPath = `${cwd}/${mcpConfigFile}`\n await sandbox.fs.write(mcpConfigPath, bridgeToMcpConfig(bridge))\n tempFiles.push(mcpConfigPath)\n mcpConfigArg = mcpConfigFile\n }\n const command = this.buildCommand(\n options,\n resume,\n mapPolicyToClaudeFlags(policy),\n mcpConfigArg,\n bridge && permission\n ? `mcp__${bridge.name}__${permission.toolName}`\n : undefined,\n )\n\n // Deliver the prompt. The default feeds it over stdin (keeps it out of\n // argv). Providers without a writable host→process stdin (e.g. Cloudflare)\n // can't accept that write, so write the prompt to a file and redirect the\n // CLI's stdin from it in-shell (`claude -p … < file`) — still out of argv.\n let runCommand = command\n let stdinInput: string | undefined = prompt\n if (sandbox.capabilities.writableStdin === false) {\n const promptPath = `/tmp/tanstack-claude-prompt-${runId}`\n await sandbox.fs.write(promptPath, prompt)\n tempFiles.push(promptPath)\n runCommand = `${command} < ${q(promptPath)}`\n stdinInput = undefined\n }\n\n logger.request(\n `activity=chat provider=claude-code model=${this.model} sandbox=${sandbox.provider} messages=${options.messages.length} resume=${resume ?? 'none'}`,\n { provider: 'claude-code', model: this.model },\n )\n\n const rawEvents = spawnNdjson(sandbox, runCommand, {\n cwd,\n ...(stdinInput !== undefined ? { input: stdinInput } : {}),\n // claude maps `bypassPermissions` to `--dangerously-skip-permissions`,\n // which it refuses to run as root. Sandbox containers routinely run as\n // root (Docker / Cloudflare), so set `IS_SANDBOX=1` — claude's\n // documented escape hatch for skip-permissions in an isolated\n // environment — merged over the sandbox env (a caller-provided value\n // wins). Safe to set unconditionally; it is a no-op for stricter modes.\n env: { IS_SANDBOX: '1', ...this.adapterConfig.env },\n ...(options.abortController?.signal\n ? { signal: options.abortController.signal }\n : options.request?.signal\n ? { signal: options.request.signal }\n : {}),\n onNonJsonLine: (line) =>\n logger.provider(`provider=claude-code non-json line: ${line}`, {\n chunk: line,\n }),\n })\n\n async function* asMessages(): AsyncIterable<AgentSdkMessage> {\n for await (const event of rawEvents) yield event as AgentSdkMessage\n }\n\n yield* mergeChunkStreams(\n translateSdkStream(asMessages(), {\n model: this.model,\n runId,\n threadId,\n ...(options.parentRunId !== undefined && {\n parentRunId: options.parentRunId,\n }),\n genId: () => this.generateId(),\n onSdkMessage: (message) =>\n logger.provider(`provider=claude-code type=${message.type}`, {\n chunk: message,\n }),\n }),\n channel.stream,\n )\n\n // Surface the working-tree diff so UIs can render what the agent changed.\n if (this.adapterConfig.emitDiff !== false) {\n try {\n const diff = await sandbox.process.exec(`git -C ${q(cwd)} diff`, {\n cwd,\n })\n if (diff.exitCode === 0 && diff.stdout.trim() !== '') {\n yield {\n type: EventType.CUSTOM,\n name: 'file.changed',\n value: { path: '.', diff: diff.stdout },\n timestamp: Date.now(),\n threadId,\n runId,\n }\n }\n } catch {\n // not a git repo / git unavailable — skip the diff event\n }\n }\n\n // Surface any pending approval requests (policy `ask` actions awaiting a\n // client decision); the client approves and re-runs to continue.\n for (const event of approvalRequests) yield event\n } catch (error: unknown) {\n const err = error as Error & { code?: string }\n const rawEvent = toRunErrorRawEvent(error)\n logger.errors('claude-code.chatStream fatal', {\n error,\n source: 'claude-code.chatStream',\n })\n yield {\n type: EventType.RUN_ERROR,\n model: options.model,\n timestamp: Date.now(),\n message: err.message || 'Unknown error occurred',\n ...(err.code !== undefined && { code: err.code }),\n ...(rawEvent !== undefined && { rawEvent }),\n error: {\n message: err.message || 'Unknown error occurred',\n ...(err.code !== undefined && { code: err.code }),\n },\n }\n } finally {\n channel?.close()\n if (bridge) await bridge.close()\n // Remove the per-run token/prompt files. Best-effort: a cleanup failure\n // must not mask the run's own outcome.\n if (cleanupSandbox) {\n for (const path of tempFiles) {\n try {\n await cleanupSandbox.fs.remove(path)\n } catch {\n // file already gone / sandbox torn down — nothing to clean up\n }\n }\n }\n }\n }\n\n structuredOutput(\n _options: StructuredOutputOptions<ClaudeCodeTextProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n return Promise.reject(\n new Error(\n 'Structured output is not yet supported by the in-sandbox Claude Code adapter. ' +\n 'Use a model adapter (e.g. anthropic) for structured output, or omit outputSchema.',\n ),\n )\n }\n}\n\n/**\n * Creates a Claude Code harness adapter that runs **inside a sandbox**.\n *\n * Unlike HTTP provider adapters, this is a *harness* adapter: it spawns the\n * `claude` CLI inside the sandbox provided by `withSandbox(...)` (the adapter\n * declares `requires: [SandboxCapability]`), streams its `stream-json` stdout\n * back as AG-UI events, and lets Claude Code run its own agent loop and native\n * tools (Bash, file edits, search, …) against the sandbox workspace. The\n * sandbox image must provide the `claude` executable and `ANTHROPIC_API_KEY`\n * in its environment (e.g. via `workspace.secrets`). The session id is\n * surfaced via a CUSTOM `claude-code.session-id` event so follow-up calls can\n * resume through `modelOptions.sessionId`.\n */\nexport function claudeCodeText<TModel extends ClaudeCodeModel>(\n model: TModel,\n config: ClaudeCodeTextConfig = {},\n): ClaudeCodeTextAdapter<TModel> {\n return new ClaudeCodeTextAdapter(config, model)\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ClaudeCodeTextAdapter, claudeCodeText } from './adapters/text.js';
|
|
2
|
+
export type { ClaudeCodeTextConfig, ClaudeCodePermissionMode, } from './adapters/text.js';
|
|
3
|
+
export type { ClaudeCodeTextProviderOptions } from './provider-options.js';
|
|
4
|
+
export { CLAUDE_CODE_MODELS } from './model-meta.js';
|
|
5
|
+
export type { ClaudeCodeModel, KnownClaudeCodeModel } from './model-meta.js';
|
|
6
|
+
export { SESSION_ID_EVENT, BRIDGED_MCP_SERVER_NAME, translateSdkStream, stripMcpPrefix, } from './stream/translate.js';
|
|
7
|
+
export type { ClaudeCodeProviderUsageDetails, TranslateContext, } from './stream/translate.js';
|
|
8
|
+
export type { AgentSdkMessage } from './stream/sdk-types.js';
|
|
9
|
+
export { buildPrompt } from './messages/prompt.js';
|
|
10
|
+
export type { BuiltPrompt } from './messages/prompt.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ClaudeCodeTextAdapter, claudeCodeText } from "./adapters/text.js";
|
|
2
|
+
import { CLAUDE_CODE_MODELS } from "./model-meta.js";
|
|
3
|
+
import { BRIDGED_MCP_SERVER_NAME, SESSION_ID_EVENT, stripMcpPrefix, translateSdkStream } from "./stream/translate.js";
|
|
4
|
+
import { buildPrompt } from "./messages/prompt.js";
|
|
5
|
+
export {
|
|
6
|
+
BRIDGED_MCP_SERVER_NAME,
|
|
7
|
+
CLAUDE_CODE_MODELS,
|
|
8
|
+
ClaudeCodeTextAdapter,
|
|
9
|
+
SESSION_ID_EVENT,
|
|
10
|
+
buildPrompt,
|
|
11
|
+
claudeCodeText,
|
|
12
|
+
stripMcpPrefix,
|
|
13
|
+
translateSdkStream
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ModelMessage } from '@tanstack/ai';
|
|
2
|
+
export interface BuiltPrompt {
|
|
3
|
+
prompt: string;
|
|
4
|
+
/** Claude Code session id to resume, when the caller threaded one through. */
|
|
5
|
+
resume?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Convert TanStack chat history into the Agent SDK's `{ prompt, resume }`
|
|
9
|
+
* inputs.
|
|
10
|
+
*
|
|
11
|
+
* With a `sessionId`, the harness already holds the conversation context, so
|
|
12
|
+
* only the trailing user message is sent and the session is resumed. Without
|
|
13
|
+
* one, prior turns are flattened into a plain-text transcript preamble (tool
|
|
14
|
+
* messages and tool-call-only assistant turns are harness-internal noise and
|
|
15
|
+
* are skipped; prompts are text-only in v1).
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildPrompt(messages: Array<ModelMessage>, sessionId: string | undefined): BuiltPrompt;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
function extractText(content) {
|
|
2
|
+
if (content === null) return "";
|
|
3
|
+
if (typeof content === "string") return content;
|
|
4
|
+
return content.map(
|
|
5
|
+
(part) => part.type === "text" && typeof part.content === "string" ? part.content : ""
|
|
6
|
+
).join("");
|
|
7
|
+
}
|
|
8
|
+
function buildPrompt(messages, sessionId) {
|
|
9
|
+
const lastMessage = messages.at(-1);
|
|
10
|
+
const lastUserText = lastMessage?.role === "user" ? extractText(lastMessage.content).trim() : "";
|
|
11
|
+
if (!lastUserText) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
"Claude Code adapter requires a trailing user message with text content."
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
if (sessionId !== void 0) {
|
|
17
|
+
return { prompt: lastUserText, resume: sessionId };
|
|
18
|
+
}
|
|
19
|
+
const priorTurns = messages.slice(0, -1).filter(
|
|
20
|
+
(message) => (message.role === "user" || message.role === "assistant") && extractText(message.content).trim() !== ""
|
|
21
|
+
).map(
|
|
22
|
+
(message) => `${message.role === "user" ? "User" : "Assistant"}: ${extractText(message.content).trim()}`
|
|
23
|
+
);
|
|
24
|
+
if (priorTurns.length === 0) {
|
|
25
|
+
return { prompt: lastUserText };
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
prompt: `Previous conversation:
|
|
29
|
+
${priorTurns.join("\n")}
|
|
30
|
+
|
|
31
|
+
${lastUserText}`
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
buildPrompt
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sources":["../../../src/messages/prompt.ts"],"sourcesContent":["import type { ModelMessage } from '@tanstack/ai'\n\nexport interface BuiltPrompt {\n prompt: string\n /** Claude Code session id to resume, when the caller threaded one through. */\n resume?: string\n}\n\nfunction extractText(content: ModelMessage['content']): string {\n if (content === null) return ''\n if (typeof content === 'string') return content\n return content\n .map((part) =>\n part.type === 'text' && typeof part.content === 'string'\n ? part.content\n : '',\n )\n .join('')\n}\n\n/**\n * Convert TanStack chat history into the Agent SDK's `{ prompt, resume }`\n * inputs.\n *\n * With a `sessionId`, the harness already holds the conversation context, so\n * only the trailing user message is sent and the session is resumed. Without\n * one, prior turns are flattened into a plain-text transcript preamble (tool\n * messages and tool-call-only assistant turns are harness-internal noise and\n * are skipped; prompts are text-only in v1).\n */\nexport function buildPrompt(\n messages: Array<ModelMessage>,\n sessionId: string | undefined,\n): BuiltPrompt {\n const lastMessage = messages.at(-1)\n const lastUserText =\n lastMessage?.role === 'user' ? extractText(lastMessage.content).trim() : ''\n\n if (!lastUserText) {\n throw new Error(\n 'Claude Code adapter requires a trailing user message with text content.',\n )\n }\n\n if (sessionId !== undefined) {\n return { prompt: lastUserText, resume: sessionId }\n }\n\n const priorTurns = messages\n .slice(0, -1)\n .filter(\n (message) =>\n (message.role === 'user' || message.role === 'assistant') &&\n extractText(message.content).trim() !== '',\n )\n .map(\n (message) =>\n `${message.role === 'user' ? 'User' : 'Assistant'}: ${extractText(message.content).trim()}`,\n )\n\n if (priorTurns.length === 0) {\n return { prompt: lastUserText }\n }\n\n return {\n prompt: `Previous conversation:\\n${priorTurns.join('\\n')}\\n\\n${lastUserText}`,\n }\n}\n"],"names":[],"mappings":"AAQA,SAAS,YAAY,SAA0C;AAC7D,MAAI,YAAY,KAAM,QAAO;AAC7B,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,SAAO,QACJ;AAAA,IAAI,CAAC,SACJ,KAAK,SAAS,UAAU,OAAO,KAAK,YAAY,WAC5C,KAAK,UACL;AAAA,EAAA,EAEL,KAAK,EAAE;AACZ;AAYO,SAAS,YACd,UACA,WACa;AACb,QAAM,cAAc,SAAS,GAAG,EAAE;AAClC,QAAM,eACJ,aAAa,SAAS,SAAS,YAAY,YAAY,OAAO,EAAE,KAAA,IAAS;AAE3E,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,MAAI,cAAc,QAAW;AAC3B,WAAO,EAAE,QAAQ,cAAc,QAAQ,UAAA;AAAA,EACzC;AAEA,QAAM,aAAa,SAChB,MAAM,GAAG,EAAE,EACX;AAAA,IACC,CAAC,aACE,QAAQ,SAAS,UAAU,QAAQ,SAAS,gBAC7C,YAAY,QAAQ,OAAO,EAAE,WAAW;AAAA,EAAA,EAE3C;AAAA,IACC,CAAC,YACC,GAAG,QAAQ,SAAS,SAAS,SAAS,WAAW,KAAK,YAAY,QAAQ,OAAO,EAAE,MAAM;AAAA,EAAA;AAG/F,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,QAAQ,aAAA;AAAA,EACnB;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,EAA2B,WAAW,KAAK,IAAI,CAAC;AAAA;AAAA,EAAO,YAAY;AAAA,EAAA;AAE/E;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models known to work with Claude Code. The harness accepts any Anthropic
|
|
3
|
+
* model id (and the `opus` / `sonnet` / `haiku` aliases resolved by the CLI),
|
|
4
|
+
* so this list exists for autocomplete — any string is accepted via the
|
|
5
|
+
* `(string & {})` escape hatch in {@link ClaudeCodeModel}.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CLAUDE_CODE_MODELS: readonly ["claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5", "opus", "sonnet", "haiku"];
|
|
8
|
+
export type KnownClaudeCodeModel = (typeof CLAUDE_CODE_MODELS)[number];
|
|
9
|
+
/** Any Claude model id accepted by Claude Code; known ids get autocomplete. */
|
|
10
|
+
export type ClaudeCodeModel = KnownClaudeCodeModel | (string & {});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const CLAUDE_CODE_MODELS = [
|
|
2
|
+
"claude-opus-4-8",
|
|
3
|
+
"claude-opus-4-7",
|
|
4
|
+
"claude-opus-4-6",
|
|
5
|
+
"claude-sonnet-4-6",
|
|
6
|
+
"claude-haiku-4-5",
|
|
7
|
+
"opus",
|
|
8
|
+
"sonnet",
|
|
9
|
+
"haiku"
|
|
10
|
+
];
|
|
11
|
+
export {
|
|
12
|
+
CLAUDE_CODE_MODELS
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=model-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["/**\n * Models known to work with Claude Code. The harness accepts any Anthropic\n * model id (and the `opus` / `sonnet` / `haiku` aliases resolved by the CLI),\n * so this list exists for autocomplete — any string is accepted via the\n * `(string & {})` escape hatch in {@link ClaudeCodeModel}.\n */\nexport const CLAUDE_CODE_MODELS = [\n 'claude-opus-4-8',\n 'claude-opus-4-7',\n 'claude-opus-4-6',\n 'claude-sonnet-4-6',\n 'claude-haiku-4-5',\n 'opus',\n 'sonnet',\n 'haiku',\n] as const\n\nexport type KnownClaudeCodeModel = (typeof CLAUDE_CODE_MODELS)[number]\n\n/** Any Claude model id accepted by Claude Code; known ids get autocomplete. */\nexport type ClaudeCodeModel = KnownClaudeCodeModel | (string & {})\n"],"names":[],"mappings":"AAMO,MAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';
|
|
2
|
+
/**
|
|
3
|
+
* Per-call provider options for the Claude Code adapter, passed via
|
|
4
|
+
* `modelOptions` on `chat()`.
|
|
5
|
+
*/
|
|
6
|
+
export interface ClaudeCodeTextProviderOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Resume an existing Claude Code session. The adapter emits the session id
|
|
9
|
+
* of every run via a CUSTOM `claude-code.session-id` stream event; thread
|
|
10
|
+
* it back here to continue that session (only the latest user message is
|
|
11
|
+
* sent — the harness already holds the prior context).
|
|
12
|
+
*/
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
/**
|
|
15
|
+
* When resuming, fork to a new session id instead of continuing the
|
|
16
|
+
* original session.
|
|
17
|
+
*/
|
|
18
|
+
forkSession?: boolean;
|
|
19
|
+
/** Per-call override of the configured max harness turns. */
|
|
20
|
+
maxTurns?: number;
|
|
21
|
+
/** Per-call override of the configured permission mode. */
|
|
22
|
+
permissionMode?: PermissionMode;
|
|
23
|
+
/** Per-call override of the allowed built-in tool list. */
|
|
24
|
+
allowedTools?: Array<string>;
|
|
25
|
+
/** Per-call override of the disallowed built-in tool list. */
|
|
26
|
+
disallowedTools?: Array<string>;
|
|
27
|
+
/** Per-call override of the harness working directory. */
|
|
28
|
+
cwd?: string;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural subset of the `@anthropic-ai/claude-agent-sdk` message types that
|
|
3
|
+
* the stream translator consumes.
|
|
4
|
+
*
|
|
5
|
+
* These are intentionally defined structurally (rather than imported from the
|
|
6
|
+
* agent SDK) so the translator stays a pure, fixture-testable state machine
|
|
7
|
+
* and the package's public types don't depend on the agent SDK's bundled
|
|
8
|
+
* `@anthropic-ai/sdk` type imports.
|
|
9
|
+
*/
|
|
10
|
+
export interface SdkInitMessage {
|
|
11
|
+
type: 'system';
|
|
12
|
+
subtype: 'init';
|
|
13
|
+
session_id: string;
|
|
14
|
+
model: string;
|
|
15
|
+
tools: Array<string>;
|
|
16
|
+
cwd?: string;
|
|
17
|
+
}
|
|
18
|
+
export type SdkAssistantContentBlock = {
|
|
19
|
+
type: 'text';
|
|
20
|
+
text: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'thinking';
|
|
23
|
+
thinking: string;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'tool_use';
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
input: unknown;
|
|
29
|
+
} | {
|
|
30
|
+
type: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
};
|
|
33
|
+
export interface SdkAssistantMessage {
|
|
34
|
+
type: 'assistant';
|
|
35
|
+
message: {
|
|
36
|
+
id?: string;
|
|
37
|
+
content: Array<SdkAssistantContentBlock>;
|
|
38
|
+
};
|
|
39
|
+
parent_tool_use_id: string | null;
|
|
40
|
+
}
|
|
41
|
+
export type SdkToolResultContent = string | Array<{
|
|
42
|
+
type: string;
|
|
43
|
+
text?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}>;
|
|
46
|
+
export type SdkUserContentBlock = {
|
|
47
|
+
type: 'tool_result';
|
|
48
|
+
tool_use_id: string;
|
|
49
|
+
content?: SdkToolResultContent;
|
|
50
|
+
is_error?: boolean;
|
|
51
|
+
} | {
|
|
52
|
+
type: string;
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
};
|
|
55
|
+
export interface SdkUserMessage {
|
|
56
|
+
type: 'user';
|
|
57
|
+
message: {
|
|
58
|
+
role: 'user';
|
|
59
|
+
content: string | Array<SdkUserContentBlock>;
|
|
60
|
+
};
|
|
61
|
+
parent_tool_use_id: string | null;
|
|
62
|
+
}
|
|
63
|
+
/** Raw Anthropic streaming events forwarded when `includePartialMessages` is set. */
|
|
64
|
+
export type SdkRawStreamEvent = {
|
|
65
|
+
type: 'message_start';
|
|
66
|
+
message: {
|
|
67
|
+
id?: string;
|
|
68
|
+
};
|
|
69
|
+
} | {
|
|
70
|
+
type: 'content_block_start';
|
|
71
|
+
index: number;
|
|
72
|
+
content_block: {
|
|
73
|
+
type: string;
|
|
74
|
+
};
|
|
75
|
+
} | {
|
|
76
|
+
type: 'content_block_delta';
|
|
77
|
+
index: number;
|
|
78
|
+
delta: {
|
|
79
|
+
type: string;
|
|
80
|
+
text?: string;
|
|
81
|
+
thinking?: string;
|
|
82
|
+
};
|
|
83
|
+
} | {
|
|
84
|
+
type: 'content_block_stop';
|
|
85
|
+
index: number;
|
|
86
|
+
} | {
|
|
87
|
+
type: 'message_delta';
|
|
88
|
+
} | {
|
|
89
|
+
type: 'message_stop';
|
|
90
|
+
};
|
|
91
|
+
export interface SdkPartialAssistantMessage {
|
|
92
|
+
type: 'stream_event';
|
|
93
|
+
event: SdkRawStreamEvent;
|
|
94
|
+
parent_tool_use_id: string | null;
|
|
95
|
+
}
|
|
96
|
+
export interface SdkUsage {
|
|
97
|
+
input_tokens?: number;
|
|
98
|
+
output_tokens?: number;
|
|
99
|
+
cache_read_input_tokens?: number;
|
|
100
|
+
cache_creation_input_tokens?: number;
|
|
101
|
+
}
|
|
102
|
+
export interface SdkResultMessage {
|
|
103
|
+
type: 'result';
|
|
104
|
+
subtype: 'success' | 'error_max_turns' | 'error_during_execution' | 'error_max_budget_usd' | 'error_max_structured_output_retries';
|
|
105
|
+
result?: string;
|
|
106
|
+
errors?: Array<string>;
|
|
107
|
+
usage?: SdkUsage;
|
|
108
|
+
total_cost_usd?: number;
|
|
109
|
+
structured_output?: unknown;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Harness-internal system messages the translator deliberately ignores.
|
|
113
|
+
* (The real SDK union has many more members; unknown runtime types simply
|
|
114
|
+
* fall through every branch.)
|
|
115
|
+
*/
|
|
116
|
+
export interface SdkNoiseSystemMessage {
|
|
117
|
+
type: 'system';
|
|
118
|
+
subtype: 'status' | 'permission_denied' | 'plugin_install' | 'session_state_changed' | 'task_notification' | 'task_progress';
|
|
119
|
+
}
|
|
120
|
+
/** Other harness-internal top-level message types the translator ignores. */
|
|
121
|
+
export interface SdkNoiseMessage {
|
|
122
|
+
type: 'tool_progress' | 'auth_status' | 'rate_limit_event' | 'prompt_suggestion' | 'compact_boundary';
|
|
123
|
+
}
|
|
124
|
+
export type AgentSdkMessage = SdkInitMessage | SdkAssistantMessage | SdkUserMessage | SdkPartialAssistantMessage | SdkResultMessage | SdkNoiseSystemMessage | SdkNoiseMessage;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { StreamChunk } from '@tanstack/ai';
|
|
2
|
+
import { AgentSdkMessage } from './sdk-types.js';
|
|
3
|
+
/** Name of the CUSTOM event carrying the Claude Code session id. */
|
|
4
|
+
export declare const SESSION_ID_EVENT = "claude-code.session-id";
|
|
5
|
+
/** Server name used for bridged TanStack tools (model sees `mcp__tanstack__<name>`). */
|
|
6
|
+
export declare const BRIDGED_MCP_SERVER_NAME = "tanstack";
|
|
7
|
+
/** Claude Code-specific usage details attached to RUN_FINISHED usage. */
|
|
8
|
+
export type ClaudeCodeProviderUsageDetails = {
|
|
9
|
+
/** Total cost of the harness run in USD, as reported by Claude Code. */
|
|
10
|
+
totalCostUsd?: number;
|
|
11
|
+
};
|
|
12
|
+
export interface TranslateContext {
|
|
13
|
+
model: string;
|
|
14
|
+
runId: string;
|
|
15
|
+
threadId: string;
|
|
16
|
+
parentRunId?: string;
|
|
17
|
+
genId: () => string;
|
|
18
|
+
/** Called as soon as the harness reports its session id. */
|
|
19
|
+
onSessionId?: (sessionId: string) => void;
|
|
20
|
+
/** Called for each raw SDK message, for logging. */
|
|
21
|
+
onSdkMessage?: (message: AgentSdkMessage) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Strip the bridged MCP server prefix so tool-call events match the TanStack
|
|
25
|
+
* tool names the application registered. Built-in harness tools (Bash, Read,
|
|
26
|
+
* Edit, ...) and foreign MCP tools pass through verbatim.
|
|
27
|
+
*/
|
|
28
|
+
export declare function stripMcpPrefix(name: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Translate a Claude Code Agent SDK message stream into AG-UI StreamChunk
|
|
31
|
+
* events.
|
|
32
|
+
*
|
|
33
|
+
* The harness runs its own agent loop and executes its own tools, so the
|
|
34
|
+
* translation always ends with `finishReason: 'stop'` (or `'length'` /
|
|
35
|
+
* RUN_ERROR) — never `'tool_calls'`. Harness tool activity is emitted as
|
|
36
|
+
* already-resolved TOOL_CALL_START/ARGS/END + TOOL_CALL_RESULT sequences so
|
|
37
|
+
* UIs can render it, while the TanStack engine never tries to execute them.
|
|
38
|
+
*
|
|
39
|
+
* Invariant: every TOOL_CALL_START is eventually paired with a
|
|
40
|
+
* TOOL_CALL_RESULT (synthesized as `{"status":"interrupted"}` when the run
|
|
41
|
+
* ends or aborts before the harness reported one) so the engine's
|
|
42
|
+
* pending-tool-call scan on the next request never force-executes them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function translateSdkStream(sdkMessages: AsyncIterable<AgentSdkMessage>, ctx: TranslateContext): AsyncIterable<StreamChunk>;
|