@posthog/agent 2.3.233 → 2.3.259

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.
@@ -40,6 +40,6 @@ declare function hydrateSessionJsonl(params: {
40
40
  permissionMode?: string;
41
41
  posthogAPI: PostHogAPIClient;
42
42
  log: HydrationLog;
43
- }): Promise<void>;
43
+ }): Promise<boolean>;
44
44
 
45
45
  export { conversationTurnsToJsonlEntries, getSessionJsonlPath, hydrateSessionJsonl, rebuildConversation, selectRecentTurns };
@@ -386,18 +386,18 @@ async function hydrateSessionJsonl(params) {
386
386
  log.info("Local JSONL exists, skipping S3 hydration", {
387
387
  sessionId: params.sessionId
388
388
  });
389
- return;
389
+ return true;
390
390
  } catch {
391
391
  }
392
392
  const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);
393
393
  if (!taskRun.log_url) {
394
394
  log.info("No log URL, skipping JSONL hydration");
395
- return;
395
+ return false;
396
396
  }
397
397
  const entries = await posthogAPI.fetchTaskRunLogs(taskRun);
398
398
  if (entries.length === 0) {
399
399
  log.info("No S3 log entries, skipping JSONL hydration");
400
- return;
400
+ return false;
401
401
  }
402
402
  const entryCounts = {};
403
403
  for (const entry of entries) {
@@ -414,7 +414,7 @@ async function hydrateSessionJsonl(params) {
414
414
  const allTurns = rebuildConversation(entries);
415
415
  if (allTurns.length === 0) {
416
416
  log.info("No conversation in S3 logs, skipping JSONL hydration");
417
- return;
417
+ return false;
418
418
  }
419
419
  const maxTokens = supports1MContext(params.model ?? "") ? LARGE_CONTEXT_MAX_TOKENS : DEFAULT_MAX_TOKENS;
420
420
  const conversation = selectRecentTurns(allTurns, maxTokens);
@@ -440,11 +440,13 @@ async function hydrateSessionJsonl(params) {
440
440
  turns: conversation.length,
441
441
  lines: jsonlLines.length
442
442
  });
443
+ return true;
443
444
  } catch (err) {
444
445
  log.warn("Failed to hydrate session JSONL, continuing", {
445
446
  sessionId: params.sessionId,
446
447
  error: err instanceof Error ? err.message : String(err)
447
448
  });
449
+ return false;
448
450
  }
449
451
  }
450
452
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/adapters/claude/session/jsonl-hydration.ts","../../../../src/adapters/claude/session/models.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ContentBlock } from \"@agentclientprotocol/sdk\";\nimport type { PostHogAPIClient } from \"../../../posthog-api\";\nimport type { StoredEntry } from \"../../../types\";\nimport { supports1MContext } from \"./models\";\n\ninterface ConversationTurn {\n role: \"user\" | \"assistant\";\n content: ContentBlock[];\n toolCalls?: ToolCallInfo[];\n}\n\ninterface ToolCallInfo {\n toolCallId: string;\n toolName: string;\n input: unknown;\n result?: unknown;\n}\n\ninterface JsonlConfig {\n sessionId: string;\n cwd: string;\n model?: string;\n version?: string;\n gitBranch?: string;\n slug?: string;\n permissionMode?: string;\n}\n\ninterface ClaudeCodeMeta {\n toolCallId?: string;\n toolName?: string;\n toolInput?: unknown;\n toolResponse?: unknown;\n}\n\ninterface SessionUpdate {\n sessionUpdate: string;\n content?: ContentBlock | ContentBlock[];\n _meta?: { claudeCode?: ClaudeCodeMeta };\n}\n\nconst MAX_PROJECT_KEY_LENGTH = 200;\n\nfunction hashString(s: string): string {\n let hash = 0;\n for (let i = 0; i < s.length; i++) {\n hash = (hash << 5) - hash + s.charCodeAt(i);\n hash |= 0;\n }\n return Math.abs(hash).toString(36);\n}\n\nexport function getSessionJsonlPath(sessionId: string, cwd: string): string {\n const configDir =\n process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), \".claude\");\n let projectKey = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n if (projectKey.length > MAX_PROJECT_KEY_LENGTH) {\n projectKey = `${projectKey.slice(0, MAX_PROJECT_KEY_LENGTH)}-${hashString(cwd)}`;\n }\n return path.join(configDir, \"projects\", projectKey, `${sessionId}.jsonl`);\n}\n\nexport function rebuildConversation(\n entries: StoredEntry[],\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n let currentAssistantContent: ContentBlock[] = [];\n let currentToolCalls: ToolCallInfo[] = [];\n\n for (const entry of entries) {\n const method = entry.notification?.method;\n const params = entry.notification?.params as Record<string, unknown>;\n\n if (method === \"session/update\" && params?.update) {\n const update = params.update as SessionUpdate;\n\n switch (update.sessionUpdate) {\n case \"user_message\":\n case \"user_message_chunk\": {\n if (\n currentAssistantContent.length > 0 ||\n currentToolCalls.length > 0\n ) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls:\n currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n currentAssistantContent = [];\n currentToolCalls = [];\n }\n\n const content = update.content;\n const contentArray = Array.isArray(content)\n ? content\n : content\n ? [content]\n : [];\n\n const lastTurn = turns[turns.length - 1];\n if (lastTurn?.role === \"user\") {\n lastTurn.content.push(...contentArray);\n } else {\n turns.push({ role: \"user\", content: contentArray });\n }\n break;\n }\n\n case \"agent_message\":\n case \"agent_message_chunk\":\n case \"agent_thought_chunk\": {\n const content = update.content;\n if (content && !Array.isArray(content)) {\n if (\n content.type === \"text\" &&\n currentAssistantContent.length > 0 &&\n currentAssistantContent[currentAssistantContent.length - 1]\n .type === \"text\"\n ) {\n const lastBlock = currentAssistantContent[\n currentAssistantContent.length - 1\n ] as { type: \"text\"; text: string };\n lastBlock.text += (\n content as { type: \"text\"; text: string }\n ).text;\n } else {\n currentAssistantContent.push(content);\n }\n }\n break;\n }\n\n case \"tool_call\":\n case \"tool_call_update\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolName, toolInput, toolResponse } = meta;\n\n if (toolCallId && toolName) {\n let toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (!toolCall) {\n toolCall = { toolCallId, toolName, input: toolInput };\n currentToolCalls.push(toolCall);\n }\n if (toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n\n case \"tool_result\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolResponse } = meta;\n if (toolCallId) {\n const toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (toolCall && toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n }\n }\n }\n\n if (currentAssistantContent.length > 0 || currentToolCalls.length > 0) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n }\n\n return turns;\n}\n\nconst CHARS_PER_TOKEN = 4;\nconst DEFAULT_MAX_TOKENS = 150_000;\nconst LARGE_CONTEXT_MAX_TOKENS = 800_000;\n\nfunction estimateTurnTokens(turn: ConversationTurn): number {\n let chars = 0;\n for (const block of turn.content) {\n if (\"text\" in block && typeof block.text === \"string\") {\n chars += block.text.length;\n }\n }\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n chars += JSON.stringify(tc.input ?? \"\").length;\n if (tc.result !== undefined) {\n chars +=\n typeof tc.result === \"string\"\n ? tc.result.length\n : JSON.stringify(tc.result).length;\n }\n }\n }\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\n\nexport function selectRecentTurns(\n turns: ConversationTurn[],\n maxTokens = DEFAULT_MAX_TOKENS,\n): ConversationTurn[] {\n let budget = maxTokens;\n let startIndex = turns.length;\n\n for (let i = turns.length - 1; i >= 0; i--) {\n const cost = estimateTurnTokens(turns[i]);\n if (cost > budget) break;\n budget -= cost;\n startIndex = i;\n }\n\n // Ensure we start on a user turn so the conversation is well-formed\n while (startIndex < turns.length && turns[startIndex].role !== \"user\") {\n startIndex++;\n }\n\n return turns.slice(startIndex);\n}\n\nconst BASE62 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\nfunction generateMessageId(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n let id = \"msg_01\";\n for (const b of bytes) {\n id += BASE62[b % 62];\n }\n return id;\n}\n\nconst ADJECTIVES = [\n \"bright\",\n \"calm\",\n \"daring\",\n \"eager\",\n \"fair\",\n \"gentle\",\n \"happy\",\n \"keen\",\n \"lively\",\n \"merry\",\n \"noble\",\n \"polite\",\n \"quick\",\n \"sharp\",\n \"warm\",\n \"witty\",\n];\nconst VERBS = [\n \"blazing\",\n \"crafting\",\n \"dashing\",\n \"flowing\",\n \"gliding\",\n \"humming\",\n \"jumping\",\n \"linking\",\n \"melting\",\n \"nesting\",\n \"pacing\",\n \"roaming\",\n \"sailing\",\n \"turning\",\n \"waving\",\n \"zoning\",\n];\nconst NOUNS = [\n \"aurora\",\n \"breeze\",\n \"cedar\",\n \"delta\",\n \"ember\",\n \"frost\",\n \"grove\",\n \"haven\",\n \"inlet\",\n \"jewel\",\n \"knoll\",\n \"lotus\",\n \"maple\",\n \"nexus\",\n \"oasis\",\n \"prism\",\n];\n\nfunction generateSlug(): string {\n const pick = (arr: string[]) => arr[Math.floor(Math.random() * arr.length)];\n return `${pick(ADJECTIVES)}-${pick(VERBS)}-${pick(NOUNS)}`;\n}\n\nexport function conversationTurnsToJsonlEntries(\n turns: ConversationTurn[],\n config: JsonlConfig,\n): string[] {\n const lines: string[] = [];\n let parentUuid: string | null = null;\n const model = config.model ?? \"claude-opus-4-6\";\n const version = config.version ?? \"2.1.63\";\n const gitBranch = config.gitBranch ?? \"\";\n const slug = config.slug ?? generateSlug();\n const permissionMode = config.permissionMode ?? \"default\";\n const baseTime = Date.now() - turns.length * 3000;\n let turnIndex = 0;\n\n for (const turn of turns) {\n const timestamp = new Date(baseTime + turnIndex * 3000).toISOString();\n turnIndex++;\n if (turn.role === \"user\") {\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"enqueue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"dequeue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n\n const uuid = randomUUID();\n const textParts = turn.content\n .filter(\n (block) =>\n \"text\" in block && typeof block.text === \"string\" && block.text,\n )\n .map((block) => (block as { text: string }).text);\n\n const userText = textParts.length > 0 ? textParts.join(\"\") : \" \";\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n },\n uuid,\n timestamp,\n permissionMode,\n }),\n );\n parentUuid = uuid;\n } else {\n const allBlocks: unknown[] = [];\n\n for (const block of turn.content) {\n const blockType = (block as { type: string }).type;\n if (blockType === \"thinking\" || blockType === \"text\") {\n allBlocks.push(block);\n }\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n allBlocks.push({\n type: \"tool_use\",\n id: tc.toolCallId,\n name: tc.toolName,\n input: tc.input,\n });\n }\n }\n\n const msgId = generateMessageId();\n const hasToolUse = allBlocks.some(\n (b) => (b as { type: string }).type === \"tool_use\",\n );\n const lastStopReason = hasToolUse ? \"tool_use\" : \"end_turn\";\n\n for (let i = 0; i < allBlocks.length; i++) {\n const block = allBlocks[i];\n const isLast = i === allBlocks.length - 1;\n const uuid = randomUUID();\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"assistant\",\n message: {\n model,\n id: msgId,\n type: \"message\",\n role: \"assistant\",\n content: [block],\n stop_reason: isLast ? lastStopReason : null,\n stop_sequence: null,\n usage: {\n input_tokens: 0,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n output_tokens: 0,\n },\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n if (tc.result === undefined) continue;\n\n const uuid = randomUUID();\n const resultText =\n typeof tc.result === \"string\"\n ? tc.result\n : JSON.stringify(tc.result);\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: tc.toolCallId,\n content: resultText,\n },\n ],\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n }\n }\n }\n\n return lines;\n}\n\ninterface HydrationLog {\n info: (msg: string, data?: unknown) => void;\n warn: (msg: string, data?: unknown) => void;\n}\n\nexport async function hydrateSessionJsonl(params: {\n sessionId: string;\n cwd: string;\n taskId: string;\n runId: string;\n model?: string;\n gitBranch?: string;\n permissionMode?: string;\n posthogAPI: PostHogAPIClient;\n log: HydrationLog;\n}): Promise<void> {\n const { posthogAPI, log } = params;\n\n try {\n const jsonlPath = getSessionJsonlPath(params.sessionId, params.cwd);\n try {\n await fs.access(jsonlPath);\n log.info(\"Local JSONL exists, skipping S3 hydration\", {\n sessionId: params.sessionId,\n });\n return;\n } catch {\n // File doesn't exist, proceed with hydration\n }\n\n const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);\n if (!taskRun.log_url) {\n log.info(\"No log URL, skipping JSONL hydration\");\n return;\n }\n\n const entries = await posthogAPI.fetchTaskRunLogs(taskRun);\n if (entries.length === 0) {\n log.info(\"No S3 log entries, skipping JSONL hydration\");\n return;\n }\n\n const entryCounts: Record<string, number> = {};\n for (const entry of entries) {\n const method = entry.notification?.method ?? \"unknown\";\n const entryParams = entry.notification?.params as\n | Record<string, unknown>\n | undefined;\n const update = entryParams?.update as\n | { sessionUpdate?: string }\n | undefined;\n const key = update?.sessionUpdate\n ? `${method}:${update.sessionUpdate}`\n : method;\n entryCounts[key] = (entryCounts[key] ?? 0) + 1;\n }\n log.info(\"S3 log entry breakdown\", {\n totalEntries: entries.length,\n types: entryCounts,\n });\n\n const allTurns = rebuildConversation(entries);\n if (allTurns.length === 0) {\n log.info(\"No conversation in S3 logs, skipping JSONL hydration\");\n return;\n }\n\n const maxTokens = supports1MContext(params.model ?? \"\")\n ? LARGE_CONTEXT_MAX_TOKENS\n : DEFAULT_MAX_TOKENS;\n const conversation = selectRecentTurns(allTurns, maxTokens);\n log.info(\"Selected recent turns for hydration\", {\n totalTurns: allTurns.length,\n selectedTurns: conversation.length,\n turnRoles: conversation.map((t) => t.role),\n });\n\n const jsonlLines = conversationTurnsToJsonlEntries(conversation, {\n sessionId: params.sessionId,\n cwd: params.cwd,\n model: params.model,\n gitBranch: params.gitBranch,\n permissionMode: params.permissionMode,\n });\n\n await fs.mkdir(path.dirname(jsonlPath), { recursive: true });\n\n const tmpPath = `${jsonlPath}.tmp.${Date.now()}`;\n await fs.writeFile(tmpPath, `${jsonlLines.join(\"\\n\")}\\n`);\n await fs.rename(tmpPath, jsonlPath);\n\n log.info(\"Hydrated session JSONL from S3\", {\n sessionId: params.sessionId,\n turns: conversation.length,\n lines: jsonlLines.length,\n });\n } catch (err) {\n log.warn(\"Failed to hydrate session JSONL, continuing\", {\n sessionId: params.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n","export const DEFAULT_MODEL = \"opus\";\n\nconst GATEWAY_TO_SDK_MODEL: Record<string, string> = {\n \"claude-opus-4-5\": \"opus\",\n \"claude-opus-4-6\": \"opus\",\n \"claude-sonnet-4-5\": \"sonnet\",\n \"claude-sonnet-4-6\": \"sonnet\",\n \"claude-haiku-4-5\": \"haiku\",\n};\n\nexport function toSdkModelId(modelId: string): string {\n return GATEWAY_TO_SDK_MODEL[modelId] ?? modelId;\n}\n\nconst MODELS_WITH_1M_CONTEXT = new Set([\n \"claude-opus-4-6\",\n \"claude-sonnet-4-6\",\n]);\n\nexport function supports1MContext(modelId: string): boolean {\n return MODELS_WITH_1M_CONTEXT.has(modelId);\n}\n\nconst MODELS_WITH_EFFORT = new Set([\n \"claude-opus-4-5\",\n \"claude-opus-4-6\",\n \"claude-sonnet-4-6\",\n]);\n\nconst MODELS_WITH_MAX_EFFORT = new Set([\"claude-opus-4-6\"]);\n\nexport function supportsEffort(modelId: string): boolean {\n return MODELS_WITH_EFFORT.has(modelId);\n}\n\nexport function supportsMaxEffort(modelId: string): boolean {\n return MODELS_WITH_MAX_EFFORT.has(modelId);\n}\n\nconst MODELS_TO_EXCLUDE_MCP_TOOLS = new Set([\"claude-haiku-4-5\"]);\n\nexport function supportsMcpInjection(modelId: string): boolean {\n return !MODELS_TO_EXCLUDE_MCP_TOOLS.has(modelId);\n}\n\ninterface EffortOption {\n value: string;\n name: string;\n}\n\nexport function getEffortOptions(modelId: string): EffortOption[] | null {\n if (!supportsEffort(modelId)) return null;\n\n const options: EffortOption[] = [\n { value: \"low\", name: \"Low\" },\n { value: \"medium\", name: \"Medium\" },\n { value: \"high\", name: \"High\" },\n ];\n\n if (supportsMaxEffort(modelId)) {\n options.push({ value: \"max\", name: \"Max\" });\n }\n\n return options;\n}\n\n// Model alias resolution — lets callers use human-friendly aliases like\n// \"opus\" or \"sonnet\" instead of full model IDs like \"claude-opus-4-6\".\n\nconst MODEL_CONTEXT_HINT_PATTERN = /\\[(\\d+m)\\]$/i;\n\nfunction tokenizeModelPreference(model: string): {\n tokens: string[];\n contextHint?: string;\n} {\n const lower = model.trim().toLowerCase();\n const contextHint = lower\n .match(MODEL_CONTEXT_HINT_PATTERN)?.[1]\n ?.toLowerCase();\n\n const normalized = lower.replace(MODEL_CONTEXT_HINT_PATTERN, \" $1 \");\n const rawTokens = normalized.split(/[^a-z0-9]+/).filter(Boolean);\n const tokens = rawTokens\n .map((token) => {\n if (token === \"opusplan\") return \"opus\";\n if (token === \"best\" || token === \"default\") return \"\";\n return token;\n })\n .filter((token) => token && token !== \"claude\")\n .filter((token) => /[a-z]/.test(token) || token.endsWith(\"m\"));\n\n return { tokens, contextHint };\n}\n\ninterface ModelOption {\n value: string;\n name?: string;\n description?: string;\n}\n\nfunction scoreModelMatch(\n model: ModelOption,\n tokens: string[],\n contextHint?: string,\n): number {\n const haystack = `${model.value} ${model.name ?? \"\"}`.toLowerCase();\n let score = 0;\n for (const token of tokens) {\n if (haystack.includes(token)) {\n score += token === contextHint ? 3 : 1;\n }\n }\n return score;\n}\n\nexport function resolveModelPreference(\n preference: string,\n options: ModelOption[],\n): string | null {\n const trimmed = preference.trim();\n if (!trimmed) return null;\n\n const lower = trimmed.toLowerCase();\n\n // Exact match on value or display name\n const directMatch = options.find(\n (o) =>\n o.value === trimmed ||\n o.value.toLowerCase() === lower ||\n (o.name && o.name.toLowerCase() === lower),\n );\n if (directMatch) return directMatch.value;\n\n // Substring match\n const includesMatch = options.find((o) => {\n const value = o.value.toLowerCase();\n const display = (o.name ?? \"\").toLowerCase();\n return (\n value.includes(lower) || display.includes(lower) || lower.includes(value)\n );\n });\n if (includesMatch) return includesMatch.value;\n\n // Tokenized matching for aliases like \"opus[1m]\"\n const { tokens, contextHint } = tokenizeModelPreference(trimmed);\n if (tokens.length === 0) return null;\n\n let bestMatch: ModelOption | null = null;\n let bestScore = 0;\n for (const model of options) {\n const score = scoreModelMatch(model, tokens, contextHint);\n if (0 < score && (!bestMatch || bestScore < score)) {\n bestMatch = model;\n bestScore = score;\n }\n }\n\n return bestMatch?.value ?? null;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/adapters/claude/session/jsonl-hydration.ts","../../../../src/adapters/claude/session/models.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ContentBlock } from \"@agentclientprotocol/sdk\";\nimport type { PostHogAPIClient } from \"../../../posthog-api\";\nimport type { StoredEntry } from \"../../../types\";\nimport { supports1MContext } from \"./models\";\n\ninterface ConversationTurn {\n role: \"user\" | \"assistant\";\n content: ContentBlock[];\n toolCalls?: ToolCallInfo[];\n}\n\ninterface ToolCallInfo {\n toolCallId: string;\n toolName: string;\n input: unknown;\n result?: unknown;\n}\n\ninterface JsonlConfig {\n sessionId: string;\n cwd: string;\n model?: string;\n version?: string;\n gitBranch?: string;\n slug?: string;\n permissionMode?: string;\n}\n\ninterface ClaudeCodeMeta {\n toolCallId?: string;\n toolName?: string;\n toolInput?: unknown;\n toolResponse?: unknown;\n}\n\ninterface SessionUpdate {\n sessionUpdate: string;\n content?: ContentBlock | ContentBlock[];\n _meta?: { claudeCode?: ClaudeCodeMeta };\n}\n\nconst MAX_PROJECT_KEY_LENGTH = 200;\n\nfunction hashString(s: string): string {\n let hash = 0;\n for (let i = 0; i < s.length; i++) {\n hash = (hash << 5) - hash + s.charCodeAt(i);\n hash |= 0;\n }\n return Math.abs(hash).toString(36);\n}\n\nexport function getSessionJsonlPath(sessionId: string, cwd: string): string {\n const configDir =\n process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), \".claude\");\n let projectKey = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n if (projectKey.length > MAX_PROJECT_KEY_LENGTH) {\n projectKey = `${projectKey.slice(0, MAX_PROJECT_KEY_LENGTH)}-${hashString(cwd)}`;\n }\n return path.join(configDir, \"projects\", projectKey, `${sessionId}.jsonl`);\n}\n\nexport function rebuildConversation(\n entries: StoredEntry[],\n): ConversationTurn[] {\n const turns: ConversationTurn[] = [];\n let currentAssistantContent: ContentBlock[] = [];\n let currentToolCalls: ToolCallInfo[] = [];\n\n for (const entry of entries) {\n const method = entry.notification?.method;\n const params = entry.notification?.params as Record<string, unknown>;\n\n if (method === \"session/update\" && params?.update) {\n const update = params.update as SessionUpdate;\n\n switch (update.sessionUpdate) {\n case \"user_message\":\n case \"user_message_chunk\": {\n if (\n currentAssistantContent.length > 0 ||\n currentToolCalls.length > 0\n ) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls:\n currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n currentAssistantContent = [];\n currentToolCalls = [];\n }\n\n const content = update.content;\n const contentArray = Array.isArray(content)\n ? content\n : content\n ? [content]\n : [];\n\n const lastTurn = turns[turns.length - 1];\n if (lastTurn?.role === \"user\") {\n lastTurn.content.push(...contentArray);\n } else {\n turns.push({ role: \"user\", content: contentArray });\n }\n break;\n }\n\n case \"agent_message\":\n case \"agent_message_chunk\":\n case \"agent_thought_chunk\": {\n const content = update.content;\n if (content && !Array.isArray(content)) {\n if (\n content.type === \"text\" &&\n currentAssistantContent.length > 0 &&\n currentAssistantContent[currentAssistantContent.length - 1]\n .type === \"text\"\n ) {\n const lastBlock = currentAssistantContent[\n currentAssistantContent.length - 1\n ] as { type: \"text\"; text: string };\n lastBlock.text += (\n content as { type: \"text\"; text: string }\n ).text;\n } else {\n currentAssistantContent.push(content);\n }\n }\n break;\n }\n\n case \"tool_call\":\n case \"tool_call_update\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolName, toolInput, toolResponse } = meta;\n\n if (toolCallId && toolName) {\n let toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (!toolCall) {\n toolCall = { toolCallId, toolName, input: toolInput };\n currentToolCalls.push(toolCall);\n }\n if (toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n\n case \"tool_result\": {\n const meta = update._meta?.claudeCode;\n if (meta) {\n const { toolCallId, toolResponse } = meta;\n if (toolCallId) {\n const toolCall = currentToolCalls.find(\n (tc) => tc.toolCallId === toolCallId,\n );\n if (toolCall && toolResponse !== undefined) {\n toolCall.result = toolResponse;\n }\n }\n }\n break;\n }\n }\n }\n }\n\n if (currentAssistantContent.length > 0 || currentToolCalls.length > 0) {\n turns.push({\n role: \"assistant\",\n content: currentAssistantContent,\n toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,\n });\n }\n\n return turns;\n}\n\nconst CHARS_PER_TOKEN = 4;\nconst DEFAULT_MAX_TOKENS = 150_000;\nconst LARGE_CONTEXT_MAX_TOKENS = 800_000;\n\nfunction estimateTurnTokens(turn: ConversationTurn): number {\n let chars = 0;\n for (const block of turn.content) {\n if (\"text\" in block && typeof block.text === \"string\") {\n chars += block.text.length;\n }\n }\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n chars += JSON.stringify(tc.input ?? \"\").length;\n if (tc.result !== undefined) {\n chars +=\n typeof tc.result === \"string\"\n ? tc.result.length\n : JSON.stringify(tc.result).length;\n }\n }\n }\n return Math.ceil(chars / CHARS_PER_TOKEN);\n}\n\nexport function selectRecentTurns(\n turns: ConversationTurn[],\n maxTokens = DEFAULT_MAX_TOKENS,\n): ConversationTurn[] {\n let budget = maxTokens;\n let startIndex = turns.length;\n\n for (let i = turns.length - 1; i >= 0; i--) {\n const cost = estimateTurnTokens(turns[i]);\n if (cost > budget) break;\n budget -= cost;\n startIndex = i;\n }\n\n // Ensure we start on a user turn so the conversation is well-formed\n while (startIndex < turns.length && turns[startIndex].role !== \"user\") {\n startIndex++;\n }\n\n return turns.slice(startIndex);\n}\n\nconst BASE62 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\nfunction generateMessageId(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n let id = \"msg_01\";\n for (const b of bytes) {\n id += BASE62[b % 62];\n }\n return id;\n}\n\nconst ADJECTIVES = [\n \"bright\",\n \"calm\",\n \"daring\",\n \"eager\",\n \"fair\",\n \"gentle\",\n \"happy\",\n \"keen\",\n \"lively\",\n \"merry\",\n \"noble\",\n \"polite\",\n \"quick\",\n \"sharp\",\n \"warm\",\n \"witty\",\n];\nconst VERBS = [\n \"blazing\",\n \"crafting\",\n \"dashing\",\n \"flowing\",\n \"gliding\",\n \"humming\",\n \"jumping\",\n \"linking\",\n \"melting\",\n \"nesting\",\n \"pacing\",\n \"roaming\",\n \"sailing\",\n \"turning\",\n \"waving\",\n \"zoning\",\n];\nconst NOUNS = [\n \"aurora\",\n \"breeze\",\n \"cedar\",\n \"delta\",\n \"ember\",\n \"frost\",\n \"grove\",\n \"haven\",\n \"inlet\",\n \"jewel\",\n \"knoll\",\n \"lotus\",\n \"maple\",\n \"nexus\",\n \"oasis\",\n \"prism\",\n];\n\nfunction generateSlug(): string {\n const pick = (arr: string[]) => arr[Math.floor(Math.random() * arr.length)];\n return `${pick(ADJECTIVES)}-${pick(VERBS)}-${pick(NOUNS)}`;\n}\n\nexport function conversationTurnsToJsonlEntries(\n turns: ConversationTurn[],\n config: JsonlConfig,\n): string[] {\n const lines: string[] = [];\n let parentUuid: string | null = null;\n const model = config.model ?? \"claude-opus-4-6\";\n const version = config.version ?? \"2.1.63\";\n const gitBranch = config.gitBranch ?? \"\";\n const slug = config.slug ?? generateSlug();\n const permissionMode = config.permissionMode ?? \"default\";\n const baseTime = Date.now() - turns.length * 3000;\n let turnIndex = 0;\n\n for (const turn of turns) {\n const timestamp = new Date(baseTime + turnIndex * 3000).toISOString();\n turnIndex++;\n if (turn.role === \"user\") {\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"enqueue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n lines.push(\n JSON.stringify({\n type: \"queue-operation\",\n operation: \"dequeue\",\n timestamp,\n sessionId: config.sessionId,\n }),\n );\n\n const uuid = randomUUID();\n const textParts = turn.content\n .filter(\n (block) =>\n \"text\" in block && typeof block.text === \"string\" && block.text,\n )\n .map((block) => (block as { text: string }).text);\n\n const userText = textParts.length > 0 ? textParts.join(\"\") : \" \";\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n },\n uuid,\n timestamp,\n permissionMode,\n }),\n );\n parentUuid = uuid;\n } else {\n const allBlocks: unknown[] = [];\n\n for (const block of turn.content) {\n const blockType = (block as { type: string }).type;\n if (blockType === \"thinking\" || blockType === \"text\") {\n allBlocks.push(block);\n }\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n allBlocks.push({\n type: \"tool_use\",\n id: tc.toolCallId,\n name: tc.toolName,\n input: tc.input,\n });\n }\n }\n\n const msgId = generateMessageId();\n const hasToolUse = allBlocks.some(\n (b) => (b as { type: string }).type === \"tool_use\",\n );\n const lastStopReason = hasToolUse ? \"tool_use\" : \"end_turn\";\n\n for (let i = 0; i < allBlocks.length; i++) {\n const block = allBlocks[i];\n const isLast = i === allBlocks.length - 1;\n const uuid = randomUUID();\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"assistant\",\n message: {\n model,\n id: msgId,\n type: \"message\",\n role: \"assistant\",\n content: [block],\n stop_reason: isLast ? lastStopReason : null,\n stop_sequence: null,\n usage: {\n input_tokens: 0,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n output_tokens: 0,\n },\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n\n if (turn.toolCalls) {\n for (const tc of turn.toolCalls) {\n if (tc.result === undefined) continue;\n\n const uuid = randomUUID();\n const resultText =\n typeof tc.result === \"string\"\n ? tc.result\n : JSON.stringify(tc.result);\n\n lines.push(\n JSON.stringify({\n parentUuid,\n isSidechain: false,\n userType: \"external\",\n cwd: config.cwd,\n sessionId: config.sessionId,\n version,\n gitBranch,\n slug,\n type: \"user\",\n message: {\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: tc.toolCallId,\n content: resultText,\n },\n ],\n },\n uuid,\n timestamp,\n }),\n );\n parentUuid = uuid;\n }\n }\n }\n }\n\n return lines;\n}\n\ninterface HydrationLog {\n info: (msg: string, data?: unknown) => void;\n warn: (msg: string, data?: unknown) => void;\n}\n\nexport async function hydrateSessionJsonl(params: {\n sessionId: string;\n cwd: string;\n taskId: string;\n runId: string;\n model?: string;\n gitBranch?: string;\n permissionMode?: string;\n posthogAPI: PostHogAPIClient;\n log: HydrationLog;\n}): Promise<boolean> {\n const { posthogAPI, log } = params;\n\n try {\n const jsonlPath = getSessionJsonlPath(params.sessionId, params.cwd);\n try {\n await fs.access(jsonlPath);\n log.info(\"Local JSONL exists, skipping S3 hydration\", {\n sessionId: params.sessionId,\n });\n return true;\n } catch {\n // File doesn't exist, proceed with hydration\n }\n\n const taskRun = await posthogAPI.getTaskRun(params.taskId, params.runId);\n if (!taskRun.log_url) {\n log.info(\"No log URL, skipping JSONL hydration\");\n return false;\n }\n\n const entries = await posthogAPI.fetchTaskRunLogs(taskRun);\n if (entries.length === 0) {\n log.info(\"No S3 log entries, skipping JSONL hydration\");\n return false;\n }\n\n const entryCounts: Record<string, number> = {};\n for (const entry of entries) {\n const method = entry.notification?.method ?? \"unknown\";\n const entryParams = entry.notification?.params as\n | Record<string, unknown>\n | undefined;\n const update = entryParams?.update as\n | { sessionUpdate?: string }\n | undefined;\n const key = update?.sessionUpdate\n ? `${method}:${update.sessionUpdate}`\n : method;\n entryCounts[key] = (entryCounts[key] ?? 0) + 1;\n }\n log.info(\"S3 log entry breakdown\", {\n totalEntries: entries.length,\n types: entryCounts,\n });\n\n const allTurns = rebuildConversation(entries);\n if (allTurns.length === 0) {\n log.info(\"No conversation in S3 logs, skipping JSONL hydration\");\n return false;\n }\n\n const maxTokens = supports1MContext(params.model ?? \"\")\n ? LARGE_CONTEXT_MAX_TOKENS\n : DEFAULT_MAX_TOKENS;\n const conversation = selectRecentTurns(allTurns, maxTokens);\n log.info(\"Selected recent turns for hydration\", {\n totalTurns: allTurns.length,\n selectedTurns: conversation.length,\n turnRoles: conversation.map((t) => t.role),\n });\n\n const jsonlLines = conversationTurnsToJsonlEntries(conversation, {\n sessionId: params.sessionId,\n cwd: params.cwd,\n model: params.model,\n gitBranch: params.gitBranch,\n permissionMode: params.permissionMode,\n });\n\n await fs.mkdir(path.dirname(jsonlPath), { recursive: true });\n\n const tmpPath = `${jsonlPath}.tmp.${Date.now()}`;\n await fs.writeFile(tmpPath, `${jsonlLines.join(\"\\n\")}\\n`);\n await fs.rename(tmpPath, jsonlPath);\n\n log.info(\"Hydrated session JSONL from S3\", {\n sessionId: params.sessionId,\n turns: conversation.length,\n lines: jsonlLines.length,\n });\n return true;\n } catch (err) {\n log.warn(\"Failed to hydrate session JSONL, continuing\", {\n sessionId: params.sessionId,\n error: err instanceof Error ? err.message : String(err),\n });\n return false;\n }\n}\n","export const DEFAULT_MODEL = \"opus\";\n\nconst GATEWAY_TO_SDK_MODEL: Record<string, string> = {\n \"claude-opus-4-5\": \"opus\",\n \"claude-opus-4-6\": \"opus\",\n \"claude-sonnet-4-5\": \"sonnet\",\n \"claude-sonnet-4-6\": \"sonnet\",\n \"claude-haiku-4-5\": \"haiku\",\n};\n\nexport function toSdkModelId(modelId: string): string {\n return GATEWAY_TO_SDK_MODEL[modelId] ?? modelId;\n}\n\nconst MODELS_WITH_1M_CONTEXT = new Set([\n \"claude-opus-4-6\",\n \"claude-sonnet-4-6\",\n]);\n\nexport function supports1MContext(modelId: string): boolean {\n return MODELS_WITH_1M_CONTEXT.has(modelId);\n}\n\nconst MODELS_WITH_EFFORT = new Set([\n \"claude-opus-4-5\",\n \"claude-opus-4-6\",\n \"claude-sonnet-4-6\",\n]);\n\nconst MODELS_WITH_MAX_EFFORT = new Set([\"claude-opus-4-6\"]);\n\nexport function supportsEffort(modelId: string): boolean {\n return MODELS_WITH_EFFORT.has(modelId);\n}\n\nexport function supportsMaxEffort(modelId: string): boolean {\n return MODELS_WITH_MAX_EFFORT.has(modelId);\n}\n\nconst MODELS_TO_EXCLUDE_MCP_TOOLS = new Set([\"claude-haiku-4-5\"]);\n\nexport function supportsMcpInjection(modelId: string): boolean {\n return !MODELS_TO_EXCLUDE_MCP_TOOLS.has(modelId);\n}\n\ninterface EffortOption {\n value: string;\n name: string;\n}\n\nexport function getEffortOptions(modelId: string): EffortOption[] | null {\n if (!supportsEffort(modelId)) return null;\n\n const options: EffortOption[] = [\n { value: \"low\", name: \"Low\" },\n { value: \"medium\", name: \"Medium\" },\n { value: \"high\", name: \"High\" },\n ];\n\n if (supportsMaxEffort(modelId)) {\n options.push({ value: \"max\", name: \"Max\" });\n }\n\n return options;\n}\n\n// Model alias resolution — lets callers use human-friendly aliases like\n// \"opus\" or \"sonnet\" instead of full model IDs like \"claude-opus-4-6\".\n\nconst MODEL_CONTEXT_HINT_PATTERN = /\\[(\\d+m)\\]$/i;\n\nfunction tokenizeModelPreference(model: string): {\n tokens: string[];\n contextHint?: string;\n} {\n const lower = model.trim().toLowerCase();\n const contextHint = lower\n .match(MODEL_CONTEXT_HINT_PATTERN)?.[1]\n ?.toLowerCase();\n\n const normalized = lower.replace(MODEL_CONTEXT_HINT_PATTERN, \" $1 \");\n const rawTokens = normalized.split(/[^a-z0-9]+/).filter(Boolean);\n const tokens = rawTokens\n .map((token) => {\n if (token === \"opusplan\") return \"opus\";\n if (token === \"best\" || token === \"default\") return \"\";\n return token;\n })\n .filter((token) => token && token !== \"claude\")\n .filter((token) => /[a-z]/.test(token) || token.endsWith(\"m\"));\n\n return { tokens, contextHint };\n}\n\ninterface ModelOption {\n value: string;\n name?: string;\n description?: string;\n}\n\nfunction scoreModelMatch(\n model: ModelOption,\n tokens: string[],\n contextHint?: string,\n): number {\n const haystack = `${model.value} ${model.name ?? \"\"}`.toLowerCase();\n let score = 0;\n for (const token of tokens) {\n if (haystack.includes(token)) {\n score += token === contextHint ? 3 : 1;\n }\n }\n return score;\n}\n\nexport function resolveModelPreference(\n preference: string,\n options: ModelOption[],\n): string | null {\n const trimmed = preference.trim();\n if (!trimmed) return null;\n\n const lower = trimmed.toLowerCase();\n\n // Exact match on value or display name\n const directMatch = options.find(\n (o) =>\n o.value === trimmed ||\n o.value.toLowerCase() === lower ||\n (o.name && o.name.toLowerCase() === lower),\n );\n if (directMatch) return directMatch.value;\n\n // Substring match\n const includesMatch = options.find((o) => {\n const value = o.value.toLowerCase();\n const display = (o.name ?? \"\").toLowerCase();\n return (\n value.includes(lower) || display.includes(lower) || lower.includes(value)\n );\n });\n if (includesMatch) return includesMatch.value;\n\n // Tokenized matching for aliases like \"opus[1m]\"\n const { tokens, contextHint } = tokenizeModelPreference(trimmed);\n if (tokens.length === 0) return null;\n\n let bestMatch: ModelOption | null = null;\n let bestScore = 0;\n for (const model of options) {\n const score = scoreModelMatch(model, tokens, contextHint);\n if (0 < score && (!bestMatch || bestScore < score)) {\n bestMatch = model;\n bestScore = score;\n }\n }\n\n return bestMatch?.value ?? null;\n}\n"],"mappings":"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","names":[]}
package/dist/agent.js CHANGED
@@ -245,7 +245,7 @@ import { v7 as uuidv7 } from "uuid";
245
245
  // package.json
246
246
  var package_default = {
247
247
  name: "@posthog/agent",
248
- version: "2.3.233",
248
+ version: "2.3.259",
249
249
  repository: "https://github.com/PostHog/code",
250
250
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
251
251
  exports: {
@@ -341,6 +341,7 @@ var package_default = {
341
341
  },
342
342
  dependencies: {
343
343
  "@agentclientprotocol/sdk": "0.16.1",
344
+ ajv: "^8.17.1",
344
345
  "@anthropic-ai/claude-agent-sdk": "0.2.76",
345
346
  "@anthropic-ai/sdk": "^0.78.0",
346
347
  "@hono/node-server": "^1.19.9",
@@ -2984,6 +2985,7 @@ function buildSessionOptions(params) {
2984
2985
  params.settingsManager,
2985
2986
  params.logger
2986
2987
  ),
2988
+ outputFormat: params.outputFormat,
2987
2989
  abortController: getAbortController(
2988
2990
  params.userProvidedOptions?.abortController
2989
2991
  ),
@@ -3571,6 +3573,11 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3571
3573
  };
3572
3574
  const result = handleResultMessage(message);
3573
3575
  if (result.error) throw result.error;
3576
+ if (message.subtype === "success" && message.structured_output != null && this.options?.onStructuredOutput) {
3577
+ await this.options.onStructuredOutput(
3578
+ message.structured_output
3579
+ );
3580
+ }
3574
3581
  if (isLocalOnlyCommand && message.subtype === "success" && message.result) {
3575
3582
  await this.client.sessionUpdate({
3576
3583
  sessionId: params.sessionId,
@@ -3796,6 +3803,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3796
3803
  const earlyModelId = settingsManager.getSettings().model || meta?.model || "";
3797
3804
  const mcpServers = supportsMcpInjection(earlyModelId) ? parseMcpServers(params) : {};
3798
3805
  const systemPrompt = buildSystemPrompt(meta?.systemPrompt);
3806
+ const outputFormat = meta?.jsonSchema && this.options?.onStructuredOutput ? { type: "json_schema", schema: meta.jsonSchema } : void 0;
3799
3807
  this.logger.info(isResume ? "Resuming session" : "Creating new session", {
3800
3808
  sessionId,
3801
3809
  taskId,
@@ -3819,6 +3827,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3819
3827
  ...meta?.additionalRoots ?? []
3820
3828
  ],
3821
3829
  disableBuiltInTools: meta?.disableBuiltInTools,
3830
+ outputFormat,
3822
3831
  settingsManager,
3823
3832
  onModeChange: this.createOnModeChange(),
3824
3833
  onProcessSpawned: this.options?.onProcessSpawned,
@@ -4781,7 +4790,10 @@ function createClaudeConnection(config) {
4781
4790
  const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
4782
4791
  let agent = null;
4783
4792
  const agentConnection = new AgentSideConnection((client) => {
4784
- agent = new ClaudeAcpAgent(client, config.processCallbacks);
4793
+ agent = new ClaudeAcpAgent(client, {
4794
+ ...config.processCallbacks,
4795
+ onStructuredOutput: config.onStructuredOutput
4796
+ });
4785
4797
  logger.info(`Created ${agent.adapterName} agent`);
4786
4798
  return agent;
4787
4799
  }, agentStream);
@@ -4974,6 +4986,15 @@ var PostHogAPIClient = class {
4974
4986
  }
4975
4987
  );
4976
4988
  }
4989
+ async setTaskRunOutput(taskId, runId, output) {
4990
+ return this.apiRequest(
4991
+ `/api/projects/${this.getTeamId()}/tasks/${taskId}/runs/${runId}/set_output/`,
4992
+ {
4993
+ method: "PATCH",
4994
+ body: JSON.stringify(output)
4995
+ }
4996
+ );
4997
+ }
4977
4998
  async appendTaskRunLog(taskId, runId, entries) {
4978
4999
  const teamId = this.getTeamId();
4979
5000
  return this.apiRequest(
@@ -5499,6 +5520,7 @@ var Agent = class {
5499
5520
  deviceType: "local",
5500
5521
  logger: this.logger,
5501
5522
  processCallbacks: options.processCallbacks,
5523
+ onStructuredOutput: options.onStructuredOutput,
5502
5524
  allowedModelIds,
5503
5525
  codexOptions: options.adapter === "codex" && gatewayConfig ? {
5504
5526
  cwd: options.repositoryPath,