@aigne/afs-agent 1.11.0-beta.13

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["DEFAULT_CONTEXT_WINDOW","log","found","parseSkillFrontmatter","parseSkillFrontmatterShared","llmDurationMs","data","result","parseYAML"],"sources":["../src/ash-generator.ts","../src/token-estimator.ts","../src/context.ts","../src/context-compress.ts","../src/observability.ts","../src/tool-schema.ts","../src/agent-run.ts","../src/messages-log.ts","../src/observability-routing.ts","../src/spawn-depth.ts","../src/orchestration.ts","../src/session-queue.ts","../src/provider.ts","../src/scratchpad.ts"],"sourcesContent":["/**\n * ASH source generator for agent-run.\n *\n * Converts validated tool_calls into a single ASH program\n * with @caps scoped to the exact paths in this round's calls.\n */\n\nexport interface ValidatedToolCall {\n id: string;\n op: \"read\" | \"list\" | \"exec\";\n path: string;\n args: Record<string, unknown>;\n}\n\n/**\n * Format a value as an ASH inline literal.\n * Strings get quoted, numbers/booleans are bare.\n */\nfunction formatValue(v: unknown): string {\n if (typeof v === \"string\") return JSON.stringify(v);\n if (typeof v === \"number\" || typeof v === \"boolean\") return String(v);\n return JSON.stringify(v);\n}\n\n/**\n * Format args as ASH inline object: { key: \"val\", num: 42 }\n */\nfunction formatInlineArgs(args: Record<string, unknown>): string {\n const entries = Object.entries(args);\n if (entries.length === 0) return \"\";\n const pairs = entries.map(([k, v]) => `${k}: ${formatValue(v)}`);\n return ` { ${pairs.join(\", \")} }`;\n}\n\n/**\n * Generate a single pipeline statement for a tool call.\n */\nfunction generateStatement(call: ValidatedToolCall): string {\n const resultPath = `/.results/${call.id}`;\n\n if (call.op === \"read\" || call.op === \"list\") {\n return `find ${call.path} | save ${resultPath}`;\n }\n\n // exec\n const inlineArgs = formatInlineArgs(call.args);\n return `action ${call.path}${inlineArgs} | save ${resultPath}`;\n}\n\n/**\n * Derive @caps declaration from the calls in this round.\n *\n * Capabilities:\n * - read: for read/list ops (exact path)\n * - exec: for exec ops (exact path)\n * - write: always /.results/* (where save goes)\n */\nfunction deriveCaps(calls: ValidatedToolCall[]): string {\n const parts: string[] = [];\n\n for (const call of calls) {\n if (call.op === \"read\" || call.op === \"list\") {\n parts.push(`read ${call.path}`);\n } else if (call.op === \"exec\") {\n parts.push(`exec ${call.path}`);\n }\n }\n\n // Always need write for save targets\n parts.push(\"write /.results/*\");\n\n return `@caps(${parts.join(\" \")})`;\n}\n\n/**\n * Generate a complete ASH program from validated tool calls.\n *\n * Each call becomes a separate pipeline within a single job.\n * The program is scoped with @caps derived from actual paths.\n */\nexport function generateAsh(calls: ValidatedToolCall[], round: number): string {\n const caps = deriveCaps(calls);\n const statements = calls.map(generateStatement);\n const body = statements.length > 0 ? statements.join(\"\\n \") : 'output \"no-op\"';\n\n return `${caps}\\njob round_${round} {\\n ${body}\\n}`;\n}\n","/**\n * Lightweight token estimation based on character types.\n *\n * Uses empirical heuristics for CJK characters, English words, and other characters\n * to approximate token counts without requiring an external tokenizer.\n */\n\n// ─── Patterns ────────────────────────────────────────────────────────────────\n\n/** CJK Unified Ideographs + Extension A + Compatibility + Hiragana + Katakana */\nconst CJK_PATTERN = /[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uf900-\\ufaff\\u3040-\\u309f\\u30a0-\\u30ff]/g;\n\n/** Consecutive ASCII letter sequences (English words) */\nconst WORD_PATTERN = /[a-zA-Z]+/g;\n\n// ─── Ratios ──────────────────────────────────────────────────────────────────\n\n/** CJK: ~1.5 characters per token */\nconst CJK_CHARS_PER_TOKEN = 1.5;\n\n/** English: ~1 token per word (conservative estimate) */\nconst TOKENS_PER_WORD = 1.0;\n\n// ─── Functions ───────────────────────────────────────────────────────────────\n\n/**\n * Estimate token count for a text string.\n *\n * Uses character-type-aware heuristics:\n * - CJK characters: ~1.5 chars per token\n * - English words: ~1 token per word\n * - Other characters (punctuation, digits, whitespace): ~1 char per token\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n\n let tokens = 0;\n let accountedChars = 0;\n\n // CJK characters\n const cjkMatches = text.match(CJK_PATTERN);\n if (cjkMatches) {\n tokens += cjkMatches.length / CJK_CHARS_PER_TOKEN;\n accountedChars += cjkMatches.length;\n }\n\n // English words\n const wordMatches = text.match(WORD_PATTERN);\n if (wordMatches) {\n tokens += wordMatches.length * TOKENS_PER_WORD;\n for (const w of wordMatches) accountedChars += w.length;\n }\n\n // Remaining characters (punctuation, digits, whitespace)\n const remaining = text.length - accountedChars;\n if (remaining > 0) tokens += remaining;\n\n return Math.ceil(tokens);\n}\n\n/**\n * Estimate total tokens for an array of messages (OpenAI format).\n *\n * Handles:\n * - `content` (string) — text tokens, capped per message\n * - `toolCalls` / `tool_calls` — function name + arguments + structure overhead\n *\n * @param singleMessageLimit - Max tokens counted per individual message content\n * (prevents a single huge tool result from dominating the estimate)\n */\nexport function estimateMessagesTokens(\n messages: Array<Record<string, unknown>>,\n singleMessageLimit = Number.POSITIVE_INFINITY,\n): number {\n let total = 0;\n\n for (const msg of messages) {\n let msgTokens = 0;\n\n // Text content\n const content = msg.content;\n if (typeof content === \"string\") {\n msgTokens += Math.min(estimateTokens(content), singleMessageLimit);\n }\n\n // Tool calls (on assistant messages)\n const toolCalls = msg.toolCalls ?? msg.tool_calls;\n if (Array.isArray(toolCalls)) {\n for (const tc of toolCalls) {\n const fn = (tc as Record<string, unknown>).function as Record<string, unknown> | undefined;\n if (fn) {\n msgTokens += estimateTokens(String(fn.name ?? \"\"));\n const args = fn.arguments;\n msgTokens += estimateTokens(typeof args === \"string\" ? args : JSON.stringify(args ?? {}));\n msgTokens += 10; // structure overhead per tool call\n }\n }\n }\n\n total += msgTokens;\n }\n\n return total;\n}\n","/**\n * Context builder — assembles messages[] for LLM calls.\n *\n * Combines system prompt, memory recall, conversation history, and user task\n * into a flat messages array. Memory is optional — without it, the output\n * matches agent-run's current hand-assembled behavior exactly.\n */\nimport type { AFSRoot } from \"@aigne/afs\";\nimport { estimateMessagesTokens, estimateTokens } from \"./token-estimator.js\";\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface ContextMemoryOptions {\n /** AFS exec path for recall (e.g. \"/modules/memory/.actions/recall\"). */\n recallPath: string;\n /** Max tokens for memory injection into system message. Default: 2000. */\n maxTokens?: number;\n /** Domain filter passed to recall. */\n domain?: string;\n}\n\nexport interface ContextOptions {\n /** Current user input / task. */\n task: string;\n /** System prompt (role, persona, instructions). */\n system?: string;\n /** Conversation history messages (passed through as-is). */\n history?: Array<Record<string, unknown>>;\n /** Memory recall configuration. Omit to disable memory. */\n memory?: ContextMemoryOptions;\n /** Additional directives appended to system message (e.g. STOP_DIRECTIVE, AFS_HINT). */\n directives?: string[];\n}\n\nexport interface MemoryTraceEntry {\n tokens: number;\n entries: number;\n sources: string[];\n}\n\nexport interface ContextManifest {\n memory: {\n selected: string[];\n query?: string;\n available?: number;\n };\n history: {\n keptTurns: number;\n truncatedTurns: number;\n compressed: boolean;\n };\n tools: {\n included: string[];\n };\n}\n\nexport interface ContextTrace {\n system: { tokens: number };\n memory: MemoryTraceEntry | null;\n history: { tokens: number; messages: number };\n user: { tokens: number };\n total: number;\n manifest?: ContextManifest;\n}\n\nexport interface ContextResult {\n messages: Array<{ role: string; content: string; [key: string]: unknown }>;\n trace: ContextTrace;\n}\n\n// ─── Memory ─────────────────────────────────────────────────────────────────\n\ninterface RecallEntry {\n path: string;\n content: string;\n score?: number;\n meta?: Record<string, unknown>;\n}\n\ninterface RecallLayer {\n level: string;\n entries: RecallEntry[];\n}\n\nconst DEFAULT_MEMORY_MAX_TOKENS = 2000;\n\n/**\n * Convert JSONL content (from archived sessions) into a readable conversation format.\n * Non-JSONL content is returned as-is.\n */\nexport function formatRecallContent(content: string): string {\n const lines = content.split(\"\\n\");\n if (lines.length === 0) return content;\n\n const formatted: string[] = [];\n let hasJson = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const msg = JSON.parse(trimmed);\n if (msg.role && msg.content) {\n formatted.push(`[${msg.role}]: ${msg.content}`);\n hasJson = true;\n } else {\n formatted.push(trimmed);\n }\n } catch {\n formatted.push(trimmed);\n }\n }\n\n return hasJson && formatted.length > 0 ? formatted.join(\"\\n\") : content;\n}\n\ninterface MemoryContextResult {\n text: string;\n trace: MemoryTraceEntry;\n query: string;\n available?: number;\n}\n\nasync function buildMemoryContext(\n afs: AFSRoot,\n opts: ContextMemoryOptions,\n task: string,\n): Promise<MemoryContextResult | null> {\n let recallResult: Awaited<ReturnType<NonNullable<AFSRoot[\"exec\"]>>> | undefined;\n try {\n recallResult = await afs.exec!(\n opts.recallPath,\n { text: task, scope: opts.domain, limit: 30 },\n {},\n );\n } catch {\n return null;\n }\n if (!recallResult.success) return null;\n\n const data = recallResult.data as { layers?: RecallLayer[]; totalAvailable?: number } | undefined;\n const layers = data?.layers;\n if (!Array.isArray(layers) || layers.length === 0) return null;\n\n const maxTokens = opts.maxTokens ?? DEFAULT_MEMORY_MAX_TOKENS;\n\n // L3 (pattern/principle) first — high value, few entries\n // L2 (observation) fills remaining budget\n const l3 = layers.find((l) => l.level === \"L3\");\n const l2 = layers.find((l) => l.level === \"L2\");\n\n const parts: string[] = [];\n const sources: string[] = [];\n let tokens = 0;\n\n for (const layer of [l3, l2]) {\n if (!layer?.entries) continue;\n for (const entry of layer.entries) {\n if (!entry.content) continue;\n // Format JSONL content into readable conversation before estimating tokens\n const readable = formatRecallContent(entry.content);\n const t = estimateTokens(readable);\n // Skip entries that exceed remaining budget (continue, not break —\n // later entries may be smaller and still fit)\n if (tokens + t > maxTokens) continue;\n parts.push(readable);\n sources.push(entry.path);\n tokens += t;\n }\n }\n\n if (parts.length === 0) return null;\n return {\n text: parts.join(\"\\n\\n---\\n\\n\"),\n trace: { tokens, entries: parts.length, sources },\n query: task,\n available: data?.totalAvailable,\n };\n}\n\n// ─── Build ──────────────────────────────────────────────────────────────────\n\n/**\n * Assemble a messages array for LLM calls.\n *\n * Output order: [system, ...history, user]\n *\n * System message = system prompt + memory recall + directives.\n * Without memory, output is identical to agent-run's current hand-assembled messages.\n * Memory failures silently fall back to the no-memory path.\n */\nexport async function buildContext(afs: AFSRoot, opts: ContextOptions): Promise<ContextResult> {\n // ── Memory recall (optional, best-effort) ──\n let memoryResult: MemoryContextResult | null = null;\n if (opts.memory) {\n memoryResult = await buildMemoryContext(afs, opts.memory, opts.task);\n }\n\n // ── System message assembly ──\n const systemParts: string[] = [];\n if (opts.system) systemParts.push(opts.system);\n if (memoryResult) systemParts.push(`\\n## Relevant memories\\n${memoryResult.text}`);\n if (opts.directives) {\n for (const d of opts.directives) {\n if (d) systemParts.push(d);\n }\n }\n const systemContent = systemParts.join(\"\\n\\n\");\n\n // ── Messages array ──\n const messages: Array<{ role: string; content: string; [key: string]: unknown }> = [];\n\n messages.push({ role: \"system\", content: systemContent });\n\n if (opts.history) {\n for (const msg of opts.history) {\n messages.push(msg as { role: string; content: string; [key: string]: unknown });\n }\n }\n\n messages.push({ role: \"user\", content: opts.task });\n\n // ── Trace ──\n const systemTokens = estimateTokens(systemContent);\n const userTokens = estimateTokens(opts.task);\n const historyTokens = opts.history ? estimateMessagesTokens(opts.history) : 0;\n const historyCount = opts.history?.length ?? 0;\n\n // ── Manifest ──\n const manifest: ContextManifest = {\n memory: {\n selected: memoryResult?.trace.sources ?? [],\n query: opts.memory ? opts.task : undefined,\n available: memoryResult?.available,\n },\n history: {\n keptTurns: historyCount,\n truncatedTurns: 0,\n compressed: false,\n },\n tools: {\n included: [],\n },\n };\n\n const trace: ContextTrace = {\n system: { tokens: systemTokens },\n memory: memoryResult?.trace ?? null,\n history: { tokens: historyTokens, messages: historyCount },\n user: { tokens: userTokens },\n total: systemTokens + historyTokens + userTokens,\n manifest,\n };\n\n return { messages, trace };\n}\n","/**\n * Context compression for agent-run.\n *\n * When accumulated messages approach the model's context window limit,\n * compresses older messages into a summary while preserving recent messages.\n * Uses the same callLLM dependency as agent-run for summary generation.\n */\n\nimport type { AFSExecResult } from \"@aigne/afs\";\nimport { estimateMessagesTokens } from \"./token-estimator.js\";\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nconst DEFAULT_CONTEXT_WINDOW = 80000;\n\n/** Trigger compression when messages exceed this ratio of context window */\nconst TRIGGER_RATIO = 0.7;\n\n/** Keep recent messages up to this ratio of context window */\nconst KEEP_RECENT_RATIO = 0.35;\n\n/** Timeout for the compression LLM call (ms) */\nconst COMPRESS_TIMEOUT_MS = 60_000;\n\n/** Max characters for the formatted summary input sent to LLM */\nconst MAX_SUMMARY_INPUT_CHARS = 30_000;\n\n/** Per-tool-result truncation limit for summary formatting */\nconst TOOL_RESULT_TRUNCATE = 500;\n\n/** System prompt for the summarizer LLM call */\nconst COMPRESS_SYSTEM_PROMPT = `You are a conversation compressor. Your task is to losslessly compress the provided conversation into a structured summary that preserves ALL important context for future conversation continuity.\n\nYou are NOT the assistant — do not respond to the user or continue the conversation. You are an external summarizer.\n\nOutput format — use this exact structure:\n\n## User Profile\n<Who the user is: name, role, expertise, preferences — if mentioned>\n\n## Conversation Summary\n<Chronological summary of what happened: topics discussed, questions asked, actions taken, tools called and their outcomes>\n\n## Key Decisions & Facts\n<Bullet list of specific decisions made, facts established, paths/URLs/IDs mentioned, configurations set>\n\n## Current State\n<Where things stand: what was accomplished, what is in progress, any errors or blockers encountered>\n\n## Open Items\n<Pending tasks, unanswered questions, follow-up items — if any>\n\nRules:\n- Preserve specific details: names, file paths, IDs, error messages, config values\n- Include tool call outcomes (what was called, what it returned in brief)\n- Write in the same language the user used in the conversation\n- Be thorough — it is better to include too much than to lose critical context\n- If a section has no content, write \"None\" and move on`;\n\n// ─── Main Function ───────────────────────────────────────────────────────────\n\n/**\n * Check if messages need compression and compress if necessary.\n *\n * Returns the original messages array (same reference) if no compression is needed,\n * or a new array with compressed messages if compression was performed.\n *\n * Compression is best-effort: if callLLM fails, returns original messages unchanged.\n * When compression succeeds, calls `onCompressed` with the new messages for history rewrite.\n *\n * Note: compression LLM call token usage is NOT counted toward agent-run's total_tokens budget.\n * This is intentional — compression is a meta-operation, not a user-facing LLM interaction.\n */\n/** Progress info emitted during compression. */\nexport interface CompressProgress {\n phase: \"triggered\" | \"summarizing\" | \"done\" | \"skipped\" | \"failed\";\n /** Estimated tokens before compression. */\n beforeTokens: number;\n /** Context window size. */\n contextWindow: number;\n /** Number of messages being compressed (triggered/summarizing/done). */\n compressedMessages?: number;\n /** Number of messages kept (triggered/summarizing/done). */\n keptMessages?: number;\n /** Estimated tokens after compression (done only). */\n afterTokens?: number;\n /** Error message (failed only). */\n error?: string;\n}\n\nexport async function maybeCompress(\n messages: Array<Record<string, unknown>>,\n opts: {\n contextWindow?: number;\n /**\n * Anchor message that must be preserved verbatim across compressions\n * (typically the current user task). Identified by object reference.\n * If the anchor falls in the compress zone, it is excluded from the\n * summary and re-inserted between the system message and the summary\n * so the LLM always sees a clear \"what the user asked\" anchor.\n */\n pinMessage?: Record<string, unknown>;\n callLLM: (args: Record<string, unknown>) => Promise<AFSExecResult>;\n onCompressed?: (\n compressedMessages: Array<Record<string, unknown>>,\n archivedMessages: Array<Record<string, unknown>>,\n ) => Promise<void>;\n onProgress?: (info: CompressProgress) => void;\n },\n): Promise<Array<Record<string, unknown>>> {\n const contextWindow = opts.contextWindow ?? DEFAULT_CONTEXT_WINDOW;\n const triggerThreshold = Math.floor(contextWindow * TRIGGER_RATIO);\n const keepRecentTokens = Math.floor(contextWindow * KEEP_RECENT_RATIO);\n\n const totalTokens = estimateMessagesTokens(messages);\n if (totalTokens <= triggerThreshold) {\n opts.onProgress?.({\n phase: \"skipped\",\n beforeTokens: totalTokens,\n contextWindow,\n });\n return messages;\n }\n\n // ── Partition messages ──────────────────────────────────────────────\n // 1. System message (index 0 if role === \"system\") — always preserved\n // 2. Recent messages — iterate backward, accumulate until keepRecentTokens\n // 3. Middle messages — everything between system and recent → compress\n\n let systemMessage: Record<string, unknown> | undefined;\n let contentStart = 0;\n if (messages.length > 0 && messages[0]!.role === \"system\") {\n systemMessage = messages[0]!;\n contentStart = 1;\n }\n\n // Find split point: iterate backward from end\n // Cap per-message tokens to prevent a single huge tool result from consuming the entire keep budget\n const singleMessageLimit = Math.floor(keepRecentTokens * 0.5);\n let splitIndex = messages.length;\n let recentTokens = 0;\n for (let i = messages.length - 1; i >= contentStart; i--) {\n const msgTokens = estimateMessagesTokens([messages[i]!], singleMessageLimit);\n if (recentTokens + msgTokens > keepRecentTokens) {\n splitIndex = i + 1;\n break;\n }\n recentTokens += msgTokens;\n splitIndex = i;\n }\n\n // Fallback: if the capped split made everything fit in keep zone (toCompress would be empty)\n // but we know compression is needed, redo without the cap\n if (splitIndex <= contentStart) {\n splitIndex = messages.length;\n recentTokens = 0;\n for (let i = messages.length - 1; i >= contentStart; i--) {\n const msgTokens = estimateMessagesTokens([messages[i]!]);\n if (recentTokens + msgTokens > keepRecentTokens) {\n splitIndex = i + 1;\n break;\n }\n recentTokens += msgTokens;\n splitIndex = i;\n }\n }\n\n // Adjust split point to respect message boundaries:\n // - keep zone must not start with a tool message (orphaned result)\n // - compress zone must not end with assistant+tool_calls (orphaned calls)\n splitIndex = adjustSplitForMessageBoundary(messages, splitIndex, contentStart);\n\n // Resolve pin: only honor if it's a non-system message inside this array.\n const pinIdx =\n opts.pinMessage && contentStart > 0\n ? messages.indexOf(opts.pinMessage, contentStart)\n : opts.pinMessage\n ? messages.indexOf(opts.pinMessage)\n : -1;\n const pinValid = pinIdx >= contentStart;\n const pinInKeepZone = pinValid && pinIdx >= splitIndex;\n const pinInCompressZone = pinValid && !pinInKeepZone;\n const pinnedMessage = pinValid ? messages[pinIdx]! : undefined;\n\n // Ensure we have something to compress.\n // Exclude the pin from the compress zone — it's preserved verbatim.\n const toCompress: Array<Record<string, unknown>> = [];\n for (let i = contentStart; i < splitIndex; i++) {\n if (i === pinIdx) continue;\n toCompress.push(messages[i]!);\n }\n const toKeep = messages.slice(splitIndex);\n if (toCompress.length === 0) return messages;\n\n const baseProgress: Pick<\n CompressProgress,\n \"beforeTokens\" | \"contextWindow\" | \"compressedMessages\" | \"keptMessages\"\n > = {\n beforeTokens: totalTokens,\n contextWindow,\n compressedMessages: toCompress.length,\n keptMessages: toKeep.length,\n };\n\n opts.onProgress?.({ phase: \"triggered\", ...baseProgress });\n\n // ── Generate summary ──────────────────────────────────────────────\n try {\n const formatted = formatMessagesForSummary(toCompress);\n\n opts.onProgress?.({ phase: \"summarizing\", ...baseProgress });\n\n const compressResult = await Promise.race([\n opts.callLLM({\n messages: [\n { role: \"system\", content: COMPRESS_SYSTEM_PROMPT },\n { role: \"user\", content: formatted },\n ],\n }),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"Compression LLM call timed out\")), COMPRESS_TIMEOUT_MS),\n ),\n ]);\n\n if (!compressResult.success) {\n return compressFallback(\n systemMessage,\n toKeep,\n toCompress,\n baseProgress,\n opts,\n \"LLM call failed\",\n pinInCompressZone ? pinnedMessage : undefined,\n );\n }\n\n const summary = (compressResult.data as Record<string, unknown>)?.text;\n if (typeof summary !== \"string\" || !summary.trim()) {\n return compressFallback(\n systemMessage,\n toKeep,\n toCompress,\n baseProgress,\n opts,\n \"Empty summary\",\n pinInCompressZone ? pinnedMessage : undefined,\n );\n }\n\n // ── Assemble compressed messages ──────────────────────────────\n // Order: [system, pinned_user_task?, summary, ...toKeep]\n // Pin is only inserted if it was in the compress zone — if it was\n // already in toKeep we leave it there to avoid duplication.\n const result: Array<Record<string, unknown>> = [];\n if (systemMessage) result.push(systemMessage);\n if (pinInCompressZone && pinnedMessage) result.push(pinnedMessage);\n result.push({\n role: \"user\",\n content: `[Previous conversation summary]\\n${summary.trim()}`,\n });\n result.push(...toKeep);\n\n const afterTokens = estimateMessagesTokens(result);\n opts.onProgress?.({ phase: \"done\", ...baseProgress, afterTokens });\n\n // Notify caller to rewrite working history + archive compressed messages\n if (opts.onCompressed) {\n try {\n await opts.onCompressed(result, toCompress);\n } catch {\n /* best-effort */\n }\n }\n\n return result;\n } catch (err) {\n return compressFallback(\n systemMessage,\n toKeep,\n toCompress,\n baseProgress,\n opts,\n err instanceof Error ? err.message : String(err),\n pinInCompressZone ? pinnedMessage : undefined,\n );\n }\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Fallback when LLM-based compression fails (timeout, error, empty summary).\n * Drops compressed messages and inserts a \"[conversation history truncated]\"\n * placeholder so the agent can continue instead of looping.\n */\nfunction compressFallback(\n systemMessage: Record<string, unknown> | undefined,\n toKeep: Array<Record<string, unknown>>,\n toCompress: Array<Record<string, unknown>>,\n baseProgress: Pick<\n CompressProgress,\n \"beforeTokens\" | \"contextWindow\" | \"compressedMessages\" | \"keptMessages\"\n >,\n opts: {\n onCompressed?: (\n compressedMessages: Array<Record<string, unknown>>,\n archivedMessages: Array<Record<string, unknown>>,\n ) => Promise<void>;\n onProgress?: (info: CompressProgress) => void;\n },\n error: string,\n pinnedMessage?: Record<string, unknown>,\n): Array<Record<string, unknown>> {\n const result: Array<Record<string, unknown>> = [];\n if (systemMessage) result.push(systemMessage);\n if (pinnedMessage) result.push(pinnedMessage);\n result.push({\n role: \"user\",\n content:\n \"[Previous conversation history was truncated due to context limits. \" +\n `${toCompress.length} older messages were removed.]`,\n });\n result.push(...toKeep);\n\n const afterTokens = estimateMessagesTokens(result);\n opts.onProgress?.({\n phase: \"done\",\n ...baseProgress,\n afterTokens,\n error: `Fallback truncation: ${error}`,\n });\n\n if (opts.onCompressed) {\n try {\n opts.onCompressed(result, toCompress);\n } catch {\n /* best-effort */\n }\n }\n\n return result;\n}\n\n/**\n * Adjust splitIndex so it doesn't break tool_call/tool_result groups.\n *\n * Rules:\n * 1. Keep zone must not start with a tool message (orphaned result without parent assistant).\n * → Walk backward to include the parent assistant+tool_calls.\n * 2. Compress zone must not end with assistant+tool_calls whose results are in keep zone.\n * → Move that assistant into keep zone.\n */\nfunction adjustSplitForMessageBoundary(\n messages: Array<Record<string, unknown>>,\n splitIndex: number,\n contentStart: number,\n): number {\n if (splitIndex <= contentStart || splitIndex >= messages.length) return splitIndex;\n\n // Rule 1: if keep zone starts with tool messages, walk back to parent assistant\n while (splitIndex > contentStart && messages[splitIndex]?.role === \"tool\") {\n splitIndex--;\n }\n\n // Rule 2: if compress zone ends with assistant+tool_calls, move it to keep zone\n if (splitIndex > contentStart) {\n const lastCompress = messages[splitIndex - 1];\n const toolCalls = lastCompress?.toolCalls ?? lastCompress?.tool_calls;\n if (Array.isArray(toolCalls) && toolCalls.length > 0) {\n splitIndex--;\n }\n }\n\n return splitIndex;\n}\n\n/**\n * Format a single message into a readable line for the summarizer.\n */\nfunction formatSingleMessage(msg: Record<string, unknown>): string {\n const role = String(msg.role ?? \"unknown\");\n const content = String(msg.content ?? \"\");\n\n // Assistant with tool calls — list function names\n const toolCalls = msg.toolCalls ?? msg.tool_calls;\n if (Array.isArray(toolCalls) && toolCalls.length > 0) {\n const callSummary = toolCalls\n .map((tc: any) => `${tc.function?.name ?? \"unknown\"}(...)`)\n .join(\", \");\n return `[${role}] ${content.slice(0, 500)}\\n Tool calls: ${callSummary}`;\n }\n if (role === \"tool\") {\n return `[tool result] ${content.slice(0, TOOL_RESULT_TRUNCATE)}`;\n }\n return `[${role}] ${content.slice(0, 1000)}`;\n}\n\n/**\n * Format messages into a readable text block for the summarizer.\n *\n * Uses a two-end strategy: prioritize the earliest messages (conversation start,\n * often contains user identity and goals) and the most recent messages (current\n * context and latest actions). Middle messages are omitted if budget is exceeded.\n */\nfunction formatMessagesForSummary(messages: Array<Record<string, unknown>>): string {\n // Budget: reserve half for head (oldest), half for tail (newest)\n const headBudget = Math.floor(MAX_SUMMARY_INPUT_CHARS * 0.4);\n const tailBudget = Math.floor(MAX_SUMMARY_INPUT_CHARS * 0.6);\n\n // Collect from head\n const headParts: string[] = [];\n let headLen = 0;\n let headEnd = 0;\n for (let i = 0; i < messages.length; i++) {\n const line = formatSingleMessage(messages[i]!);\n if (headLen + line.length + 2 > headBudget) break;\n headParts.push(line);\n headLen += line.length + 2;\n headEnd = i + 1;\n }\n\n // Collect from tail (reversed, then flip back)\n const tailParts: string[] = [];\n let tailLen = 0;\n let tailStart = messages.length;\n for (let i = messages.length - 1; i >= headEnd; i--) {\n const line = formatSingleMessage(messages[i]!);\n if (tailLen + line.length + 2 > tailBudget) break;\n tailParts.unshift(line);\n tailLen += line.length + 2;\n tailStart = i;\n }\n\n // Assemble\n const omitted = tailStart - headEnd;\n if (omitted > 0) {\n return [...headParts, `\\n[... ${omitted} messages omitted ...]\\n`, ...tailParts].join(\"\\n\\n\");\n }\n return [...headParts, ...tailParts].join(\"\\n\\n\");\n}\n","/**\n * Agent-run observability helpers (Phase 0.5 jsonl).\n *\n * One run = one .jsonl file under `/instance/logs/agent-runs/{date}/`. Each line\n * is one event with `type` discriminator + monotonic `seq` + ms `ts`. Writes go\n * through the standard `callAFS(\"write\", path, { content, mode: \"append\" })`\n * interface so a future AFSLog provider can be mounted at `/instance/logs/`\n * without touching application code.\n *\n * - `safeStringifyLine`: JSON.stringify with no indent, circular/BigInt/Date/\n * Symbol/Function handling, plus per-line size cap via largest-field-first\n * truncation.\n * - `truncateField`: per-field truncation marker for over-budget strings + nested objects.\n * - `stripInternalFields`: drops `_*` prefixed keys from recorded toolCall args\n * (prevents `_scope_afs` / `_abort_signal` etc. from leaking into the log).\n */\n\nexport const FIELD_LIMIT = 64 * 1024; // 64 KB / field\nexport const EVENT_LIMIT = 256 * 1024; // 256 KB / line (best-effort)\n\ntype Replacer = (key: string, value: unknown) => unknown;\n\nfunction buildReplacer(): Replacer {\n const seen = new WeakSet<object>();\n return (_key: string, val: unknown): unknown => {\n if (typeof val === \"bigint\") return `${val.toString()}n`;\n if (val instanceof Date) return val.toISOString();\n if (typeof val === \"function\") return \"[Function]\";\n if (typeof val === \"symbol\") return val.toString();\n if (val && typeof val === \"object\") {\n if (seen.has(val as object)) return \"[Circular]\";\n seen.add(val as object);\n }\n return val;\n };\n}\n\n/**\n * Stringify a single jsonl event into one line (no indent). Returns valid JSON\n * even for `undefined` (which `JSON.stringify` would otherwise yield as\n * `undefined` and break a `JSON.parse` round-trip).\n *\n * If the line exceeds `EVENT_LIMIT`, the largest fields are truncated until the\n * line fits; truncated fields gain `_truncated: true` + `_originalSize` markers.\n */\nexport function safeStringifyLine(value: unknown, maxEventSize: number = EVENT_LIMIT): string {\n if (value === undefined) {\n return JSON.stringify({ _serialization_failed: true, error: \"input is undefined\" });\n }\n let json: string;\n try {\n json = JSON.stringify(value, buildReplacer());\n } catch (err) {\n return JSON.stringify({\n _serialization_failed: true,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n if (\n json.length > maxEventSize &&\n value !== null &&\n typeof value === \"object\" &&\n !Array.isArray(value)\n ) {\n return truncateOversizedLine(value as Record<string, unknown>, maxEventSize);\n }\n return json;\n}\n\nfunction truncateOversizedLine(obj: Record<string, unknown>, maxEventSize: number): string {\n const truncated: Record<string, unknown> = { ...obj };\n const fieldSizes: Array<[string, number]> = [];\n for (const k of Object.keys(truncated)) {\n let size: number;\n try {\n size = JSON.stringify(truncated[k], buildReplacer()).length;\n } catch {\n size = 0;\n }\n fieldSizes.push([k, size]);\n }\n fieldSizes.sort((a, b) => b[1] - a[1]);\n\n for (const [k] of fieldSizes) {\n truncated[k] = truncateField(truncated[k], FIELD_LIMIT);\n let sized: number;\n try {\n sized = JSON.stringify(truncated, buildReplacer()).length;\n } catch {\n sized = maxEventSize + 1;\n }\n if (sized <= maxEventSize) break;\n }\n try {\n return JSON.stringify(truncated, buildReplacer());\n } catch (err) {\n return JSON.stringify({\n _serialization_failed: true,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\nexport function truncateField(value: unknown, limit: number): unknown {\n if (value === null || value === undefined) return value;\n if (typeof value === \"string\") {\n if (value.length > limit) {\n return {\n _truncated: true,\n _originalSize: value.length,\n content: value.slice(0, limit),\n };\n }\n return value;\n }\n let json: string;\n try {\n json = JSON.stringify(value, buildReplacer());\n } catch {\n return { _truncated: true, _serialization_failed: true };\n }\n if (json.length > limit) {\n return {\n _truncated: true,\n _originalSize: json.length,\n content: json.slice(0, limit),\n };\n }\n return value;\n}\n\nexport function stripInternalFields(args: Record<string, unknown>): Record<string, unknown> {\n const cleaned: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(args)) {\n if (!k.startsWith(\"_\")) cleaned[k] = v;\n }\n return cleaned;\n}\n\n// ─── LogEvent discriminated union ───────────────────────────────────────\n\ninterface BaseEvent {\n seq: number;\n ts: number;\n}\n\nexport interface RunStartEvent extends BaseEvent {\n type: \"run.start\";\n runId: string;\n blockletId: string | null;\n userDid: string | null;\n sessionId: string | null;\n input: {\n task: string;\n model: string;\n tools: Array<{ path: string; ops: string[] }>;\n budget: Record<string, unknown>;\n systemPrompt?: string;\n };\n /** Ownership routing telemetry (Phase 3c). Records the derived persistence\n * class + resolved sink so observe-only migration can spot misrouted or\n * dropped runs. Absent on legacy runtimes that don't inject the capability. */\n ownership?: {\n persistenceClass: \"user\" | \"instance\" | \"ephemeral\";\n agentRunOrigin: \"interactive\" | \"system\";\n ownershipRoutingMode: \"observe-only\" | \"strict-user\" | \"strict-all\";\n instanceDid: string | null;\n sinkKind: \"afs\" | \"legacy-current-afs\" | \"none\";\n /** Why this sink was chosen — e.g. `user-direct-write`, or\n * `user-missing:instanceDid …` when observe-only fell through to legacy\n * probing. Lets migration spot misrouted runs without a drop (Phase 3e). */\n sinkReason: string;\n };\n}\n\nexport interface MessageEvent extends BaseEvent {\n type: \"message\";\n role: string;\n content: unknown;\n toolCalls?: unknown[];\n callId?: string;\n thoughts?: string;\n}\n\nexport interface TurnEvent extends BaseEvent {\n type: \"turn\";\n round: number;\n model: string | null;\n hub: string | null;\n tokensIn: number;\n tokensOut: number;\n /** Prompt tokens served from the provider's cache for this round\n * (Anthropic `cache_read_input_tokens`). 0 when caching wasn't hit\n * or wasn't reported by the provider. */\n tokensCached: number;\n cost: number;\n durationMs: number;\n status: \"ok\" | \"error\";\n errorMessage: string | null;\n}\n\nexport interface ToolEvent extends BaseEvent {\n type: \"tool\";\n round: number;\n callId: string;\n name: string;\n path: string;\n op: string;\n args: unknown;\n result: unknown;\n status: \"ok\" | \"error\";\n errorMessage: string | null;\n durationMs: number;\n}\n\nexport interface CompressEvent extends BaseEvent {\n type: \"compress\";\n round: number;\n compressed_messages: Array<Record<string, unknown>>;\n archived_count: number;\n before_tokens: number;\n after_tokens: number;\n}\n\nexport interface RunEndEvent extends BaseEvent {\n type: \"run.end\";\n runId: string;\n durationMs: number;\n status: \"ok\" | \"budget_exhausted\" | \"error\";\n result: { data: unknown; errorMessage: string | null };\n totals: {\n rounds: number;\n totalTokensIn: number;\n totalTokensOut: number;\n totalCost: number;\n modelsUsed: string[];\n hubsUsed: string[];\n toolsUsed: string[];\n };\n}\n\nexport type LogEvent =\n | RunStartEvent\n | MessageEvent\n | TurnEvent\n | ToolEvent\n | CompressEvent\n | RunEndEvent;\n\n/** A LogEvent with `seq` + `ts` deferred — emit helpers stamp those\n * monotonically. Distributes Omit across the union so each variant keeps\n * its required discriminator + payload keys at the call site. */\nexport type LogEventInput = LogEvent extends infer E\n ? E extends LogEvent\n ? Omit<E, \"seq\" | \"ts\">\n : never\n : never;\n","/**\n * Tool schema generator for agent-run.\n *\n * Converts ToolEntry[] declarations into OpenAI function-calling format.\n * One tool per unique AFS operation, with path descriptions listing allowed patterns.\n * When actionSchemas are provided, generates per-action tools with explicit typed parameters.\n */\n\nimport type { ToolEntry } from \"@aigne/afs-ash\";\n\nexport interface OpenAITool {\n type: \"function\";\n function: {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, Record<string, unknown>>;\n required: string[];\n };\n };\n}\n\n/** Discovered action schema from startup discovery phase. */\nexport interface ActionSchema {\n actionName: string;\n description: string;\n pathPattern: string;\n inputSchema?: {\n type?: string;\n properties?: Record<string, Record<string, unknown> & { type: string; description?: string }>;\n required?: string[];\n };\n}\n\ntype OpName = \"read\" | \"list\" | \"exec\" | \"search\" | \"write\" | \"delete\" | \"stat\" | \"explain\";\n\nconst OP_DEFINITIONS: Record<\n OpName,\n {\n name: string;\n description: string;\n extraProps: Record<string, { type: string; description: string; [k: string]: unknown }>;\n extraRequired: string[];\n /**\n * When true, `path` is NOT forced into the schema's `required` list.\n * Used by `write`, whose batch mode (`entries`) legitimately omits the\n * top-level `path`. Forcing `path` required there makes the model's\n * (correct) batch tool call fail client-side JSON-schema validation in\n * @aigne/model-base, which then exhausts retries and aborts the run.\n * The runtime (agent-run validateToolCall) still rejects a single write\n * that omits both `path` and `entries`, so single-write safety is kept.\n */\n pathOptional?: boolean;\n }\n> = {\n read: {\n name: \"afs_read\",\n description:\n \"Read RAW content at an AFS path. Use this ONLY when you already know the path is a data file and you want its bytes (e.g. /data/persona.md, a log). \" +\n \"DO NOT use `afs_read` to learn how something works or discover capabilities — use `afs_explain` for that; \" +\n \"`afs_explain` returns a curated guide (markdown with usage, warnings, required next steps) that raw reads omit, \" +\n \"and skipping it causes agents to miss mandatory post-mount setup and write broken workarounds.\\n\" +\n \"To read SEVERAL files (e.g. every child a list just returned), pass `entries` in ONE call \" +\n \"and OMIT `path` — never loop single reads. Batch results are per-entry: check each \" +\n \"results[i].success, partial success is normal (a missing file fails alone).\",\n extraProps: {\n entries: {\n type: \"array\",\n description:\n \"Batch mode: array of {path} entries, up to 16 per call. When provided, top-level \" +\n \"`path` is ignored. Chunk larger sets into multiple calls.\",\n items: {\n type: \"object\",\n properties: { path: { type: \"string\", description: \"AFS path to read\" } },\n required: [\"path\"],\n },\n },\n },\n extraRequired: [],\n pathOptional: true,\n },\n list: {\n name: \"afs_list\",\n description: \"List directory contents at an AFS path\",\n extraProps: {\n depth: { type: \"number\", description: \"Recursion depth (default 1)\" },\n pattern: { type: \"string\", description: \"Filter pattern, e.g. *.md\" },\n },\n extraRequired: [],\n },\n exec: {\n name: \"afs_exec\",\n description:\n \"Execute an action at an AFS path. IMPORTANT: Before calling, use afs_list on the parent path's .actions/ to discover available actions and their inputSchema, then pass the required fields in args.\",\n extraProps: {\n args: { type: \"object\", description: \"Action arguments matching the action's inputSchema\" },\n },\n extraRequired: [],\n },\n search: {\n name: \"afs_search\",\n description: \"Search for content within an AFS path\",\n extraProps: {\n query: { type: \"string\", description: \"Search query\" },\n },\n extraRequired: [\"query\"],\n },\n write: {\n name: \"afs_write\",\n description:\n \"Write content to an AFS path. Eight modes cover most cases without read-modify-write loops:\\n\" +\n \" - replace (default) — overwrite path with `content`.\\n\" +\n \" - append / prepend — add `content` at end / start of existing.\\n\" +\n \" - patch — str_replace inside existing content (legacy).\\n\" +\n \" - create / update — fail if path exists / doesn't exist.\\n\" +\n \" - tree-merge — JSON-aware: merge `content` (a JSON-stringified object) into existing JSON, preserving sibling fields. Use this to flip a single field without re-writing the rest of the object.\\n\" +\n \" - tree-toggle — flip a boolean field named by `field`. No `content` needed.\\n\" +\n \" - tree-increment — add `by` (default 1) to a number field named by `field`. No `content` needed.\\n\" +\n \"Provide `path` for a single write. For multiple files, use batch mode: pass `entries` \" +\n \"and OMIT the top-level `path` (it is ignored when `entries` is present) — never loop \" +\n \"single writes. Batch is NOT a transaction: results are per-entry, check each \" +\n \"results[i], partial success is normal.\",\n extraProps: {\n content: {\n type: \"string\",\n description:\n \"Content to write. For JSON files use a JSON-stringified object string. \" +\n \"Ignored when `entries` is provided, and unused by tree-toggle / tree-increment.\",\n },\n mode: {\n type: \"string\",\n description:\n \"Write mode. One of: replace (default), append, prepend, patch, create, update, \" +\n \"tree-merge, tree-toggle, tree-increment.\",\n },\n field: {\n type: \"string\",\n description: \"Field name on the JSON object — required for tree-toggle and tree-increment.\",\n },\n by: {\n type: \"number\",\n description: \"Increment delta for tree-increment (default 1). Negative values decrement.\",\n },\n ifMatch: {\n type: \"string\",\n description:\n \"Optimistic concurrency. Pass the opaque `version` returned by an earlier stat/read \" +\n \"to fail the write (AFS_CONFLICT) if another writer changed the file in between.\",\n },\n entries: {\n type: \"array\",\n description:\n \"Batch mode: array of {path, content, mode?} entries. When provided, top-level path/content/mode are ignored.\",\n items: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"AFS path to write to\" },\n content: { type: \"string\", description: \"Content to write\" },\n mode: { type: \"string\", description: \"Write mode (default: replace)\" },\n },\n required: [\"path\"],\n },\n },\n },\n extraRequired: [],\n pathOptional: true,\n },\n delete: {\n name: \"afs_delete\",\n description:\n \"Delete an AFS path. Two modes: (1) Single-file delete: just `path`. \" +\n \"(2) Batch delete on a directory: `path` is the directory + `where` \" +\n \"is a predicate (a JSON-stringified object) matched against each \" +\n \"child's content. Only matching children are deleted; the directory \" +\n \"itself is kept. Use this for 'sweep' operations like clearing \" +\n \"completed items in one call instead of list-then-loop.\",\n extraProps: {\n where: {\n type: \"string\",\n description:\n \"Optional. JSON-stringified predicate object. Each top-level \" +\n \"key/value pair must match an entry's content for that entry to \" +\n 'be deleted. Example: `\"{\\\\\"completed\\\\\":true}\"` deletes only ' +\n \"entries whose JSON content has completed:true. Omit for \" +\n \"single-file delete.\",\n },\n maxItems: {\n type: \"number\",\n description:\n \"Optional cap on batch delete size (server enforces an upper \" +\n \"bound). Use to limit blast radius when unsure.\",\n },\n },\n extraRequired: [],\n },\n stat: {\n name: \"afs_stat\",\n description: \"Get metadata for an AFS path\",\n extraProps: {},\n extraRequired: [],\n },\n explain: {\n name: \"afs_explain\",\n description:\n \"Get the curated guide for an AFS path. This is the DEFAULT first tool for discovery — always try this before `afs_read` or `afs_list` when investigating anything you don't already know how to use. \" +\n \"Returns markdown: what the node is, how to invoke it, required fields, warnings, next steps. \" +\n \"For providers in /registry/providers/*, the explain IS the mount guide — includes required post-mount setup (e.g. running a skill) that you MUST follow in full.\",\n extraProps: {},\n extraRequired: [],\n },\n};\n\n/**\n * Build OpenAI function-calling tools from ToolEntry declarations.\n *\n * Deduplicates operations across entries — one tool per unique op.\n * Each tool's path description lists all allowed patterns for that op.\n *\n * When actionSchemas are provided (from startup discovery), generates\n * per-action tools (afs_action_{name}) with explicit typed parameters\n * so LLMs know exactly what fields each action requires.\n */\nexport function buildToolSchema(tools: ToolEntry[], actionSchemas?: ActionSchema[]): OpenAITool[] {\n // Collect paths per operation, excluded actions, and whether ** is used\n const pathsByOp = new Map<string, string[]>();\n const excludedActionsByOp = new Map<string, string[]>();\n const maxDepthByOp = new Map<string, Map<string, number>>(); // op → (path → maxDepth)\n\n for (const entry of tools) {\n for (const op of entry.ops) {\n if (!pathsByOp.has(op)) pathsByOp.set(op, []);\n const paths = pathsByOp.get(op)!;\n if (!paths.includes(entry.path)) paths.push(entry.path);\n\n // Track maxDepth for ** patterns\n if (entry.path.includes(\"**\") && entry.maxDepth != null) {\n if (!maxDepthByOp.has(op)) maxDepthByOp.set(op, new Map());\n maxDepthByOp.get(op)!.set(entry.path, entry.maxDepth);\n }\n\n // Collect exclude_actions for exec operations\n if (op === \"exec\" && entry.exclude_actions?.length) {\n if (!excludedActionsByOp.has(op)) excludedActionsByOp.set(op, []);\n const excluded = excludedActionsByOp.get(op)!;\n for (const a of entry.exclude_actions) {\n if (!excluded.includes(a)) excluded.push(a);\n }\n }\n }\n }\n\n const result: OpenAITool[] = [];\n\n for (const [op, paths] of pathsByOp) {\n const def = OP_DEFINITIONS[op as OpName];\n if (!def) continue;\n\n const depthMap = maxDepthByOp.get(op);\n const hasDstar = paths.some((p) => p.includes(\"**\"));\n\n let pathDesc = `AFS path. Allowed: ${paths.join(\", \")}.`;\n if (hasDstar && depthMap) {\n const depthNotes = [...depthMap.entries()].map(([p, d]) => `${p} (maxDepth ${d})`).join(\", \");\n pathDesc += ` ** matches multiple levels: ${depthNotes}.`;\n }\n pathDesc += \" Note: * matches one level only (e.g. /a/* matches /a/b but NOT /a/b/c).\";\n\n // Include excluded actions in exec tool description\n const excluded = excludedActionsByOp.get(op);\n if (excluded?.length) {\n pathDesc += ` Excluded actions: ${excluded.join(\", \")}.`;\n }\n\n // Enrich afs_exec when discovered action schemas exist:\n // inject action summaries into description, make args required,\n // and give args explicit properties so LLMs fill them correctly.\n let description = def.description;\n let extraProps = def.extraProps as Record<string, Record<string, unknown>>;\n let extraRequired = def.extraRequired;\n if (op === \"exec\" && actionSchemas?.length) {\n const lines = actionSchemas.map((a) => {\n const fields = Object.entries(a.inputSchema?.properties ?? {})\n .map(([k, v]) => {\n const req = a.inputSchema?.required?.includes(k) ? \" (required)\" : \"\";\n let typeStr = v.type ?? \"string\";\n // For complex types, add brief structure hint\n if (typeStr === \"object\" && v.additionalProperties) typeStr = \"object (map)\";\n if (typeStr === \"array\" && v.items) typeStr = \"array\";\n return `${k}: ${typeStr}${req}`;\n })\n .join(\", \");\n return `- ${a.pathPattern}: {${fields || \"none\"}} — ${a.description}`;\n });\n description =\n \"Execute an action. Pass the action's parameters in args.\\n\" +\n `Available actions:\\n${lines.join(\"\\n\")}`;\n // args is required so LLMs always pass action parameters explicitly,\n // but nullable to tolerate smaller models (e.g. Haiku) returning args:null\n // for actions that have no parameters.\n extraRequired = [\"args\"];\n\n // Merge all action schemas' properties into args so LLMs see\n // the actual parameter structure, not just an opaque object.\n // Note: do NOT merge required fields — different actions have different\n // required fields. The per-action descriptions indicate which fields are required.\n const mergedProps: Record<string, Record<string, unknown>> = {};\n for (const a of actionSchemas) {\n if (a.inputSchema?.properties) {\n for (const [k, v] of Object.entries(a.inputSchema.properties)) {\n // Preserve full property schema (nested objects, arrays, etc.)\n mergedProps[k] = { ...v, type: v.type ?? \"string\" };\n }\n }\n }\n\n extraProps = {\n args: {\n type: [\"object\", \"null\"],\n description: \"Action arguments matching the action's inputSchema\",\n ...(Object.keys(mergedProps).length > 0 ? { properties: mergedProps } : {}),\n },\n };\n }\n\n result.push({\n type: \"function\",\n function: {\n name: def.name,\n description,\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: pathDesc },\n ...extraProps,\n },\n required: def.pathOptional ? [...extraRequired] : [\"path\", ...extraRequired],\n },\n },\n });\n }\n\n return result;\n}\n","/**\n * Agent-run loop for ASH provider.\n *\n * Combines LLM inference (via AigneHub), tool_call validation (path-validator),\n * ASH execution (for read/list/exec), and direct AFS calls (for search/write/stat/explain)\n * into a multi-round agentic loop.\n */\n\nimport type { AFSExecResult } from \"@aigne/afs\";\nimport { makeNsLog } from \"@aigne/afs\";\nimport { type ToolEntry, validateToolCall } from \"@aigne/afs-ash\";\nimport { parseSkillFrontmatter as parseSkillFrontmatterShared } from \"@aigne/afs-skills/format\";\nimport { joinURL } from \"ufo\";\nimport { generateAsh, type ValidatedToolCall } from \"./ash-generator.js\";\nimport { buildContext, type ContextMemoryOptions } from \"./context.js\";\nimport { maybeCompress } from \"./context-compress.js\";\nimport {\n FIELD_LIMIT,\n type LogEvent,\n type LogEventInput,\n stripInternalFields,\n truncateField,\n} from \"./observability.js\";\nimport { type ActionSchema, buildToolSchema } from \"./tool-schema.js\";\n\nconst log = makeNsLog(\"provider:agent\");\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface AgentRunParams {\n task: string;\n model: string;\n tools: ToolEntry[];\n budget?: {\n max_rounds?: number;\n actions_per_round?: number;\n total_tokens?: number;\n /** Model context window size (tokens). Used for compression threshold. */\n context_window?: number;\n /** Max LLM call retry attempts on transient failures (default 3). */\n max_retries?: number;\n };\n system?: string;\n session?: string;\n /** Skill directories to scan for SKILL.md files (e.g. [\"/program/skills\", \"/data/skills\"]) */\n skillPaths?: string[];\n /** Constrain LLM tool selection. \"auto\" (default) | \"none\" | \"required\" | <tool-name>.\n * Mirrors aigne-framework's Router pattern; passed verbatim to the LLM. */\n toolChoice?: string;\n /** Extra args forwarded verbatim to every `callLLM` invocation. Used to pass\n * AI Device routing hints (policy, requirements, exclusions, session, etc.)\n * through to `/dev/ai/.actions/chat` without baking that vocabulary into\n * agent-run itself. Keys collide-last with ash's own llmArgs (messages,\n * tools, toolChoice, responseFormat, _onChunk) — those can't be overridden. */\n modelArgs?: Record<string, unknown>;\n /** AFS exec path (or { path, ...extraArgs }) for sending intermediate progress messages. */\n onProgress?: string | { path: string; [key: string]: unknown };\n /** In-process callback fired after each tool call with structured progress data. */\n onToolProgress?: (event: ToolProgressEvent) => void;\n /** AFS path to a JSON Schema file. When set, a `respond` tool is injected and the LLM's\n * structured call to it becomes the result (as an object instead of a string). */\n responseSchema?: string;\n /** Shared execution context automatically merged into nested `args` of every exec tool call.\n * Provides defaults for downstream actions (e.g. scheduler dispatch) without requiring\n * the LLM to copy caller context manually. LLM-provided values always take priority. */\n execContext?: Record<string, unknown>;\n /** Parent session ID — when set, this run is a child of the given session.\n * Used for session hierarchy derivation (S3). */\n parentSession?: string;\n /** Spawn chain — list of ancestor session IDs from root to current.\n * Used for depth enforcement (S3). */\n chain?: string[];\n /** Parent proc ID from the calling blocklet — registers this run as a child of that proc. */\n parentProcId?: string;\n /** Parent agent info for template `$parent` variable (S4). */\n parentAgentInfo?: { name: string; type: string; session: string };\n /** Abort signal from parent budget tracker. Checked at the start of each round;\n * when aborted, the loop returns immediately preserving completed work. (S11) */\n abortSignal?: AbortSignal;\n /** When true, suppress the built-in AFS Discovery Protocol hint (which tells\n * the LLM to \"Start with `read /.knowledge`\"). Use this for narrow-scope\n * agents whose system prompt already specifies exact paths to read — the\n * generic /.knowledge advice wastes rounds exploring the framework instead\n * of following the agent's own instructions. */\n skipAfsHint?: boolean;\n /** Memory configuration. When set, recall is injected into the system message and\n * memory tools are exposed to the LLM for active memory operations. */\n memory?: {\n /** AFS exec path for recall (e.g. \"/modules/memory/.actions/recall\"). */\n recallPath: string;\n /** Max tokens for memory injection into system message. Default: 2000. */\n maxTokens?: number;\n /** Domain filter passed to recall. */\n domain?: string;\n /** AFS path pattern for memory tools (e.g. \"/modules/memory/.actions/*\").\n * When set, memory actions (recall, remember, boost, feedback) are exposed as tools. */\n toolsPath?: string;\n /** AFS exec path for session archive (e.g. \"/modules/memory/.actions/archive\").\n * When set, the conversation is archived to memory on completion. */\n archivePath?: string;\n };\n /** Index configuration. When `scope` is set, agent-run auto-grants\n * list+read on `/<mount-root>/domains/<scope>` so the agent can\n * observe what's indexed (parallel to the memory.domain auto-grant).\n * Mount root is derived from `queryPath` by stripping `/.actions/query`. */\n index?: {\n /** AFS exec path for query (e.g. \"/modules/index/.actions/query\"). */\n queryPath: string;\n /** Domain/scope for inspection grants. Without this, no auto-grant fires. */\n scope?: string;\n };\n}\n\nexport interface ToolProgressEvent {\n type:\n | \"tool_start\"\n | \"tool_result\"\n | \"thinking\"\n | \"llm_start\"\n | \"llm_result\"\n | \"llm_delta\"\n | \"thinking_delta\"\n | \"summary\"\n | \"warning\"\n | \"compress_start\"\n | \"compress_result\"\n | \"subAgentMetadata\";\n round: number;\n /** Nesting depth: 0 = root, 1 = child, 2 = grandchild, etc. (S9) */\n depth: number;\n /** Ancestor session chain from root to current run. (S9) */\n chain: string[];\n /** For tool_start/tool_result: array of tool calls in this batch. */\n calls?: Array<{\n id: string;\n tool: string;\n path: string;\n status: \"pending\" | \"ok\" | \"error\";\n error?: string;\n args?: Record<string, unknown>;\n result?: string;\n }>;\n /** For thinking: LLM's intermediate text. */\n text?: string;\n /** Resolved model name (llm_start, llm_result, summary). */\n model?: string;\n /** Retry attempt number, 1-based (llm_result on failure). */\n attempt?: number;\n /** Max retry attempts (llm_result). */\n maxAttempts?: number;\n /** Error message on LLM retry failure (llm_result). */\n llmError?: string;\n /** Delay before the next retry in milliseconds (llm_result on retryable failure). */\n retryDelayMs?: number;\n /** Accumulated token/cost totals (summary). */\n tokens?: { input: number; output: number; cached?: number; cost?: number };\n /** Context compression stats (compress_start, compress_result). */\n compress?: {\n phase: \"triggered\" | \"summarizing\" | \"done\" | \"failed\";\n beforeTokens: number;\n contextWindow: number;\n compressedMessages: number;\n keptMessages: number;\n afterTokens?: number;\n error?: string;\n };\n /** Sub-agent metadata extracted from child .actions/run result (subAgentMetadata). */\n subAgentMeta?: Record<string, unknown>;\n}\n\nexport interface TraceEntry {\n round: number;\n tool_calls: Array<{\n id: string;\n name: string;\n path: string;\n status: \"ok\" | \"error\" | \"circuit_breaker\";\n error?: string;\n }>;\n tokens: { input: number; output: number };\n}\n\nexport interface AgentRunResult {\n status: \"completed\" | \"budget_exhausted\" | \"error\";\n result?: string | Record<string, unknown>;\n error?: string;\n /** Detailed diagnostics when status is \"error\" (request summary + last response). */\n detail?: { request?: unknown; lastResponse?: unknown };\n rounds: number;\n total_actions: number;\n total_tokens: number;\n /** B4 — count of successful nested .actions/run dispatches from this run. */\n sub_runs: number;\n trace: TraceEntry[];\n /** Final accumulator snapshot (rounds, tokens, cost, models/hubs/tools used).\n * Used by orchestration.ts to populate run.end event totals. */\n totals?: TotalsSnapshot;\n}\n\nexport interface TotalsSnapshot {\n rounds: number;\n totalTokensIn: number;\n totalTokensOut: number;\n /** Sum of `usage.cacheReadInputTokens` across all rounds. Reflects how\n * many prompt tokens were served from cache (Anthropic/etc. discount\n * these). Surfaced in run.end totals so observability can show \"X cache\n * tokens reused\" without re-walking turn events. */\n totalCachedTokens: number;\n totalCost: number;\n modelsUsed: string[];\n hubsUsed: string[];\n toolsUsed: string[];\n}\n\n/** Message types for JSONL history (OpenAI canonical snake_case format) */\nexport interface HistoryToolCall {\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n}\n\nexport type HistoryMessage =\n | { role: \"user\"; content: string; createdAt?: string }\n | {\n role: \"assistant\";\n content: string;\n tool_calls?: HistoryToolCall[];\n createdAt?: string;\n durationMs?: number;\n }\n | {\n role: \"tool\";\n tool_call_id: string;\n content: string | unknown[];\n createdAt?: string;\n durationMs?: number;\n };\n\nexport interface AgentRunDeps {\n callLLM: (args: Record<string, unknown>) => Promise<AFSExecResult>;\n runAsh: (source: string, args: Record<string, unknown>) => Promise<AFSExecResult>;\n callAFS: (op: string, path: string, args?: Record<string, unknown>) => Promise<AFSExecResult>;\n /** Test seam for retry backoff; production uses abort-aware setTimeout. */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n loadHistory?: (sessionPath: string) => Promise<HistoryMessage[]>;\n /** Append new messages to working history (history.jsonl). */\n appendHistory?: (sessionPath: string, messages: HistoryMessage[]) => Promise<void>;\n /** Rewrite working history with compressed messages (called only on compression). */\n rewriteHistory?: (sessionPath: string, messages: HistoryMessage[]) => Promise<void>;\n /** Archive compressed messages to a timestamped file (called only on compression). */\n archiveHistory?: (sessionPath: string, messages: HistoryMessage[]) => Promise<void>;\n /** Observability: emit a single jsonl event to the run's log file.\n * Provided by orchestration.ts; absent when no log destination is wired up\n * (e.g. CLI direct call without `_scope_afs`). */\n emit?: (event: LogEvent) => Promise<void>;\n /** Observability: per-run monotonic seq counter. Owned by orchestration.ts. */\n nextSeq?: () => number;\n}\n\n/** Internal per-run accumulator. Snapshot exposed via `AgentRunResult.totals`. */\ninterface TotalsAccumulator {\n rounds: number;\n totalTokensIn: number;\n totalTokensOut: number;\n totalCachedTokens: number;\n totalCost: number;\n modelsUsed: Set<string>;\n hubsUsed: Set<string>;\n toolsUsed: Set<string>;\n}\n\n// ─── Constants ──────────────────────────────────────────────────────────────\n\nconst DEFAULT_MAX_ROUNDS = 20;\nconst DEFAULT_ACTIONS_PER_ROUND = 10;\nconst RESULTS_PREFIX = \"/.results/\";\n\n/** Circuit breaker: trip after N consecutive identical tool calls. */\nconst CIRCUIT_BREAKER_THRESHOLD = 3;\n\n/**\n * Default max output tokens per LLM call. Without this the gateway applies a\n * conservative per-model default (~8k) — observed truncating a full article's\n * `content` arg mid-sentence inside a cms-write tool call, after which the model\n * re-emitted the same truncated call until the circuit breaker blocked recovery.\n * We ask high so long content (article body + reasoning, or a whole doc page)\n * has ample headroom; AI Device clamps this down to each routed model's real\n * `maxOutputTokens` (see applyMaxOutputBudget in execution/forward.ts), so a\n * model that supports less never receives an over-limit request. Only a default\n * — a caller-supplied max_tokens always wins.\n */\nconst DEFAULT_MAX_OUTPUT_TOKENS = 32768;\n\n/** LLM call retry defaults. Non-rate-limit retries keep the historical linear delay. */\nconst DEFAULT_MAX_RETRIES = 3;\nconst LLM_RETRY_DELAY_MS = 1000;\nconst LLM_RETRY_MAX_MS = 5000;\nconst LLM_RATE_LIMIT_RETRY_BASE_MS = 5000;\nconst LLM_RATE_LIMIT_RETRY_MAX_MS = 30000;\n\n/** Timeout for a single LLM call (5 minutes). Prevents session lock from hanging forever. */\nconst LLM_CALL_TIMEOUT_MS = 5 * 60 * 1000;\n\n/** Default context window size when not provided by model metadata. */\nconst DEFAULT_CONTEXT_WINDOW = 80_000;\n\n/** Maximum serialized size for chain array in progress events (bytes). */\nconst MAX_CHAIN_JSON_SIZE = 1024;\n\n// ─── Progress Nesting (S9) ─────────────────────────────────────────────────\n\n/**\n * Compute sanitized depth and chain for progress event stamping.\n *\n * - Filters non-string entries from the chain\n * - Strips path traversal characters\n * - If no chain provided, builds [session] (or [] if no session)\n * - Truncates chain if serialized JSON exceeds MAX_CHAIN_JSON_SIZE\n * - depth = max(0, chain.length - 1)\n */\nfunction computeProgressNesting(params: {\n session?: string;\n chain?: string[];\n parentSession?: string;\n}): {\n depth: number;\n chain: string[];\n} {\n let chain: string[];\n\n if (params.chain && params.chain.length > 0) {\n const filtered = params.chain.filter((s): s is string => typeof s === \"string\");\n if (filtered.length !== params.chain.length) {\n log.warn(\"[agent-run] chain contains non-string elements, filtered out\");\n }\n chain = filtered.map((s) => s.replace(/\\.\\.\\//g, \"\").replace(/\\.\\.\\\\/g, \"\"));\n } else if (params.session) {\n if (params.parentSession && !params.chain) {\n log.warn(\"[agent-run] parentSession set but chain missing, defaulting depth to 0\");\n }\n chain = [params.session];\n } else {\n chain = [];\n }\n\n // Truncate chain if serialized size exceeds cap\n while (chain.length > 1 && JSON.stringify(chain).length > MAX_CHAIN_JSON_SIZE) {\n chain = [chain[0]!, ...chain.slice(2)];\n }\n // If even a single entry exceeds cap, truncate it\n if (chain.length === 1 && JSON.stringify(chain).length > MAX_CHAIN_JSON_SIZE) {\n chain = [chain[0]!.slice(0, MAX_CHAIN_JSON_SIZE - 10)];\n }\n\n const depth = Math.max(0, chain.length - 1);\n return { depth, chain };\n}\n\nfunction isSubAgentRunPath(path: string): boolean {\n return path.endsWith(\"/.actions/run\") || path.endsWith(\"/.actions/agent-run\");\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────────\n\n/**\n * Operations routed through ASH (deterministic sandbox).\n *\n * Currently empty: all ops go through direct AFS calls.\n * agent-run's security comes from path-validator (tools declaration whitelist),\n * not from ASH @caps. The ASH sandbox is valuable for user-written scripts\n * (/.actions/run) but redundant for agent-run's auto-generated single-step execs.\n */\nconst ASH_OPS = new Set<string>([]);\n\nconst RATE_LIMIT_ERROR_RE =\n /\\b429\\b|RESOURCE_EXHAUSTED|Too Many Requests|rate[-\\s]?limit|quota exceeded|quota has been exceeded/i;\n\nfunction clampDelayMs(ms: number, maxMs: number): number {\n if (!Number.isFinite(ms) || ms <= 0) return 0;\n return Math.min(Math.ceil(ms), maxMs);\n}\n\nfunction parseRetryAfterMs(error: string): number | undefined {\n const retryAfter = error.match(\n /retry[-_\\s]?after[\"']?\\s*[:=]?\\s*[\"']?(\\d+(?:\\.\\d+)?)\\s*(ms|milliseconds?|s|sec|seconds?|m|minutes?)?/i,\n );\n const tryAgainIn = error.match(\n /try again (?:later,?\\s*)?in\\s+(\\d+(?:\\.\\d+)?)\\s*(ms|milliseconds?|s|sec|seconds?|m|minutes?)/i,\n );\n const match = retryAfter ?? tryAgainIn;\n if (!match) return undefined;\n const value = Number(match[1]);\n if (!Number.isFinite(value) || value <= 0) return undefined;\n const unit = match[2]?.toLowerCase();\n if (unit?.startsWith(\"m\") && unit !== \"ms\" && !unit.startsWith(\"millisecond\")) {\n return value * 60_000;\n }\n if (!unit || unit.startsWith(\"s\")) return value * 1000;\n return value;\n}\n\nexport function computeLLMRetryDelayMs(error: string, failedAttempt: number): number {\n const attempt = Math.max(1, failedAttempt);\n const retryAfterMs = parseRetryAfterMs(error);\n if (retryAfterMs !== undefined) {\n return clampDelayMs(retryAfterMs, LLM_RATE_LIMIT_RETRY_MAX_MS);\n }\n if (RATE_LIMIT_ERROR_RE.test(error)) {\n return clampDelayMs(\n LLM_RATE_LIMIT_RETRY_BASE_MS * 2 ** (attempt - 1),\n LLM_RATE_LIMIT_RETRY_MAX_MS,\n );\n }\n return clampDelayMs(LLM_RETRY_DELAY_MS * attempt, LLM_RETRY_MAX_MS);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return Promise.resolve();\n if (signal?.aborted) return Promise.reject(new Error(\"Cancelled\"));\n return new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout>;\n const cleanup = () => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const onResolve = () => {\n cleanup();\n resolve();\n };\n const onAbort = () => {\n cleanup();\n reject(new Error(\"Cancelled\"));\n };\n timer = setTimeout(onResolve, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** Required arguments per operation (beyond path) */\nconst REQUIRED_ARGS: Record<string, string[]> = {\n search: [\"query\"],\n // write: content is required for single mode, but entries replaces it in batch mode.\n // Validation is handled in callAFS, not here.\n};\n\n/** Map tool function name → AFS operation name */\nfunction toolNameToOp(name: string): string | undefined {\n // Per-action tools (afs_action_send, afs_action_do_thing, etc.) → exec\n if (name.startsWith(\"afs_action_\")) return \"exec\";\n\n const map: Record<string, string> = {\n afs_read: \"read\",\n afs_list: \"list\",\n afs_exec: \"exec\",\n afs_search: \"search\",\n afs_write: \"write\",\n afs_delete: \"delete\",\n afs_stat: \"stat\",\n afs_explain: \"explain\",\n };\n return map[name];\n}\n\ninterface ToolCallInput {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n}\n\n/** JSON.stringify with sorted keys for deterministic comparison of tool call args. */\nfunction stableStringify(obj: Record<string, unknown>): string {\n return JSON.stringify(obj, Object.keys(obj).sort());\n}\n\n/** Truncate a result string for progress events. */\nfunction truncateResult(s: string | undefined, max: number): string | undefined {\n if (!s) return undefined;\n return s.length > max ? `${s.slice(0, max)}...` : s;\n}\n\n/**\n * Normalize a tool call from any format to our internal ToolCallInput.\n *\n * AigneHub returns OpenAI format:\n * { id, type: \"function\", function: { name, arguments } }\n * Some SDKs return Vercel AI SDK format:\n * { toolCallId, toolName, args }\n */\nfunction normalizeToolCall(tc: Record<string, unknown>): ToolCallInput {\n // Vercel AI SDK format\n if (tc.toolCallId && tc.toolName) {\n return {\n toolCallId: tc.toolCallId as string,\n toolName: tc.toolName as string,\n args: (tc.args as Record<string, unknown>) ?? {},\n };\n }\n\n // OpenAI format: { id, function: { name, arguments } }\n const fn = tc.function as Record<string, unknown> | undefined;\n const rawArgs = fn?.arguments;\n let args: Record<string, unknown> = {};\n if (typeof rawArgs === \"string\") {\n try {\n args = JSON.parse(rawArgs);\n } catch {\n args = { _parseError: `Invalid JSON in function arguments: ${rawArgs.slice(0, 200)}` };\n }\n } else if (rawArgs && typeof rawArgs === \"object\") {\n args = rawArgs as Record<string, unknown>;\n }\n\n return {\n toolCallId: (tc.toolCallId ?? tc.id ?? \"\") as string,\n toolName: (tc.toolName ?? fn?.name ?? \"\") as string,\n args,\n };\n}\n\n/**\n * Map AFS operation to a glyph a human scans faster than a word.\n * `afs_action_<name>` (per-action sugar) and any other non-standard tool\n * name collapse to the generic exec ⚡.\n */\nconst OP_EMOJI: Record<string, string> = {\n read: \"📖\",\n write: \"✍️\",\n edit: \"✏️\",\n list: \"📋\",\n stat: \"ℹ️\",\n explain: \"💡\",\n search: \"🔎\",\n exec: \"⚡\",\n delete: \"🗑\",\n};\n\nfunction toolNameToEmoji(toolName: string): string {\n if (toolName.startsWith(\"afs_action_\")) return OP_EMOJI.exec!;\n const op = toolName.replace(/^afs_/, \"\");\n return OP_EMOJI[op] ?? \"🔧\";\n}\n\n/**\n * Render a round's tool calls + outcomes as a user-facing one-line-per-call\n * summary. Used by the onProgress payload so the progress surface (Telegram\n * live-progress, web UI tail, etc.) shows each AFS operation the agent ran\n * and whether it succeeded.\n *\n * Output per call: `<emoji> <path> <status>`, e.g.\n * 📖 /x/me ✓\n * 📋 /x/me/tweets ✓\n * ⚡ /x/.actions/search ✗\n *\n * Status glyphs:\n * ✓ — tool executed successfully\n * ✗ — tool errored (validation, runtime, permission)\n * ⊘ — circuit breaker tripped (same call repeated too many times)\n *\n * Falls back to `🔧` for tools outside the standard AFS op set.\n */\nfunction summarizeToolCalls(\n roundCalls: ReadonlyArray<ToolCallInput>,\n traceEntries: ReadonlyArray<{ id: string; status: \"ok\" | \"error\" | \"circuit_breaker\" }>,\n errorResults: ReadonlyArray<{ id: string; error: string }>,\n): string {\n const traceById = new Map(traceEntries.map((t) => [t.id, t]));\n const errorIds = new Set(errorResults.map((e) => e.id));\n\n return roundCalls\n .map((call) => {\n const emoji = toolNameToEmoji(call.toolName);\n const path = String(call.args.path ?? \"\");\n const trace = traceById.get(call.toolCallId);\n // errorResults wins over trace (validation failures populate errorResults\n // before traceEntries gets an \"ok\" stamp in some branches)\n let status: string;\n if (errorIds.has(call.toolCallId)) {\n status = \"✗\";\n } else if (trace?.status === \"circuit_breaker\") {\n status = \"⊘\";\n } else if (trace?.status === \"error\") {\n status = \"✗\";\n } else {\n status = \"✓\";\n }\n return path ? `${emoji} ${path} ${status}` : `${emoji} ${status}`;\n })\n .join(\"\\n\");\n}\n\n/**\n * Fix path for per-action tool calls.\n *\n * LLMs often make mistakes with per-action tools:\n * 1. Put tool name in path: /.actions/afs_action_send → /.actions/send\n * 2. Drop mount prefix: /default/conversations/123 → /telegram/default/conversations/123\n *\n * Uses discovered pathPattern to auto-correct missing mount prefixes.\n * Mutates call.args.path in place.\n */\nfunction fixPerActionPath(call: ToolCallInput, schemasByAction: Map<string, ActionSchema>): void {\n const path = call.args.path as string | undefined;\n if (!path) return;\n\n // Extract real action name: afs_action_send → send, afs_action_do_thing → do-thing\n const rawName = call.toolName.slice(\"afs_action_\".length);\n const realName = rawName.replace(/_/g, \"-\");\n\n // Fix action name in path\n const marker = \"/.actions/\";\n const idx = path.lastIndexOf(marker);\n if (idx !== -1) {\n const currentAction = path.slice(idx + marker.length).split(\"/\")[0];\n if (currentAction && currentAction !== realName) {\n call.args.path = path.slice(0, idx) + marker + realName;\n }\n }\n\n // Fix missing mount prefix using discovered pathPattern\n const schema = schemasByAction.get(realName);\n if (!schema?.pathPattern) return;\n\n const fixedPath = call.args.path as string;\n const starIdx = schema.pathPattern.indexOf(\"*\");\n if (starIdx === -1) return;\n\n const expectedPrefix = schema.pathPattern.slice(0, starIdx);\n if (fixedPath.startsWith(expectedPrefix)) return; // Already correct\n\n // Try to find the missing prefix: check if LLM's path is a suffix of the full path\n // e.g., expectedPrefix = \"/telegram/default/conversations/\"\n // fixedPath starts with \"/default/conversations/\" → missing \"/telegram\"\n for (let i = 1; i < expectedPrefix.length; i++) {\n if (expectedPrefix[i] === \"/\" && fixedPath.startsWith(expectedPrefix.slice(i))) {\n call.args.path = expectedPrefix.slice(0, i) + fixedPath;\n return;\n }\n }\n}\n\n/** Extract exec args from tool call: try nested `args` field first, fall back to all fields except `path`. */\nfunction extractExecArgs(callArgs: Record<string, unknown>): Record<string, unknown> {\n if (callArgs.args && typeof callArgs.args === \"object\" && !Array.isArray(callArgs.args)) {\n return callArgs.args as Record<string, unknown>;\n }\n const { path: _, ...rest } = callArgs;\n return rest;\n}\n\n// ─── Action Discovery ───────────────────────────────────────────────────────\n\n/**\n * Discover available actions and their inputSchemas at startup.\n *\n * Strategy (per exec-capable tool entry):\n * 1. Instance-probe: list basePath to find a child, then list its .actions/\n * 2. Capabilities fallback: walk up path hierarchy to find /.meta/.capabilities,\n * extract action schemas from the manifest's catalog entries\n *\n * Results are used to generate per-action tools with explicit typed parameters.\n * Best-effort: failures are silently ignored and the generic afs_exec fallback remains.\n */\nasync function discoverActionSchemas(\n tools: ToolEntry[],\n deps: AgentRunDeps,\n): Promise<ActionSchema[]> {\n const schemas: ActionSchema[] = [];\n const discoveredPaths = new Set<string>();\n const candidates: Array<{ tool: ToolEntry; basePath: string }> = [];\n\n for (const tool of tools) {\n if (!tool.ops.includes(\"exec\")) continue;\n\n // Strip trailing glob: /foo/bar/* → /foo/bar, /foo/** → /foo\n const basePath = tool.path.replace(/\\/?\\*+$/, \"\");\n if (!basePath || discoveredPaths.has(basePath)) continue;\n discoveredPaths.add(basePath);\n candidates.push({ tool, basePath });\n }\n\n const discovered = await Promise.all(\n candidates.map(async ({ tool, basePath }) => {\n const toolSchemas: ActionSchema[] = [];\n const toolActions = new Set<string>();\n\n try {\n // Fast path: tool path already targets .actions/ — list it directly\n if (basePath.endsWith(\"/.actions\")) {\n await discoverFromActionsDir(tool, basePath, toolActions, toolSchemas, deps);\n return toolSchemas;\n }\n\n // Strategy 1: Instance-probe — list basePath to find a child's .actions/\n const found = await discoverViaInstanceProbe(\n tool,\n basePath,\n toolActions,\n toolSchemas,\n deps,\n );\n\n // Strategy 2: Capabilities fallback — read /.meta/.capabilities from mount root\n if (!found) {\n await discoverViaCapabilities(tool, basePath, toolActions, toolSchemas, deps);\n }\n } catch {\n // Discovery is best-effort — continue with generic afs_exec\n }\n\n return toolSchemas;\n }),\n );\n\n const discoveredActions = new Set<string>();\n for (const toolSchemas of discovered) {\n for (const schema of toolSchemas) {\n if (discoveredActions.has(schema.actionName)) continue;\n discoveredActions.add(schema.actionName);\n schemas.push(schema);\n }\n }\n\n return schemas;\n}\n\n/** Fast path: tool path already ends with /.actions/* — list the directory directly. */\nasync function discoverFromActionsDir(\n tool: ToolEntry,\n actionsPath: string,\n discoveredActions: Set<string>,\n schemas: ActionSchema[],\n deps: AgentRunDeps,\n): Promise<void> {\n const result = await deps.callAFS(\"list\", actionsPath);\n if (!result.success) return;\n\n const actions = extractEntries(result.data);\n for (const action of actions) {\n const name = extractActionNameFromEntry(action);\n if (!name || discoveredActions.has(name)) continue;\n discoveredActions.add(name);\n\n schemas.push({\n actionName: name,\n description: action.meta?.description || `Execute ${name}`,\n pathPattern: `${tool.path.replace(/\\*+$/, name)}`,\n inputSchema: action.meta?.inputSchema,\n });\n }\n}\n\n/** Strategy 1: list basePath, pick first child, list its .actions/ */\nasync function discoverViaInstanceProbe(\n tool: ToolEntry,\n basePath: string,\n discoveredActions: Set<string>,\n schemas: ActionSchema[],\n deps: AgentRunDeps,\n): Promise<boolean> {\n const listResult = await deps.callAFS(\"list\", basePath);\n if (!listResult.success) return false;\n\n const entries = extractEntries(listResult.data);\n if (entries.length === 0) return false;\n\n // Check for MCP tools: entries with meta.kind === \"mcp:tool\" are directly executable\n // and carry their own inputSchema — no need to probe .actions/\n const mcpTools = entries.filter(\n (e) => e.meta?.kind === \"mcp:tool\" || e.meta?.kinds?.includes?.(\"mcp:tool\"),\n );\n if (mcpTools.length > 0) {\n let found = false;\n for (const mcpTool of mcpTools) {\n const name = mcpTool.meta?.mcp?.name || extractActionNameFromEntry(mcpTool);\n if (!name || discoveredActions.has(name)) continue;\n discoveredActions.add(name);\n found = true;\n\n const toolPath = mcpTool.path || `${basePath}/${name}`;\n schemas.push({\n actionName: name,\n description: mcpTool.meta?.description || `Execute ${name}`,\n pathPattern: toolPath,\n inputSchema: mcpTool.meta?.inputSchema,\n });\n }\n return found;\n }\n\n const firstChild = entries[0]!;\n const childPath = firstChild.path || firstChild.id;\n if (!childPath) return false;\n\n const actionsPath = `${childPath}/.actions`;\n const actionsResult = await deps.callAFS(\"list\", actionsPath);\n if (!actionsResult.success) return false;\n\n const actions = extractEntries(actionsResult.data);\n let found = false;\n for (const action of actions) {\n const name = extractActionNameFromEntry(action);\n if (!name || discoveredActions.has(name)) continue;\n discoveredActions.add(name);\n found = true;\n\n schemas.push({\n actionName: name,\n description: action.meta?.description || `Execute ${name}`,\n pathPattern: `${tool.path}/.actions/${name}`,\n inputSchema: action.meta?.inputSchema,\n });\n }\n return found;\n}\n\n/**\n * Strategy 2: walk up path hierarchy to find a provider's /.meta/.capabilities,\n * then extract action schemas from the manifest's catalog + inputSchema.\n *\n * For a tool path like /telegram/default/conversations/*, tries:\n * /telegram/default/conversations/.meta/.capabilities\n * /telegram/default/.meta/.capabilities\n * /telegram/.meta/.capabilities\n */\nasync function discoverViaCapabilities(\n tool: ToolEntry,\n basePath: string,\n discoveredActions: Set<string>,\n schemas: ActionSchema[],\n deps: AgentRunDeps,\n): Promise<boolean> {\n // Walk up path segments\n const segments = basePath.split(\"/\").filter(Boolean);\n\n for (let depth = segments.length; depth >= 1; depth--) {\n const ancestorPath = `/${segments.slice(0, depth).join(\"/\")}`;\n const capsPath = `${ancestorPath}/.meta/.capabilities`;\n\n try {\n const result = await deps.callAFS(\"read\", capsPath);\n if (!result.success) continue;\n\n const content = extractCapabilitiesContent(result.data);\n if (!content?.actions) continue;\n\n let found = false;\n for (const actionGroup of content.actions) {\n const catalog = actionGroup.catalog;\n if (!Array.isArray(catalog)) continue;\n\n for (const entry of catalog) {\n const name = entry.name;\n if (!name || discoveredActions.has(name)) continue;\n discoveredActions.add(name);\n found = true;\n\n schemas.push({\n actionName: name,\n description: entry.description || `Execute ${name}`,\n pathPattern: `${tool.path}/.actions/${name}`,\n inputSchema: entry.inputSchema,\n });\n }\n }\n if (found) return true;\n } catch {\n // Discovery is best-effort — try next ancestor\n }\n }\n return false;\n}\n\n/** Extract capabilities content from a read result (may be nested in data.content or data directly). */\nfunction extractCapabilitiesContent(\n data: unknown,\n): { actions?: Array<{ catalog?: Array<Record<string, any>> }> } | null {\n if (!data || typeof data !== \"object\") return null;\n const d = data as Record<string, any>;\n // Direct content\n if (d.actions) return d as any;\n // Nested in content field\n if (d.content && typeof d.content === \"object\" && (d.content as any).actions) {\n return d.content as any;\n }\n return null;\n}\n\n/** Extract entries array from callAFS response data (may be raw array or wrapped). */\nfunction extractEntries(data: unknown): Array<Record<string, any>> {\n if (Array.isArray(data)) return data;\n if (data && typeof data === \"object\" && Array.isArray((data as any).data)) {\n return (data as any).data;\n }\n return [];\n}\n\n/** Tolerant extraction of text content from a callAFS(\"read\") result's data. */\nfunction extractReadContent(data: unknown): string | undefined {\n if (typeof data === \"string\") return data;\n if (data && typeof data === \"object\") {\n const d = data as Record<string, any>;\n if (typeof d.content === \"string\") return d.content;\n if (typeof d.data === \"string\") return d.data;\n if (d.data && typeof d.data === \"object\" && typeof d.data.content === \"string\") {\n return d.data.content;\n }\n }\n return undefined;\n}\n\n/** Parse `name` + `description` from a SKILL.md frontmatter block. Delegates to\n * the canonical parser in `@aigne/afs-skills/format` (single source of truth)\n * and preserves this module's `null`-when-empty contract for its callers. */\nfunction parseSkillFrontmatter(md: string): { name?: string; description?: string } | null {\n const fm = parseSkillFrontmatterShared(md);\n if (Object.keys(fm).length === 0) return null;\n return { name: fm.name, description: fm.description };\n}\n\n/**\n * Build a compact skill catalog from the agent's skill roots, read at startup\n * (server-side) so the LLM does NOT spend discovery rounds listing roots and\n * reading every SKILL.md just to learn what exists. Each skill's `name` +\n * `description` come from its SKILL.md frontmatter; the agent then reads the\n * full SKILL.md only for the one skill it decides to use.\n *\n * Bounded: scans at most 2 levels deep and caps the catalog size, so the\n * injected prompt stays small no matter how many skills are mounted. All AFS\n * access is best-effort — a failing root/skill is skipped, never fatal.\n */\nasync function buildSkillCatalog(\n skillPaths: string[] | undefined,\n deps: AgentRunDeps,\n): Promise<string | undefined> {\n if (!skillPaths || skillPaths.length === 0) return undefined;\n const MAX_SKILLS = 40;\n const DESC_MAX = 220;\n const entries: Array<{ name: string; description: string; path: string }> = [];\n const seen = new Set<string>();\n\n /** Try `<dir>/SKILL.md`; on success record the skill. Returns true if a\n * SKILL.md was found (so the caller does not descend into a leaf dir). */\n const tryLeaf = async (dirPath: string): Promise<boolean> => {\n const skillFile = `${dirPath}/SKILL.md`;\n let res: AFSExecResult;\n try {\n res = await deps.callAFS(\"read\", skillFile);\n } catch {\n return false;\n }\n if (!res.success) return false;\n const md = extractReadContent(res.data);\n if (!md) return false;\n const fm = parseSkillFrontmatter(md);\n if (!fm?.name || seen.has(fm.name)) return !!fm?.name;\n seen.add(fm.name);\n let desc = (fm.description ?? \"\").replace(/\\s+/g, \" \").trim();\n if (desc.length > DESC_MAX) desc = `${desc.slice(0, DESC_MAX - 1)}…`;\n entries.push({ name: fm.name, description: desc, path: skillFile });\n return true;\n };\n\n for (const root of skillPaths) {\n if (entries.length >= MAX_SKILLS) break;\n let listRes: AFSExecResult;\n try {\n listRes = await deps.callAFS(\"list\", root);\n } catch {\n continue;\n }\n if (!listRes.success) continue;\n for (const child of extractEntries(listRes.data)) {\n if (entries.length >= MAX_SKILLS) break;\n const childPath: string | undefined = child.path || child.id;\n if (!childPath) continue;\n // Leaf skill directly under the root?\n if (await tryLeaf(childPath)) continue;\n // Otherwise treat as a group: descend ONE level for leaf skills.\n let groupRes: AFSExecResult;\n try {\n groupRes = await deps.callAFS(\"list\", childPath);\n } catch {\n continue;\n }\n if (!groupRes.success) continue;\n for (const gc of extractEntries(groupRes.data)) {\n if (entries.length >= MAX_SKILLS) break;\n const gcPath: string | undefined = gc.path || gc.id;\n if (gcPath) await tryLeaf(gcPath);\n }\n }\n }\n\n if (entries.length === 0) return undefined;\n const lines = entries.map(\n (e) => `- **${e.name}** — ${e.description || \"(no description)\"} → read \\`${e.path}\\``,\n );\n return [\n \"## Available Skills\",\n \"These skills are ready to use. When a user request matches a skill's purpose, `read` its SKILL.md for the full procedure and follow it exactly — do not improvise the workflow. If none fit, work directly with the AFS tools.\",\n \"\",\n ...lines,\n ].join(\"\\n\");\n}\n\n/** Extract action name from an action entry (from path or id). */\nfunction extractActionNameFromEntry(entry: Record<string, any>): string | undefined {\n // Try meta.name first\n if (entry.meta?.name) return entry.meta.name;\n // Extract from path: /foo/.actions/send → send\n const path = entry.path || entry.id || \"\";\n const marker = \"/.actions/\";\n const idx = path.lastIndexOf(marker);\n if (idx !== -1) return path.slice(idx + marker.length).split(\"/\")[0];\n // Fallback: use id directly\n if (entry.id && !entry.id.includes(\"/\")) return entry.id;\n return undefined;\n}\n\n// ─── Tool Result Size Limit ──────────────────────────────────────────────────\n\n/**\n * Compute the per-tool-result character limit based on context window size.\n * Each tool result should occupy at most ~2% of the context window.\n */\nfunction computeToolResultLimit(contextWindow: number | undefined): number {\n const cw = contextWindow ?? DEFAULT_CONTEXT_WINDOW;\n return Math.max(16000, Math.floor(cw * 0.05 * 3)); // 5% of context × ~3 chars/token, min 16000\n}\n\n/**\n * Truncate a tool result string if it exceeds the given character limit.\n * Returns the original string unchanged if within limit.\n */\nfunction truncateToolResult(content: string, limit: number): string {\n if (content.length <= limit) return content;\n return `${content.slice(0, limit)}\\n[... truncated ${content.length - limit} chars]`;\n}\n\n// ─── Tool Content Enrichment ─────────────────────────────────────────────────\n\n/**\n * Enrich tool result content with multimodal images when `_images` is present.\n * Returns the original string for normal results, or a multimodal content array\n * containing both text and image parts when images are detected.\n */\nfunction enrichToolContent(resultStr: string): string | unknown[] {\n try {\n const parsed = JSON.parse(resultStr);\n if (Array.isArray(parsed?._images) && parsed._images.length > 0) {\n const images = parsed._images.filter(\n (img: any) =>\n img && typeof img === \"object\" && img.type && (img.url || img.data || img.path),\n );\n if (images.length > 0) {\n return [{ type: \"text\", text: resultStr }, ...images];\n }\n }\n } catch {\n /* not JSON, return as-is */\n }\n return resultStr;\n}\n\n// ─── History Normalization ───────────────────────────────────────────────────\n\n/** Normalize an in-memory message (AigneHub camelCase) to canonical JSONL format (OpenAI snake_case). */\nfunction normalizeForHistory(msg: Record<string, unknown>): HistoryMessage | null {\n const role = msg.role as string;\n if (role === \"system\") return null; // system never saved\n\n const createdAt = new Date().toISOString();\n\n if (role === \"user\") {\n return { role: \"user\", content: String(msg.content ?? \"\"), createdAt };\n }\n\n if (role === \"assistant\") {\n const result: HistoryMessage = {\n role: \"assistant\",\n content: String(msg.content ?? \"\"),\n createdAt,\n ...(typeof msg.durationMs === \"number\" ? { durationMs: msg.durationMs } : {}),\n };\n // Normalize toolCalls (camelCase from AigneHub) → tool_calls (snake_case canonical)\n const rawToolCalls = (msg.toolCalls ?? msg.tool_calls) as\n | Array<Record<string, unknown>>\n | undefined;\n if (rawToolCalls?.length) {\n (result as any).tool_calls = rawToolCalls.map((tc) => {\n const fn = tc.function as Record<string, unknown> | undefined;\n // Support both OpenAI format (function.arguments) and Vercel AI SDK format (args)\n const rawArgs = fn?.arguments ?? tc.args;\n return {\n id: (tc.id ?? tc.toolCallId ?? \"\") as string,\n type: \"function\" as const,\n function: {\n name: (fn?.name ?? tc.toolName ?? \"\") as string,\n arguments: typeof rawArgs === \"string\" ? rawArgs : JSON.stringify(rawArgs ?? {}),\n },\n };\n });\n }\n return result;\n }\n\n if (role === \"tool\") {\n // Preserve multimodal content arrays (e.g. text + image from _images enrichment)\n const content = Array.isArray(msg.content) ? msg.content : String(msg.content ?? \"\");\n return {\n role: \"tool\",\n tool_call_id: (msg.tool_call_id ?? msg.toolCallId ?? \"\") as string,\n content,\n createdAt,\n ...(typeof msg.durationMs === \"number\" ? { durationMs: msg.durationMs } : {}),\n } as HistoryMessage;\n }\n\n return null;\n}\n\n// ─── Core Loop ──────────────────────────────────────────────────────────────\n\nexport async function runAgentLoop(\n params: AgentRunParams,\n deps: AgentRunDeps,\n): Promise<AgentRunResult> {\n const maxRounds = params.budget?.max_rounds ?? DEFAULT_MAX_ROUNDS;\n const actionsPerRound = params.budget?.actions_per_round ?? DEFAULT_ACTIONS_PER_ROUND;\n const tokenBudget = params.budget?.total_tokens ?? Number.POSITIVE_INFINITY;\n\n // ─── S9: Progress nesting — compute once, stamp on every event ────\n const nesting = computeProgressNesting(params);\n const emitProgress = (event: Omit<ToolProgressEvent, \"depth\" | \"chain\">) => {\n if (!params.onToolProgress) return;\n try {\n params.onToolProgress({ ...event, depth: nesting.depth, chain: [...nesting.chain] });\n } catch {\n /* best-effort */\n }\n };\n\n /** Stamp seq + ts and forward to deps.emit. No-op when observability isn't\n * wired up (CLI direct call). Failures are swallowed — trace is best-effort.\n * `LogEventInput` (= LogEvent minus seq/ts, distributed) preserves each\n * variant's required keys at the call site. */\n const emitObs = async (event: LogEventInput): Promise<void> => {\n if (!deps.emit || !deps.nextSeq) return;\n try {\n await deps.emit({ ...event, seq: deps.nextSeq(), ts: Date.now() } as LogEvent);\n } catch {\n /* best-effort */\n }\n };\n\n // Minimal AFSRoot facade for buildContext (delegates to deps.callAFS)\n const afs = {\n exec: async (path: string, args: Record<string, unknown>, opts: Record<string, unknown>) => {\n return deps.callAFS(\"exec\", path, { ...args, ...opts });\n },\n } as import(\"@aigne/afs\").AFSRoot;\n\n // ─── Proc registration (best-effort) ──────────────────────────────────────\n const sessionTag = params.session\n ? (params.session.split(\"/\").filter(Boolean).pop() ?? params.session)\n : Math.random().toString(16).slice(2, 10);\n const procId = await deps\n .callAFS(\"exec\", \"/proc/.actions/register\", {\n type: \"agent-run\",\n did: `did:afs:ash-run:${sessionTag}`,\n parentId: (params.execContext?.procId as string | undefined) ?? params.parentProcId,\n budget: {\n tokens: params.budget?.total_tokens,\n calls: params.budget?.max_rounds,\n },\n })\n .then((r) => (r?.data as { procId?: string } | undefined)?.procId)\n .catch(() => undefined);\n const completeProc = (status: \"done\" | \"failed\") => {\n if (procId) {\n deps.callAFS(\"exec\", \"/proc/.actions/complete\", { id: procId, status }).catch(() => {});\n }\n };\n\n // ─── Startup: inject memory tools (if configured) ─────────────────\n // Must come before action discovery so memory actions are discoverable.\n if (params.memory?.toolsPath) {\n params.tools.push({\n path: params.memory.toolsPath,\n ops: [\"exec\"],\n });\n }\n\n // AFS conformance: when memory is configured with a domain, also grant\n // standard list+read on `/<mount-root>/<domain>` so the agent can\n // *observe* what's stored alongside semantic recall. Domain is encoded\n // in the path, so the agent can only enumerate its own scope.\n // Mount root is derived from `recallPath` by stripping `/.actions/recall`.\n if (params.memory?.domain && params.memory?.recallPath) {\n const mountRoot = params.memory.recallPath.replace(/\\/\\.actions\\/recall\\/?$/, \"\");\n if (mountRoot && mountRoot !== params.memory.recallPath) {\n params.tools.push({\n path: joinURL(mountRoot, params.memory.domain),\n ops: [\"list\", \"read\"],\n maxDepth: 3,\n });\n }\n }\n\n // Same conformance for index: when scope is set, grant list+read on\n // `/<mount-root>/domains/<scope>` so the agent can enumerate what's\n // indexed in its scope (parallel to memory). Index entries surface as\n // `{entryPath, state, anchorCount, ...}` per the @List handler in\n // index-provider.\n if (params.index?.scope && params.index?.queryPath) {\n const mountRoot = params.index.queryPath.replace(/\\/\\.actions\\/query\\/?$/, \"\");\n if (mountRoot && mountRoot !== params.index.queryPath) {\n params.tools.push({\n path: joinURL(mountRoot, \"domains\", params.index.scope),\n ops: [\"list\", \"read\"],\n maxDepth: 2,\n });\n }\n }\n\n // ─── Startup: grant the cross-surface ask-user tool to every agent ───\n // `ask_user` is a base capability (like respond) — any agent can pause and\n // ask the human a question on whatever surface they're on. The action lives\n // on the ui provider; granting exec here puts it in the whitelist AND lets\n // discovery + buildToolSchema surface it to the LLM. When no live UI session\n // is attached, execAsk returns `cancelled` (never hangs).\n const ASK_USER_PATH = \"/dev/ui/.actions/ask\";\n if (!params.tools.some((t) => t.path === ASK_USER_PATH)) {\n params.tools.push({ path: ASK_USER_PATH, ops: [\"exec\"] });\n }\n\n // ─── Startup: discover action schemas (best-effort) ─────────────────\n const actionSchemas = await discoverActionSchemas(params.tools, deps);\n\n // Index schemas by action name for path fixup\n const schemasByAction = new Map<string, ActionSchema>();\n for (const s of actionSchemas) {\n schemasByAction.set(s.actionName, s);\n }\n\n // Build tool schema from declarations + discovered action schemas\n const toolSchema = buildToolSchema(params.tools, actionSchemas);\n\n // Skill discovery intentionally dropped from tool schema — skills are\n // just AFS files (see AFS_HINT in system prompt). The LLM browses via\n // list/read/exec; no special `afs_skill` meta-tool.\n\n // ─── Startup: load response schema (structured output) ──────────────\n let responseSchema: Record<string, unknown> | undefined;\n if (params.responseSchema) {\n // Try as AFS path first (starts with \"/\")\n if (params.responseSchema.startsWith(\"/\")) {\n try {\n const schemaResult = await deps.callAFS(\"read\", params.responseSchema);\n const content = (schemaResult as any)?.data?.content;\n if (typeof content === \"string\") {\n responseSchema = JSON.parse(content);\n } else if (content && typeof content === \"object\") {\n responseSchema = content as Record<string, unknown>;\n }\n } catch {\n // AFS read failure — fall through to inline parse\n }\n }\n // Fallback: try parsing as inline JSON string\n if (!responseSchema) {\n try {\n const parsed = JSON.parse(params.responseSchema);\n if (parsed && typeof parsed === \"object\") {\n responseSchema = parsed as Record<string, unknown>;\n }\n } catch {\n // Not valid JSON either — proceed without structured output\n }\n }\n // responseSchema is used via response_format (not as a tool)\n }\n\n // ─── Startup: load history + assemble messages ──────────────────────\n let history: HistoryMessage[] = [];\n if (params.session && deps.loadHistory) {\n try {\n history = await deps.loadHistory(params.session);\n } catch {\n // loadHistory failure should not prevent agent-run from running\n }\n }\n\n // ─── Assemble messages via buildContext ─────────────────────────────\n const AFS_HINT = [\n \"## AFS Discovery Protocol\",\n \"Start with `read /.knowledge` — it returns a complete capability index of all providers, actions, and paths in ONE call.\",\n \"For deeper detail on a specific provider: `read /.knowledge/{provider-name}`.\",\n \"Only use `explain {path}` when you need the deepest detail about a specific path or action.\",\n \"Do NOT read source code from /modules/project/ to learn about providers — use `/.knowledge` or `explain` instead.\",\n \"\",\n \"## Skills\",\n \"Skills are regular AFS files, not a special tool. Two roots:\",\n \" - /blocklet/skills — this app's own skills (from the blocklet)\",\n \" - /.mounted-skills — each mounted provider's bundled skills\",\n \"\",\n \"When you need a capability:\",\n \" 1. `list` one of the skill roots to see what's available\",\n \" 2. `read <dir>/SKILL.md` (or `README.md`) for usage + params\",\n \" 3. `read <path>.ash` if you need exact `param` declarations\",\n ' 4. `exec <path>.ash { ...params, caps: [\"*\"] }` to run the skill',\n \"\",\n \"A SKILL.md-bearing directory = one leaf skill. A DESCRIPTION.md-bearing directory = a group; descend into its children to find leaves.\",\n ].join(\"\\n\");\n const STOP_DIRECTIVE = responseSchema\n ? `When you have completed the user's task, respond with your final answer as a JSON object. Do not make additional tool calls after you have gathered all needed information.\\n\\nResponse JSON Schema:\\n${JSON.stringify(responseSchema, null, 2)}`\n : params.skipAfsHint\n ? \"When you have completed the user's task, respond with a concise text summary. Do not make additional tool calls after the task is done.\"\n : `When you have completed the user's task, respond with a concise text summary. Do not make additional tool calls after the task is done.\\n\\n${AFS_HINT}`;\n\n // Models have no knowledge of \"now\" — without a freshly-stamped reference\n // they invent timestamps (observed: todo concierge writing\n // createdAt:\"2025-07-11\" while live wall-clock was 2026-05-20). Inject the\n // current UTC ISO string so any tool_call that needs a real timestamp\n // (createdAt, archive filenames, due-date math) has a ground truth.\n const TIME_DIRECTIVE = `Current time: ${new Date().toISOString()} (UTC). When writing timestamps in tool args (createdAt, updatedAt, etc.) use this — do not invent dates.`;\n\n // Build memory config for buildContext (if configured)\n const memoryConfig: ContextMemoryOptions | undefined = params.memory\n ? {\n recallPath: params.memory.recallPath,\n maxTokens: params.memory.maxTokens,\n domain: params.memory.domain,\n }\n : undefined;\n\n // Read the agent's skill roots once at startup and inject a compact catalog\n // (name + description + read-path per skill) so the LLM does not burn\n // discovery rounds listing roots and reading every SKILL.md. It reads the\n // full SKILL.md only for the one skill it picks. Best-effort, never fatal.\n const skillCatalog = await buildSkillCatalog(params.skillPaths, deps);\n\n const ctx = await buildContext(afs, {\n task: params.task,\n system: params.system,\n history: history as Array<Record<string, unknown>>,\n memory: memoryConfig,\n directives: skillCatalog\n ? [TIME_DIRECTIVE, STOP_DIRECTIVE, skillCatalog]\n : [TIME_DIRECTIVE, STOP_DIRECTIVE],\n });\n const messages: Array<Record<string, unknown>> = ctx.messages;\n\n // Anchor for compression: the current user task (last message buildContext\n // appended). Stable object reference — survives compression + appended rounds.\n const currentTaskMessage = messages[messages.length - 1];\n\n // ─── History helpers ───────────────────────────────────────────────\n const contextWindow = params.budget?.context_window;\n const toolResultLimit = computeToolResultLimit(contextWindow);\n\n /** Normalize new messages, persist to working history (if session), and emit\n * one observability `message` event per normalized entry. emit fires\n * regardless of session — observability is independent from history.jsonl. */\n const appendNewMessages = async (newMsgs: Array<Record<string, unknown>>) => {\n const normalized: HistoryMessage[] = [];\n for (const msg of newMsgs) {\n const n = normalizeForHistory(msg);\n if (n) normalized.push(n);\n }\n if (normalized.length === 0) return;\n\n // Persist to working history (only if session)\n if (params.session) {\n try {\n await deps.appendHistory?.(params.session, normalized);\n } catch {\n /* best-effort */\n }\n }\n\n // Observability: emit one `message` event per normalized message.\n // Single point covers both branches (no-tool path + tool round path)\n // because both go through this helper.\n for (const m of normalized) {\n const tc = (m as { tool_calls?: unknown[] }).tool_calls;\n const cid = (m as { tool_call_id?: string }).tool_call_id;\n await emitObs({\n type: \"message\",\n role: m.role,\n content: m.content,\n ...(tc ? { toolCalls: tc } : {}),\n ...(cid ? { callId: cid } : {}),\n });\n }\n };\n\n /** Latest compress progress, captured by `onProgress` and read by\n * `rewriteCompressed` (whose signature is fixed by maybeCompress's\n * `onCompressed` contract — only `compressed` + `archived` are passed). */\n let latestCompressInfo: { beforeTokens: number; afterTokens: number; round: number } = {\n beforeTokens: 0,\n afterTokens: 0,\n round: 0,\n };\n\n /** Archive original messages + rewrite working history + emit `compress` event. */\n const rewriteCompressed = async (\n compressed: Array<Record<string, unknown>>,\n archived: Array<Record<string, unknown>>,\n ) => {\n if (params.session) {\n // 1. Archive the original messages that were compressed\n if (deps.archiveHistory && archived.length > 0) {\n const archivedNorm: HistoryMessage[] = [];\n for (const msg of archived) {\n const n = normalizeForHistory(msg);\n if (n) archivedNorm.push(n);\n }\n try {\n await deps.archiveHistory(params.session, archivedNorm);\n } catch {\n /* best-effort */\n }\n }\n\n // 2. Rewrite working history with compressed messages\n if (deps.rewriteHistory) {\n const compressedNorm: HistoryMessage[] = [];\n for (const msg of compressed) {\n const n = normalizeForHistory(msg);\n if (n) compressedNorm.push(n);\n }\n await deps.rewriteHistory(params.session, compressedNorm);\n }\n }\n\n // 3. Observability: emit `compress` event with the full new array.\n // Reader uses integer-replace semantics on this event.\n await emitObs({\n type: \"compress\",\n round: latestCompressInfo.round,\n compressed_messages: compressed,\n archived_count: archived.length,\n before_tokens: latestCompressInfo.beforeTokens,\n after_tokens: latestCompressInfo.afterTokens,\n });\n };\n\n /** Archive conversation to memory provider (best-effort, called on completion). */\n const archiveToMemory = async (status: string) => {\n if (!params.memory?.archivePath || !params.session) return;\n if (status !== \"completed\") return;\n try {\n // Collect user + assistant messages with actual text content.\n // Exclude: system (prompt), tool (raw AFS results), assistant tool_calls-only (no text).\n const archiveMessages = messages\n .filter((m) => {\n const role = m.role;\n if (role !== \"user\" && role !== \"assistant\") return false;\n // Skip assistant messages with no text content (tool_calls-only)\n const content = m.content;\n return content != null && String(content).trim().length > 0;\n })\n .map((m) => ({\n role: String(m.role),\n content: String(m.content),\n }));\n if (archiveMessages.length > 0) {\n // Convert session path to safe sessionId: /data/sessions/web/default → data-sessions-web-default\n const safeSessionId = params.session!.replace(/^\\/+/, \"\").replace(/\\//g, \"-\");\n await deps.callAFS(\"exec\", params.memory.archivePath, {\n sessionId: safeSessionId,\n messages: archiveMessages,\n domain: params.memory.domain,\n });\n }\n } catch (e) {\n log.error(`[agent-run] archiveToMemory error: ${e instanceof Error ? e.message : String(e)}`);\n }\n };\n\n // Append initial user message to history\n await appendNewMessages([messages[messages.length - 1]!]);\n\n const trace: TraceEntry[] = [];\n let totalTokens = 0;\n let totalActions = 0;\n // B4 — count successful nested .actions/run dispatches so the parent's\n // _meta.sub_runs reflects the session hierarchy spec. Incremented only on\n // an `ok` result from a sub-agent call (not errors, not skills, not breaker).\n let subRuns = 0;\n\n // Accumulated token/cost tracking for summary event\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCachedTokens = 0;\n let totalCost = 0;\n let resolvedModelName = \"\";\n\n // Circuit breaker: track consecutive identical tool calls per round\n // Key: `${toolName}:${stableStringify(args)}`, Value: { count, lastResult }\n const callHistory = new Map<string, { count: number; lastResult: string }>();\n\n // Observability: in-memory totals accumulator. Snapshot exposed via\n // `AgentRunResult.totals` so orchestration.ts can populate the run.end event.\n const totalsAccumulator: TotalsAccumulator = {\n rounds: 0,\n totalTokensIn: 0,\n totalTokensOut: 0,\n totalCachedTokens: 0,\n totalCost: 0,\n modelsUsed: new Set<string>(),\n hubsUsed: new Set<string>(),\n toolsUsed: new Set<string>(),\n };\n\n /** Update totals + emit `turn` event after each LLM call. Hub is pulled from\n * `data.reason.topPick.hub` when AI Device returns a routing reason. */\n const emitTurn = async (\n turnRound: number,\n turnStartedAtMs: number,\n data: Record<string, unknown> | undefined,\n inputTokens: number,\n outputTokens: number,\n cost: number,\n cachedTokens: number,\n status: \"ok\" | \"error\" = \"ok\",\n errorMessage: string | null = null,\n ) => {\n const reason = data?.reason as Record<string, unknown> | undefined;\n const topPick = reason?.topPick as Record<string, unknown> | undefined;\n const hub = (topPick?.hub as string | undefined) ?? null;\n const turnModel = (data?.model as string | undefined) ?? resolvedModelName ?? null;\n\n totalsAccumulator.rounds += 1;\n totalsAccumulator.totalTokensIn += inputTokens;\n totalsAccumulator.totalTokensOut += outputTokens;\n totalsAccumulator.totalCost += cost;\n totalsAccumulator.totalCachedTokens += cachedTokens;\n if (turnModel) totalsAccumulator.modelsUsed.add(turnModel);\n if (hub) totalsAccumulator.hubsUsed.add(hub);\n\n await emitObs({\n type: \"turn\",\n round: turnRound,\n model: turnModel,\n hub,\n tokensIn: inputTokens,\n tokensOut: outputTokens,\n tokensCached: cachedTokens,\n cost,\n durationMs: Date.now() - turnStartedAtMs,\n status,\n errorMessage,\n });\n };\n\n /** Snapshot the totals accumulator for the AgentRunResult.totals field. */\n const totalsSnapshot = (): TotalsSnapshot => ({\n rounds: totalsAccumulator.rounds,\n totalTokensIn: totalsAccumulator.totalTokensIn,\n totalTokensOut: totalsAccumulator.totalTokensOut,\n totalCachedTokens: totalsAccumulator.totalCachedTokens,\n totalCost: totalsAccumulator.totalCost,\n modelsUsed: [...totalsAccumulator.modelsUsed],\n hubsUsed: [...totalsAccumulator.hubsUsed],\n toolsUsed: [...totalsAccumulator.toolsUsed],\n });\n\n for (let round = 1; round <= maxRounds; round++) {\n const roundStartedAtMs = Date.now();\n // ── S11: Abort signal check — exit immediately, preserve completed work ──\n if (params.abortSignal?.aborted) {\n emitProgress({\n type: \"summary\",\n round: round - 1,\n model: resolvedModelName,\n tokens: {\n input: totalInputTokens,\n output: totalOutputTokens,\n cached: totalCachedTokens,\n cost: totalCost,\n },\n });\n completeProc(\"done\");\n return {\n status: \"budget_exhausted\",\n result: undefined,\n rounds: round - 1,\n total_actions: totalActions,\n total_tokens: totalTokens,\n sub_runs: subRuns,\n trace,\n totals: totalsSnapshot(),\n };\n }\n\n // ── Context compression check (every round, including round 1) ──\n const compressed = await maybeCompress(messages, {\n contextWindow,\n pinMessage: currentTaskMessage,\n callLLM: deps.callLLM,\n onCompressed: rewriteCompressed,\n onProgress: (info) => {\n if (info.phase === \"skipped\") return;\n // Capture before/after tokens for the next `compress` event emit.\n // `done` arrives before `onCompressed` fires (per context-compress.ts).\n latestCompressInfo = {\n round,\n beforeTokens: info.beforeTokens,\n afterTokens: info.afterTokens ?? latestCompressInfo.afterTokens,\n };\n if (params.onToolProgress) {\n const eventType =\n info.phase === \"done\" || info.phase === \"failed\" ? \"compress_result\" : \"compress_start\";\n emitProgress({\n type: eventType,\n round,\n compress: {\n phase: info.phase,\n beforeTokens: info.beforeTokens,\n contextWindow: info.contextWindow,\n compressedMessages: info.compressedMessages ?? 0,\n keptMessages: info.keptMessages ?? 0,\n afterTokens: info.afterTokens,\n error: info.error,\n },\n });\n }\n },\n });\n if (compressed !== messages) {\n messages.length = 0;\n messages.push(...compressed);\n }\n\n // Call LLM with retry (transient failures: JSON parse errors, rate limits, etc.)\n // Seed with caller-supplied modelArgs first so that ash's own llmArgs\n // (messages, tools, toolChoice, responseFormat, _onChunk) always win —\n // callers set modelArgs for routing hints (policy/requirements/session/\n // exclusions) that `/dev/ai/.actions/chat` understands.\n const llmArgs: Record<string, unknown> = { ...(params.modelArgs ?? {}) };\n llmArgs.messages = [...messages];\n // Give the model enough output headroom that long content (e.g. a full\n // article written inside a cms-write tool call) is not truncated mid-string.\n // Never override a caller-supplied limit.\n if (llmArgs.max_tokens == null && llmArgs.maxTokens == null) {\n llmArgs.max_tokens = DEFAULT_MAX_OUTPUT_TOKENS;\n }\n if (toolSchema.length > 0) {\n llmArgs.tools = toolSchema;\n llmArgs.toolChoice = params.toolChoice ?? \"auto\";\n }\n if (responseSchema) {\n llmArgs.responseFormat = {\n type: \"json_schema\",\n jsonSchema: { name: \"response\", schema: responseSchema },\n };\n }\n // Observability: ask AI Device to surface routing reason when relevant.\n // Hubs that don't recognize the field ignore it harmlessly.\n llmArgs.includeReason = true;\n\n const maxRetries = params.budget?.max_retries ?? DEFAULT_MAX_RETRIES;\n let llmResult: AFSExecResult | undefined;\n let lastLLMError = \"\";\n\n // Inject streaming callback for incremental output\n let hadStreamingDeltas = false;\n if (params.onToolProgress) {\n llmArgs._onChunk = (chunk: { text?: string; thoughts?: string }) => {\n if (chunk.thoughts) {\n hadStreamingDeltas = true;\n emitProgress({ type: \"thinking_delta\", round, text: chunk.thoughts });\n }\n if (chunk.text) {\n hadStreamingDeltas = true;\n emitProgress({ type: \"llm_delta\", round, text: chunk.text });\n }\n };\n }\n\n // Fire llm_start before LLM call\n emitProgress({ type: \"llm_start\", round, model: resolvedModelName });\n\n const llmStartTime = Date.now();\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n llmResult = await Promise.race([\n deps.callLLM(llmArgs),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error(\"LLM call timed out\")), LLM_CALL_TIMEOUT_MS),\n ),\n ]);\n if (llmResult.success) break;\n lastLLMError =\n (llmResult.data as any)?.error ?? (llmResult as any).error?.message ?? \"unknown error\";\n } catch (err) {\n // Thrown errors (e.g. \"No module found\" during startup race) are retryable too\n lastLLMError = err instanceof Error ? err.message : String(err);\n llmResult = undefined;\n }\n const hasNextAttempt = attempt < maxRetries - 1;\n const retryDelayMs = hasNextAttempt\n ? computeLLMRetryDelayMs(lastLLMError, attempt + 1)\n : undefined;\n // Fire llm_result on retry failure\n emitProgress({\n type: \"llm_result\",\n round,\n model: resolvedModelName,\n attempt: attempt + 1,\n maxAttempts: maxRetries,\n llmError: lastLLMError,\n retryDelayMs,\n });\n if (hasNextAttempt && retryDelayMs && retryDelayMs > 0) {\n await (deps.sleep ?? sleep)(retryDelayMs, params.abortSignal);\n }\n }\n\n if (!llmResult?.success) {\n trace.push({ round, tool_calls: [], tokens: { input: 0, output: 0 } });\n // Build detailed diagnostics for debugging\n const diagMessages = (llmArgs.messages as unknown[]) || [];\n const requestSummary = {\n model: params.model,\n messageCount: diagMessages.length,\n hasTools: !!llmArgs.tools,\n toolCount: Array.isArray(llmArgs.tools) ? llmArgs.tools.length : 0,\n };\n // Observability: emit a `turn` event with status=error so the jsonl\n // captures that this round attempted an LLM call but failed all retries.\n await emitTurn(round, roundStartedAtMs, undefined, 0, 0, 0, 0, \"error\", lastLLMError);\n completeProc(\"failed\");\n return {\n status: \"error\",\n error: `LLM call failed after ${maxRetries} attempts: ${lastLLMError}`,\n detail: {\n request: requestSummary,\n lastResponse: llmResult ?? null,\n },\n rounds: round,\n total_actions: totalActions,\n total_tokens: totalTokens,\n sub_runs: subRuns,\n trace,\n totals: totalsSnapshot(),\n };\n }\n\n const data = llmResult.data as Record<string, unknown>;\n const inputTokens = (data.inputTokens as number) ?? 0;\n const outputTokens = (data.outputTokens as number) ?? 0;\n totalTokens += inputTokens + outputTokens;\n if (procId) {\n deps\n .callAFS(\"exec\", \"/proc/.actions/record-usage\", {\n id: procId,\n tokens: inputTokens + outputTokens,\n calls: 1,\n })\n .catch(() => {});\n }\n\n // Capture resolved model name and accumulate usage\n if (data.model) resolvedModelName = data.model as string;\n const llmUsage = data.usage as Record<string, number> | undefined;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n if (llmUsage?.cacheReadInputTokens) totalCachedTokens += llmUsage.cacheReadInputTokens;\n if (llmUsage?.aigneHubCredits) totalCost += llmUsage.aigneHubCredits;\n\n const text = data.text as string | undefined;\n const json = data.json as Record<string, unknown> | undefined;\n const thoughtsText = data.thoughts as string | undefined;\n const rawToolCalls = data.toolCalls as Array<Record<string, unknown>> | undefined;\n\n // Truncation guard: if the model stopped because it hit the output-token\n // cap, any tool-call arguments it emitted this round may be cut off\n // mid-string (observed: a cms-write `content` truncated mid-article, then\n // re-sent identically until the circuit breaker blocked recovery). Surface a\n // visible warning so a truncated write isn't mistaken for a clean success.\n const finishReason = (data.finishReason as string | undefined)?.toLowerCase();\n if (finishReason === \"length\" || finishReason === \"max_tokens\") {\n emitProgress({\n type: \"warning\",\n round,\n model: resolvedModelName,\n text: \"Model output hit the token limit and was truncated — any content written this round may be incomplete. Write more concise content, or split a large file (one cms-write, then mode:append for the rest).\",\n });\n }\n\n // Emit complete thinking block if thoughts exist but no streaming deltas were fired\n if (thoughtsText && !hadStreamingDeltas) {\n emitProgress({ type: \"thinking\", round, text: thoughtsText, model: resolvedModelName });\n }\n\n // No tool calls → LLM is done\n if (!rawToolCalls || rawToolCalls.length === 0) {\n trace.push({ round, tool_calls: [], tokens: { input: inputTokens, output: outputTokens } });\n // Fire summary event with accumulated token/cost totals\n emitProgress({\n type: \"summary\",\n round,\n model: resolvedModelName,\n tokens: {\n input: totalInputTokens,\n output: totalOutputTokens,\n cached: totalCachedTokens,\n cost: totalCost,\n },\n });\n // Observability: emit `turn` BEFORE the assistant message append so the\n // jsonl stream presents the round's metadata header before its content.\n await emitTurn(\n round,\n roundStartedAtMs,\n data,\n inputTokens,\n outputTokens,\n llmUsage?.aigneHubCredits ?? 0,\n llmUsage?.cacheReadInputTokens ?? 0,\n );\n\n // Add final assistant message and persist\n const assistantContent = json ? JSON.stringify(json) : (text ?? \"\");\n const llmDurationMs = Date.now() - llmStartTime;\n messages.push({ role: \"assistant\", content: assistantContent, durationMs: llmDurationMs });\n await appendNewMessages([messages[messages.length - 1]!]);\n // When responseSchema is set, use structured json output if available,\n // otherwise fall back to parsing the text as JSON\n let result: string | Record<string, unknown> = text ?? \"\";\n if (responseSchema) {\n if (json) {\n result = json;\n } else if (text) {\n try {\n result = JSON.parse(text) as Record<string, unknown>;\n } catch {\n // LLM may wrap JSON in markdown fences — try to extract\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n result = JSON.parse(jsonMatch[0]) as Record<string, unknown>;\n } catch {\n // fall through — use raw text\n }\n }\n }\n }\n }\n // Fire onProgress for the no-tool-call final round too, so surfaces\n // without a message-edit API (e.g. weixin) still see the LLM's reply.\n // The tool-execution path (below) also fires this, but never reaches\n // here — so this branch needs its own invocation or the user never\n // gets the bubble when the agent answers directly without tools.\n if (params.onProgress) {\n const prog = params.onProgress;\n const progressPath = typeof prog === \"string\" ? prog : prog.path;\n const progressArgs =\n typeof prog === \"string\"\n ? {}\n : Object.fromEntries(Object.entries(prog).filter(([k]) => k !== \"path\"));\n const trimmed = text?.trim() ?? \"\";\n const prefixedText = trimmed ? `🤖 ${trimmed}` : \"\";\n try {\n await deps.callAFS(\"exec\", progressPath, {\n ...progressArgs,\n text: prefixedText,\n message_text: prefixedText,\n tool_summary: \"\",\n });\n } catch {\n // Best-effort — don't let progress surface failures abort the run.\n }\n }\n await archiveToMemory(\"completed\");\n completeProc(\"done\");\n return {\n status: \"completed\",\n result,\n rounds: round,\n total_actions: totalActions,\n total_tokens: totalTokens,\n sub_runs: subRuns,\n trace,\n totals: totalsSnapshot(),\n };\n }\n\n // (onProgress fires AFTER tool execution below — we need outcomes to\n // render per-call ✓/✗ status.)\n\n // Check token budget AFTER getting response but BEFORE executing tools\n if (totalTokens > tokenBudget) {\n trace.push({ round, tool_calls: [], tokens: { input: inputTokens, output: outputTokens } });\n emitProgress({\n type: \"summary\",\n round,\n model: resolvedModelName,\n tokens: {\n input: totalInputTokens,\n output: totalOutputTokens,\n cached: totalCachedTokens,\n cost: totalCost,\n },\n });\n await emitTurn(\n round,\n roundStartedAtMs,\n data,\n inputTokens,\n outputTokens,\n llmUsage?.aigneHubCredits ?? 0,\n llmUsage?.cacheReadInputTokens ?? 0,\n );\n completeProc(\"done\");\n return {\n status: \"budget_exhausted\",\n result: text,\n rounds: round,\n total_actions: totalActions,\n total_tokens: totalTokens,\n sub_runs: subRuns,\n trace,\n totals: totalsSnapshot(),\n };\n }\n\n // Normalize tool calls from any format (OpenAI / Vercel AI SDK)\n const toolCalls = rawToolCalls.map(normalizeToolCall);\n\n // Observability: emit `turn` event BEFORE pushing the assistant message\n // so the jsonl stream presents this round's metadata header before its content.\n await emitTurn(\n round,\n roundStartedAtMs,\n data,\n inputTokens,\n outputTokens,\n llmUsage?.aigneHubCredits ?? 0,\n llmUsage?.cacheReadInputTokens ?? 0,\n );\n\n // Track message index for history append at end of round\n const roundMsgStart = messages.length;\n\n // Add assistant message with tool calls (keep raw format for LLM round-trip)\n const llmDurationMs = Date.now() - llmStartTime;\n messages.push({\n role: \"assistant\",\n content: text ?? \"\",\n toolCalls: rawToolCalls,\n durationMs: llmDurationMs,\n });\n\n // Observability: emit the assistant message *immediately* so the jsonl\n // stream matches the logical execution order:\n // turn → assistant(toolCalls) → tool dispatches → tool results.\n // Without this, tool dispatch events emit while we're still in the\n // dispatch loop below, but the assistant message that *triggered* them\n // only lands at round-end (line 2221), reading like the dispatches\n // came before their trigger.\n await appendNewMessages([messages[messages.length - 1]!]);\n\n // Truncate to actions_per_round — notify LLM about dropped calls\n const roundCalls = toolCalls.slice(0, actionsPerRound);\n const droppedCalls = toolCalls.slice(actionsPerRound);\n const traceEntries: TraceEntry[\"tool_calls\"] = [];\n\n // Fire tool_start progress (pending state for all calls in this round)\n if (text?.trim()) {\n emitProgress({ type: \"thinking\", round, text: text!, model: resolvedModelName });\n }\n emitProgress({\n type: \"tool_start\",\n round,\n calls: roundCalls.map((c) => ({\n id: c.toolCallId,\n tool: c.toolName,\n path: String(c.args.path ?? \"\"),\n status: \"pending\" as const,\n args: c.args,\n })),\n });\n\n const toolsStartTime = Date.now();\n\n // (skill calls no longer special — they're just afs_exec on .ash files)\n const skillResults = new Map<string, string>();\n\n // Circuit breaker: detect repeated identical tool calls\n const breakerResults = new Map<string, string>();\n const thisRoundKeys = new Set<string>();\n for (const call of roundCalls) {\n const key = `${call.toolName}:${stableStringify(call.args)}`;\n thisRoundKeys.add(key);\n // ask_user is human-gated — each call blocks for a real person, so it can\n // never runaway-loop. Exempt it from the circuit breaker so an agent can\n // ask several similar questions in a row (the user hit this with a\n // multi-step questionnaire done as repeated asks).\n if (String((call.args as Record<string, unknown>)?.path ?? \"\") === ASK_USER_PATH) continue;\n const entry = callHistory.get(key);\n if (entry && entry.count >= CIRCUIT_BREAKER_THRESHOLD - 1) {\n breakerResults.set(call.toolCallId, entry.lastResult);\n traceEntries.push({\n id: call.toolCallId,\n name: call.toolName,\n path: String(call.args.path ?? \"\"),\n status: \"circuit_breaker\",\n });\n }\n }\n\n // Validate all non-skill calls\n const validatedCalls: Array<{\n call: ToolCallInput;\n op: string;\n valid: boolean;\n reason?: string;\n }> = [];\n for (const call of roundCalls) {\n if (skillResults.has(call.toolCallId)) continue; // already handled\n if (breakerResults.has(call.toolCallId)) continue; // circuit breaker tripped\n\n const op = toolNameToOp(call.toolName);\n if (!op) {\n validatedCalls.push({\n call,\n op: \"unknown\",\n valid: false,\n reason: `Unknown tool: ${call.toolName}`,\n });\n continue;\n }\n\n // Fix paths for per-action tools: LLMs often put the tool name\n // (afs_action_send) in the path instead of the real action name (send).\n if (call.toolName.startsWith(\"afs_action_\")) {\n fixPerActionPath(call, schemasByAction);\n }\n\n const path = call.args.path as string;\n // Batch write: path is optional when entries is provided\n const isBatchWrite =\n op === \"write\" && Array.isArray(call.args.entries) && call.args.entries.length > 0;\n // Batch read: path is optional when entries is provided; every batched\n // path must individually pass the same ACL check as a single read.\n const batchReadPaths =\n op === \"read\" && Array.isArray(call.args.entries) && call.args.entries.length > 0\n ? (call.args.entries as Array<{ path?: unknown }>)\n .map((e) => e?.path)\n .filter((p): p is string => typeof p === \"string\")\n : null;\n if (!path && !isBatchWrite && !batchReadPaths) {\n validatedCalls.push({ call, op, valid: false, reason: \"Missing path argument\" });\n continue;\n }\n if (path) {\n const validation = validateToolCall(path, op, params.tools);\n if (!validation.allowed) {\n validatedCalls.push({ call, op, valid: false, reason: validation.reason });\n continue;\n }\n }\n if (batchReadPaths) {\n const denied = batchReadPaths\n .map((p) => ({ p, v: validateToolCall(p, op, params.tools) }))\n .find(({ v }) => !v.allowed);\n if (denied) {\n validatedCalls.push({ call, op, valid: false, reason: denied.v.reason });\n continue;\n }\n }\n // Check required args per operation\n const missingArg = REQUIRED_ARGS[op]?.find((arg) => !(arg in call.args));\n if (missingArg) {\n validatedCalls.push({\n call,\n op,\n valid: false,\n reason: `Missing required argument '${missingArg}' for ${op}`,\n });\n continue;\n }\n validatedCalls.push({ call, op, valid: true });\n }\n\n // Split into ASH-routable and direct calls\n const ashCalls: ValidatedToolCall[] = [];\n const directCalls: Array<{ call: ToolCallInput; op: string }> = [];\n const errorResults: Array<{ id: string; error: string }> = [];\n\n for (const { call, op, valid, reason } of validatedCalls) {\n if (!valid) {\n errorResults.push({ id: call.toolCallId, error: reason ?? \"Validation failed\" });\n traceEntries.push({\n id: call.toolCallId,\n name: call.toolName,\n path: String(call.args.path ?? \"\"),\n status: \"error\",\n error: reason,\n });\n emitProgress({\n type: \"tool_result\",\n round,\n calls: [\n {\n id: call.toolCallId,\n tool: call.toolName,\n path: String(call.args.path ?? \"\"),\n status: \"error\",\n error: reason,\n },\n ],\n });\n continue;\n }\n\n const path = call.args.path as string;\n if (ASH_OPS.has(op)) {\n ashCalls.push({\n id: call.toolCallId,\n op: op as \"read\" | \"list\" | \"exec\",\n path,\n args: extractExecArgs(call.args),\n });\n } else {\n directCalls.push({ call, op });\n }\n traceEntries.push({ id: call.toolCallId, name: call.toolName, path, status: \"ok\" });\n }\n\n // Execute ASH-routable calls\n const ashResults: Record<string, string> = {};\n if (ashCalls.length > 0) {\n const source = generateAsh(ashCalls, round);\n\n // Security: the generated ASH source already contains @caps(exec /path write /.results/*)\n // which enforces path-level access via the compiler's checkCap mechanism.\n // We don't pass a `caps` array here, so ctx.caps defaults to [\"*\"] (wildcard),\n // letting the script-level @caps annotation be the sole enforcer.\n // Previously, deriveCapsArray produced \"op path\" format strings that didn't match\n // the legacy ctx.caps prefix check, silently blocking all agent-run exec calls.\n const ashResult = await deps.runAsh(source, {\n returnWrittenData: true,\n skipWritePrefix: RESULTS_PREFIX,\n });\n\n if (ashResult.success && (ashResult.data as any)?.writtenData) {\n const writtenData = (ashResult.data as any).writtenData as Record<string, unknown[]>;\n for (const call of ashCalls) {\n const key = `${RESULTS_PREFIX}${call.id}`;\n const data = writtenData[key];\n ashResults[call.id] = data ? JSON.stringify(data) : \"No result\";\n }\n } else {\n // ASH execution failed — set error for all ASH calls\n for (const call of ashCalls) {\n ashResults[call.id] =\n `ASH execution error: ${(ashResult.data as any)?.error ?? \"unknown\"}`;\n }\n }\n // Fire tool_result for ASH batch\n emitProgress({\n type: \"tool_result\",\n round,\n calls: ashCalls.map((c) => ({\n id: c.id,\n tool: `afs_${c.op}`,\n path: c.path,\n status: (ashResults[c.id]?.startsWith(\"ASH execution error\") ? \"error\" : \"ok\") as\n | \"ok\"\n | \"error\",\n result: truncateResult(ashResults[c.id], 2000),\n })),\n });\n }\n\n // Execute direct calls with ordering guarantees:\n // - read/list/search/stat/explain can run in parallel batches\n // - write/exec are serialized to preserve dependency order within a round\n const directResults: Record<string, string> = {};\n const executeDirectCall = async ({ call, op }: { call: ToolCallInput; op: string }) => {\n const path = (call.args.path as string) || \"/\";\n const directArgs = { ...call.args };\n delete directArgs.path;\n\n // Unwrap LLM-supplied `args` envelope for generic afs_exec calls. The\n // tool schema documents `args: object` (an \"Action arguments matching\n // the action's inputSchema\") so the LLM correctly puts the action's\n // fields inside that key. But the framework passes the entire tool\n // input (minus `path`) as the AFS exec args, which means a sandbox\n // script seeing `args` ends up reading `args.birthDate` instead of\n // `birthDate` — observed in production as the sandbox throwing\n // \"cannot read property 'equal-house' of undefined\" on horoscope\n // compute. Mirrors the unwrap that `extractExecArgs` already does for\n // ASH-routable calls.\n //\n // SCHEDULER DISPATCH CARVE-OUT: scheduler actions use the\n // `{ task, args: { task, system }, proc }` envelope where the outer\n // `args` IS the dispatch field, not the LLM's wrapping. Skip the\n // unwrap when the call has dispatch-envelope siblings (`task`, `proc`,\n // `session`) at the top level alongside `args`.\n if (\n op === \"exec\" &&\n directArgs.args &&\n typeof directArgs.args === \"object\" &&\n !Array.isArray(directArgs.args)\n ) {\n const hasDispatchSiblings =\n \"task\" in directArgs ||\n \"proc\" in directArgs ||\n \"session\" in directArgs ||\n \"system\" in directArgs;\n if (!hasDispatchSiblings) {\n const inner = directArgs.args as Record<string, unknown>;\n delete directArgs.args;\n for (const [k, v] of Object.entries(inner)) {\n if (!(k in directArgs)) directArgs[k] = v;\n }\n }\n }\n\n // Inject execContext into nested args (e.g. scheduler dispatch pattern).\n // Provides shared caller context without LLM involvement; LLM values take priority.\n // For scheduler dispatch: args = { task, args: { task, system }, proc }\n // → inject into args.args (the script parameters), not args (the dispatch envelope).\n if (op === \"exec\" && params.execContext) {\n const nested = directArgs.args;\n if (nested && typeof nested === \"object\" && !Array.isArray(nested)) {\n const nestedObj = nested as Record<string, unknown>;\n // Two-level injection: if args.args exists (scheduler dispatch pattern),\n // inject there; otherwise inject into args directly.\n const innerArgs = nestedObj.args;\n if (innerArgs && typeof innerArgs === \"object\" && !Array.isArray(innerArgs)) {\n nestedObj.args = { ...params.execContext, ...(innerArgs as Record<string, unknown>) };\n } else {\n directArgs.args = { ...params.execContext, ...nestedObj };\n }\n } else if (path.startsWith(\"/proc/messaging/tools/\")) {\n // B32: built-in messaging tools take caller identity from execContext,\n // not from the LLM. Flat-merge `from` so the provider sees it.\n for (const [k, v] of Object.entries(params.execContext)) {\n if (!(k in directArgs)) directArgs[k] = v;\n }\n }\n }\n\n // Propagate current procId as parentProcId for proc-aware dispatchers (e.g. scheduler).\n // Allows scheduled child tasks to automatically inherit this agent-run's proc as parent.\n if (op === \"exec\" && procId && !directArgs.parentProcId) {\n directArgs.parentProcId = procId;\n }\n\n // S11: inject parent budget remaining, abort signal, and spawn chain into sub-agent calls.\n if (op === \"exec\" && isSubAgentRunPath(path)) {\n const parentRemaining = tokenBudget - totalTokens;\n if (parentRemaining < Number.POSITIVE_INFINITY) {\n directArgs._parent_budget_remaining = Math.max(0, parentRemaining);\n }\n if (params.abortSignal) {\n directArgs._abort_signal = params.abortSignal;\n }\n const parentSession =\n params.session ?? nesting.chain[nesting.chain.length - 1] ?? undefined;\n if (parentSession) {\n directArgs._parent_session = parentSession;\n }\n const childSession =\n typeof directArgs.session === \"string\" && directArgs.session\n ? directArgs.session\n : `${path}#${call.toolCallId}`;\n directArgs._chain = [...nesting.chain, childSession];\n }\n\n const toolStartedAt = Date.now();\n let recordResult: unknown = null;\n let recordStatus: \"ok\" | \"error\" = \"ok\";\n let recordError: string | null = null;\n\n try {\n const result = await deps.callAFS(op, path, directArgs);\n const isOk = result.success;\n\n // B4 — successful sub-agent dispatch bumps the parent's sub_runs counter\n if (isOk && op === \"exec\" && path.endsWith(\"/.actions/run\")) {\n subRuns += 1;\n }\n\n // S8: strip _meta from sub-agent results so parent LLM only sees the result value\n let dataForLLM = result.data;\n if (\n isOk &&\n dataForLLM &&\n typeof dataForLLM === \"object\" &&\n \"_meta\" in (dataForLLM as Record<string, unknown>)\n ) {\n const shaped = dataForLLM as { result?: unknown; _meta?: Record<string, unknown> };\n if (shaped._meta) {\n emitProgress({\n type: \"subAgentMetadata\",\n round,\n calls: [{ id: call.toolCallId, tool: call.toolName, path, status: \"ok\" }],\n subAgentMeta: shaped._meta,\n });\n // S11: account child token usage in parent's budget\n const childTokens = shaped._meta.tokens_used;\n if (typeof childTokens === \"number\" && childTokens > 0) {\n totalTokens += childTokens;\n }\n }\n dataForLLM = shaped.result as Record<string, unknown> | undefined;\n }\n\n // Capture record state BEFORE JSON.stringify so a circular result\n // doesn't lose observability when the stringify throws downstream.\n if (isOk) {\n recordResult = dataForLLM;\n recordStatus = \"ok\";\n } else {\n recordStatus = \"error\";\n recordError = (result as any).error?.message ?? (result.data as any)?.error ?? \"failed\";\n }\n let stringifiedResult: string;\n if (isOk) {\n try {\n stringifiedResult = JSON.stringify(dataForLLM);\n } catch (stringErr) {\n const msg = stringErr instanceof Error ? stringErr.message : String(stringErr);\n stringifiedResult = `Error: ${msg}`;\n recordStatus = \"error\";\n recordError = msg;\n }\n } else {\n stringifiedResult = `Error: ${recordError ?? \"failed\"}`;\n }\n directResults[call.toolCallId] = stringifiedResult;\n emitProgress({\n type: \"tool_result\",\n round,\n calls: [\n {\n id: call.toolCallId,\n tool: call.toolName,\n path,\n status: isOk ? \"ok\" : \"error\",\n ...(!isOk && { error: directResults[call.toolCallId] }),\n result: truncateResult(directResults[call.toolCallId], 2000),\n },\n ],\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n directResults[call.toolCallId] = `Error: ${msg}`;\n recordStatus = \"error\";\n recordError = msg;\n emitProgress({\n type: \"tool_result\",\n round,\n calls: [\n {\n id: call.toolCallId,\n tool: call.toolName,\n path,\n status: \"error\",\n error: msg,\n result: `Error: ${msg}`,\n },\n ],\n });\n }\n\n // Observability: track this tool name + emit a `tool` event.\n totalsAccumulator.toolsUsed.add(call.toolName);\n await emitObs({\n type: \"tool\",\n round,\n callId: call.toolCallId,\n name: call.toolName,\n path,\n op,\n args: stripInternalFields(directArgs),\n result: truncateField(recordResult, FIELD_LIMIT),\n status: recordStatus,\n errorMessage: recordError,\n durationMs: Date.now() - toolStartedAt,\n });\n };\n\n const isMutatingOp = (op: string) => op === \"write\" || op === \"exec\";\n let readBatch: Array<{ call: ToolCallInput; op: string }> = [];\n const flushReadBatch = async () => {\n if (readBatch.length === 0) return;\n await Promise.all(readBatch.map((entry) => executeDirectCall(entry)));\n readBatch = [];\n };\n\n for (const entry of directCalls) {\n if (isMutatingOp(entry.op)) {\n await flushReadBatch();\n await executeDirectCall(entry);\n continue;\n }\n readBatch.push(entry);\n }\n await flushReadBatch();\n\n // Fire onProgress (the AFS-script hook used for user-visible progress\n // surfaces like Telegram live-progress). We fire AFTER tool execution\n // so the summary can include each call's outcome (✓ / ✗ / ⊘). The\n // trade-off: user sees this round's trace only after tools complete;\n // the typing indicator keeps them informed during the wait.\n //\n // Always fire — even with empty text — so the script can still take\n // side effects (typing etc.).\n if (params.onProgress) {\n const prog = params.onProgress;\n const progressPath = typeof prog === \"string\" ? prog : prog.path;\n const progressArgs =\n typeof prog === \"string\"\n ? {}\n : Object.fromEntries(Object.entries(prog).filter(([k]) => k !== \"path\"));\n const toolSummary = summarizeToolCalls(roundCalls, traceEntries, errorResults);\n // Prefix LLM's intermediate text with 🤖 so users scanning the\n // progress message can distinguish \"agent speaking\" from\n // \"agent acting\" (tool calls, already self-labelled by op emoji).\n // Trim the LLM text so trailing newlines from streaming don't\n // leak into the accumulated progress body.\n const trimmed = text?.trim() ?? \"\";\n const prefixedText = trimmed ? `🤖 ${trimmed}` : \"\";\n // Single `\\n` between text and tools — tight visual layout.\n // Round-to-round separation is also single `\\n` (see Telegram\n // live-progress in @aigne/afs-telegram).\n const enrichedText =\n prefixedText && toolSummary\n ? `${prefixedText}\\n${toolSummary}`\n : prefixedText || toolSummary;\n await deps.callAFS(\"exec\", progressPath, {\n ...progressArgs,\n text: enrichedText,\n // Split components so surfaces without message-edit (e.g. weixin) can\n // pick the LLM-speaking part only and skip the tool summary, avoiding\n // a \"one bubble per tool call\" flood in pure-chat channels.\n message_text: prefixedText,\n tool_summary: toolSummary,\n });\n }\n\n // Update circuit breaker history with this round's results.\n // Only increment count once per unique key per round — batch calls with\n // identical args within one round should count as a single occurrence.\n const updatedKeys = new Set<string>();\n for (const call of roundCalls) {\n if (breakerResults.has(call.toolCallId) || errorResults.find((e) => e.id === call.toolCallId))\n continue;\n // Don't accumulate breaker history for human-gated ask_user (exempt).\n if (String((call.args as Record<string, unknown>)?.path ?? \"\") === ASK_USER_PATH) continue;\n const key = `${call.toolName}:${stableStringify(call.args)}`;\n if (updatedKeys.has(key)) continue; // already counted this key for this round\n updatedKeys.add(key);\n const result = ashResults[call.toolCallId] ?? directResults[call.toolCallId] ?? \"\";\n const prev = callHistory.get(key);\n callHistory.set(key, { count: (prev?.count ?? 0) + 1, lastResult: result });\n }\n // Reset keys not seen this round (consecutive tracking only)\n for (const key of callHistory.keys()) {\n if (!thisRoundKeys.has(key)) callHistory.delete(key);\n }\n\n // Append tool results to messages (truncated to toolResultLimit)\n for (const call of roundCalls) {\n let content: string | unknown[];\n if (skillResults.has(call.toolCallId)) {\n content = skillResults.get(call.toolCallId)!;\n } else if (breakerResults.has(call.toolCallId)) {\n const cached = breakerResults.get(call.toolCallId)!;\n content = `[Circuit breaker: this exact call was repeated ${CIRCUIT_BREAKER_THRESHOLD} consecutive times. Cached result returned. Change your approach — do NOT re-send the identical call. If you are writing a large file and the content looks cut off, your output was likely truncated at the token limit: write more concise content, or split it (one cms-write for the first part, then mode:append for the rest).]\\n${cached}`;\n } else {\n const errorEntry = errorResults.find((e) => e.id === call.toolCallId);\n if (errorEntry) {\n content = `Error: ${errorEntry.error}`;\n } else {\n const resultStr =\n ashResults[call.toolCallId] ?? directResults[call.toolCallId] ?? undefined;\n content =\n resultStr !== undefined\n ? enrichToolContent(truncateToolResult(resultStr, toolResultLimit))\n : \"Error: No result returned for this tool call\";\n }\n }\n // Truncate string content (skip multimodal arrays from enrichToolContent)\n if (typeof content === \"string\") {\n content = truncateToolResult(content, toolResultLimit);\n }\n messages.push({ role: \"tool\", tool_call_id: call.toolCallId, content });\n }\n\n // Notify LLM about dropped tool calls so it doesn't get confused\n for (const call of droppedCalls) {\n messages.push({\n role: \"tool\",\n tool_call_id: call.toolCallId,\n content: `Error: Tool call dropped — exceeded actions_per_round limit (${actionsPerRound}). Retry in next round.`,\n });\n }\n\n // Stamp tool messages with execution duration\n const toolsDurationMs = Date.now() - toolsStartTime;\n for (let i = roundMsgStart + 1; i < messages.length; i++) {\n const m = messages[i] as Record<string, unknown>;\n if (m.role === \"tool\") m.durationMs = toolsDurationMs;\n }\n\n // Skill calls and breaker-tripped calls are not real actions — exclude from count\n totalActions +=\n roundCalls.length - errorResults.length - skillResults.size - breakerResults.size;\n trace.push({\n round,\n tool_calls: traceEntries,\n tokens: { input: inputTokens, output: outputTokens },\n });\n\n // Append the round's tool-result messages to history (the assistant\n // message that triggered the calls was already appended/emitted right\n // after it was generated, so skip it here to avoid a duplicate).\n await appendNewMessages(messages.slice(roundMsgStart + 1));\n }\n\n // Max rounds exhausted\n emitProgress({\n type: \"summary\",\n round: maxRounds,\n model: resolvedModelName,\n tokens: {\n input: totalInputTokens,\n output: totalOutputTokens,\n cached: totalCachedTokens,\n cost: totalCost,\n },\n });\n completeProc(\"done\");\n return {\n status: \"budget_exhausted\",\n rounds: maxRounds,\n total_actions: totalActions,\n total_tokens: totalTokens,\n sub_runs: subRuns,\n trace,\n totals: totalsSnapshot(),\n };\n}\n","/**\n * Append-only JSONL message log for inter-agent communication (L3).\n *\n * Provider internal: direct fs calls are allowed here (see CLAUDE.md).\n */\n\nimport { randomUUID } from \"node:crypto\";\n// biome-ignore lint/style/noRestrictedImports: provider-internal (atomic append to JSONL)\nimport { appendFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\n\nexport interface MessageEntry {\n message_id: string;\n from: string;\n to: string;\n kind: string;\n ts: string;\n seq: number;\n body: unknown;\n}\n\nconst MAX_BODY_BYTES = 64 * 1024; // 64 KB\n\nlet globalSeq = 0;\n\nexport function appendMessage(\n filePath: string,\n from: string,\n to: string,\n body: unknown,\n kind = \"message\",\n): MessageEntry {\n const bodyStr = JSON.stringify(body);\n if (bodyStr.length > MAX_BODY_BYTES) {\n throw new Error(\"PAYLOAD_TOO_LARGE: message body exceeds 64KB limit\");\n }\n\n if (!from || typeof from !== \"string\") {\n throw new TypeError(\"from must be a non-empty string\");\n }\n if (!to || typeof to !== \"string\") {\n throw new TypeError(\"to must be a non-empty string\");\n }\n\n const entry: MessageEntry = {\n message_id: randomUUID(),\n from,\n to,\n kind,\n ts: new Date().toISOString(),\n seq: ++globalSeq,\n body,\n };\n\n const line = `${JSON.stringify(entry)}\\n`;\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, line);\n } else {\n appendFileSync(filePath, line);\n }\n\n return entry;\n}\n\nexport function readMessages(\n filePath: string,\n options?: { since?: string; limit?: number },\n): MessageEntry[] {\n if (!existsSync(filePath)) return [];\n\n const raw = readFileSync(filePath, \"utf8\");\n if (!raw.trim()) return [];\n\n const entries: MessageEntry[] = [];\n const lines = raw.split(\"\\n\");\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const entry = JSON.parse(trimmed) as MessageEntry;\n entries.push(entry);\n } catch {\n // skip corrupted lines\n }\n }\n\n let filtered = entries;\n\n if (options?.since) {\n const sinceDate = new Date(options.since);\n filtered = filtered.filter((e) => new Date(e.ts) > sinceDate);\n }\n\n filtered.sort((a, b) => {\n const tsDiff = new Date(a.ts).getTime() - new Date(b.ts).getTime();\n if (tsDiff !== 0) return tsDiff;\n return a.seq - b.seq;\n });\n\n if (options?.limit && options.limit > 0) {\n filtered = filtered.slice(0, options.limit);\n }\n\n return filtered;\n}\n\nexport function resetSeqCounter(): void {\n globalSeq = 0;\n}\n","/**\n * Observability trace ownership routing (Phase 3c).\n *\n * Splits \"who owns this run's trace\" (ownership resolution) from \"where can the\n * current AFS binding physically write\" (the legacy target-availability probing\n * that used to be the whole story). The owning principal is derived first from a\n * trusted write context, then a `TraceSink` is resolved:\n *\n * user → caller's own DID-Space user fragment (resolver direct-write).\n * Requires callerDid + instanceDid + spaceResolver ALL present.\n * Missing any: drop under strict modes (NEVER fall back to\n * /instance — that would leak user data into the installer space);\n * under observe-only fall through to legacy probing for migration\n * safety (lands in instance/host-inbox, never another user's space).\n * instance → installer/system fragment. 首期 keeps the legacy probing\n * (blocklet-scoped → host-inbox → legacy /instance); only the\n * instance class is allowed to use it.\n * ephemeral → not persisted (kind \"none\"); CF anonymous interactive is the\n * expected case and must not flood warnings.\n *\n * The `spaceResolver` is an object capability passed by the runtime — it never\n * appears in any JSON context or LLM-visible args (security invariant §9.7).\n *\n * See planning/did-integration/observability-data-model/design.md §2 and\n * persistence-class-sourcing-patch.md §3.3/§4/§7/§10.5.\n */\n\nimport type { AFSRoot, SpaceResolver } from \"@aigne/afs\";\nimport { joinURL } from \"ufo\";\n\nexport type AgentRunOrigin = \"interactive\" | \"system\";\nexport type PersistenceClass = \"user\" | \"instance\" | \"ephemeral\";\nexport type OwnershipRoutingMode = \"observe-only\" | \"strict-user\" | \"strict-all\";\nexport type AnonymousInteractivePersistence = \"instance\" | \"ephemeral\";\n\n/**\n * Where a run's jsonl trace lands.\n * - `none`: not persisted (ephemeral, or a strict-mode drop). `reason` is for\n * telemetry; `dropped` distinguishes an intentional ephemeral no-op from a\n * fail-closed drop that should warn.\n * - `afs`: write through a resolver-provided AFS (the user/system fragment\n * root) at `path` (absolute within that AFS).\n * - `legacy-current-afs`: write through the run's current AFS (deps.callAFS) at\n * the probed `path` — the migration path for the instance class.\n */\nexport type TraceSink =\n | { kind: \"none\"; persistenceClass: PersistenceClass; reason: string; dropped: boolean }\n | { kind: \"afs\"; persistenceClass: PersistenceClass; afs: AFSRoot; path: string; reason: string }\n | {\n kind: \"legacy-current-afs\";\n persistenceClass: PersistenceClass;\n path: string;\n reason: string;\n };\n\n/**\n * Derive the owning persistence class from the trusted write context.\n * `agentRunOrigin` defaults to `interactive` when undefined.\n *\n * **An authenticated** caller (`callerAuthenticated: true`) ALWAYS routes to\n * `\"user\"` — their runs are owned by their persisted identity. An\n * unauthenticated caller — including an anonymous WS connection that the\n * Node daemon stamped with a synthetic guest DID — is treated as anonymous\n * and falls through to the `anonymousInteractivePersistence` policy so the\n * trace lands somewhere the observability explorer can actually scan\n * (`/blocklets/<id>/instance/logs/agent-runs/` or the host-inbox), rather\n * than the guest's per-DID user space which is by design private.\n *\n * `callerAuthenticated` defaults to `false` when `callerDid` is set but the\n * caller comes from a legacy path that doesn't carry an auth marker — that\n * was the pre-Phase 3c behavior, so legacy callers stay routed the same\n * way.\n */\nexport function derivePersistenceClass(input: {\n callerDid: string | null;\n /**\n * True when the caller authenticated via a real credential\n * (cookie / bearer / passkey). False for synthetic guest DIDs assigned by\n * the daemon to anonymous WS sessions. When `callerDid` is null this\n * field is ignored. Optional — undefined preserves the legacy \"callerDid\n * implies authenticated\" routing for pre-Phase 3c call sites.\n */\n callerAuthenticated?: boolean;\n agentRunOrigin: AgentRunOrigin | undefined;\n anonymousInteractivePersistence: AnonymousInteractivePersistence;\n}): PersistenceClass {\n if (input.callerDid && input.callerAuthenticated !== false) return \"user\";\n if (input.agentRunOrigin === \"system\") return \"instance\";\n if (input.anonymousInteractivePersistence === \"instance\") return \"instance\";\n return \"ephemeral\";\n}\n\n/** Build the relative-within-fragment jsonl path (`logs/agent-runs/<date>/<file>`). */\nexport function userFragmentRunPath(date: string, fileName: string): string {\n return joinURL(\"/logs/agent-runs\", date, fileName);\n}\n\nexport interface ResolveTraceSinkInput {\n persistenceClass: PersistenceClass;\n callerDid: string | null;\n instanceDid: string | null;\n spaceResolver?: SpaceResolver;\n ownershipRoutingMode: OwnershipRoutingMode;\n /** Absolute path within the resolved user/system fragment AFS. */\n fragmentRunPath: string;\n /** Resolve the legacy current-AFS run path (the instance-class probing). */\n legacyProbe: () => Promise<string>;\n}\n\n/**\n * Resolve the `TraceSink` for a run. Pure except for the injected\n * `spaceResolver` / `legacyProbe` async calls. Called once per run (the\n * resolved sink is reused for every emit).\n */\nexport async function resolveTraceSink(input: ResolveTraceSinkInput): Promise<TraceSink> {\n const pc = input.persistenceClass;\n\n if (pc === \"ephemeral\") {\n return { kind: \"none\", persistenceClass: pc, reason: \"ephemeral\", dropped: false };\n }\n\n if (pc === \"user\") {\n const missing: string[] = [];\n if (!input.callerDid) missing.push(\"callerDid\");\n if (!input.instanceDid) missing.push(\"instanceDid\");\n if (!input.spaceResolver) missing.push(\"spaceResolver\");\n\n if (missing.length === 0) {\n const space = await input.spaceResolver!.resolveUserSpace(input.callerDid!);\n const userAFS = await space.getInstanceSpace({\n instanceDid: input.instanceDid!,\n role: \"user\",\n accessMode: \"readwrite\",\n });\n return {\n kind: \"afs\",\n persistenceClass: pc,\n afs: userAFS as unknown as AFSRoot,\n path: input.fragmentRunPath,\n reason: \"user-direct-write\",\n };\n }\n\n const reason = `user-missing:${missing.join(\",\")} mode=${input.ownershipRoutingMode}`;\n // strict modes fail-closed: NEVER fall back to /instance (would write\n // user-owned data into the installer space — ownership violation §4.1).\n if (\n input.ownershipRoutingMode === \"strict-user\" ||\n input.ownershipRoutingMode === \"strict-all\"\n ) {\n return { kind: \"none\", persistenceClass: pc, reason, dropped: true };\n }\n // observe-only migration safety: legacy probing lands in instance/host-inbox\n // (never another user's space). Telemetry still records the missing fields.\n const legacy = await input.legacyProbe();\n return { kind: \"legacy-current-afs\", persistenceClass: pc, path: legacy, reason };\n }\n\n // instance — 首期 keeps the legacy target-availability probing. Only the\n // instance class is allowed to use it. Under strict-all every class must have\n // a complete trusted context, so an instance write missing its instanceDid\n // column key drops instead of blind-probing (Phase 3e).\n if (input.ownershipRoutingMode === \"strict-all\" && !input.instanceDid) {\n return {\n kind: \"none\",\n persistenceClass: pc,\n reason: `instance-missing:instanceDid mode=strict-all`,\n dropped: true,\n };\n }\n const legacy = await input.legacyProbe();\n return {\n kind: \"legacy-current-afs\",\n persistenceClass: pc,\n path: legacy,\n reason: \"instance-legacy-probing\",\n };\n}\n","const DEFAULT_MAX = 3;\nconst HARD_CAP = 10;\n\nexport function checkSpawnDepth(chain: string[], manifestMax?: number): void {\n if (!Array.isArray(chain)) {\n throw new TypeError(\"chain must be an array\");\n }\n\n let max = DEFAULT_MAX;\n if (typeof manifestMax === \"number\" && manifestMax > 0) {\n max = Math.min(Math.floor(manifestMax), HARD_CAP);\n }\n\n const depth = chain.length;\n if (depth >= max) {\n throw new Error(`MAX_SPAWN_DEPTH_EXCEEDED: depth ${depth} >= max ${max}`);\n }\n}\n","/**\n * agent-run orchestration — the args→params→deps→runAgentLoop pipeline.\n *\n * Owns the execution flow that used to live as `executeAgentRunImpl` on\n * the AFSAsh class. Now exposed as a standalone function so AFSAgent\n * can call it directly without delegating to ash.\n *\n * What this layer does (between AFS exec args and `runAgentLoop`):\n *\n * 1. Strip the in-process `_*` args (scope_afs, on_tool_progress,\n * abort_signal, parent_session, chain) so cleanArgs is\n * serialization-safe.\n * 2. Validate task / model / tools shape.\n * 3. Resolve the model path (short name → /dev/ai/hubs/aignehub mount;\n * absolute path → normalized verbatim; chat-action leaf → kept as-is).\n * 4. Stat the model node to discover its context window (best-effort,\n * non-fatal).\n * 5. Append caller-provided structured `context` JSON to the task.\n * 6. Build the `AgentRunParams` + `AgentRunDeps` (callLLM, runAsh,\n * callAFS, history persistence) and invoke `runAgentLoop`.\n *\n * The `runAsh` dep delegates back to ash via AFS exec on the configured\n * mount path (default `/ash/.actions/run`) — agent-run does not own the\n * ash DSL execution. ash's run handler accepts `_return_written_data`\n * and `_skip_write_prefix` flags forwarded here so the orchestration\n * doesn't need to import AFSAsh internals.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { AFSExecResult, AFSRoot, SpaceResolver } from \"@aigne/afs\";\nimport { makeNsLog } from \"@aigne/afs\";\nimport type { ToolEntry } from \"@aigne/afs-ash\";\nimport { joinURL } from \"ufo\";\nimport {\n type AgentRunDeps,\n type AgentRunParams,\n type AgentRunResult,\n type HistoryMessage,\n runAgentLoop,\n type ToolProgressEvent,\n} from \"./agent-run.js\";\nimport { type LogEvent, safeStringifyLine } from \"./observability.js\";\nimport {\n type AgentRunOrigin,\n derivePersistenceClass,\n type OwnershipRoutingMode,\n resolveTraceSink,\n type TraceSink,\n userFragmentRunPath,\n} from \"./observability-routing.js\";\nimport { checkSpawnDepth } from \"./spawn-depth.js\";\n\nconst log = makeNsLog(\"provider:agent\");\n\n// ─── Helpers (moved from ash) ──────────────────────────────────────────\n\nfunction normalizeAbsoluteAfsPath(path: string): string {\n if (!path.startsWith(\"/\")) return path;\n const segments: string[] = [];\n for (const segment of path.split(\"/\")) {\n if (!segment || segment === \".\") continue;\n if (segment === \"..\") segments.pop();\n else segments.push(segment);\n }\n return `/${segments.join(\"/\")}`;\n}\n\nfunction hasUnsafePathSegments(path: string): boolean {\n return path.split(\"/\").some((segment) => segment === \".\" || segment === \"..\");\n}\n\n/**\n * Resolve a user-provided model identifier into an absolute AFS path.\n *\n * - `/foo/bar` → verbatim (after `..` / `.` normalization, rejected if\n * any path segment is `.` or `..`).\n * - `gpt-4o` → `/dev/ai/hubs/aignehub/models/gpt-4o`.\n *\n * The returned path may either point at a model NODE (e.g.\n * `/dev/ai/hubs/aignehub/models/gpt-4o`) or directly at a chat-action\n * leaf (e.g. `/dev/ai/.actions/chat`). The caller distinguishes via\n * regex on `/.actions/(chat|embed|image|video)$`.\n */\nexport function resolveAgentModelPath(model: string): string {\n if (!model) throw new Error(\"agent-run requires 'model' parameter as string\");\n\n if (model.startsWith(\"/\")) {\n if (hasUnsafePathSegments(model)) {\n throw new Error(\"agent-run model path contains unsafe path segments\");\n }\n return normalizeAbsoluteAfsPath(model);\n }\n\n if (model.includes(\"//\") || hasUnsafePathSegments(model)) {\n throw new Error(\"agent-run model path contains unsafe path segments\");\n }\n return `/dev/ai/hubs/aignehub/models/${model}`;\n}\n\n/**\n * Normalize tool calls to AIGNE format: { id, type: \"function\", function: { name, arguments } }.\n *\n * Accepts Vercel AI SDK ({ toolCallId, toolName, args }),\n * OpenAI ({ id, type, function: { name, arguments: string } }),\n * or already-normalized AIGNE format.\n */\nexport function normalizeToolCallsToAIGNE(\n toolCalls: Array<Record<string, unknown>>,\n): Array<Record<string, unknown>> {\n return toolCalls.map((tc) => {\n if (tc.toolName && !tc.function) {\n return {\n id: (tc.toolCallId ?? tc.id) as string,\n type: \"function\",\n function: { name: tc.toolName, arguments: tc.args ?? {} },\n };\n }\n const fn = tc.function as Record<string, unknown> | undefined;\n if (fn && typeof fn.arguments === \"string\") {\n try {\n return { ...tc, function: { ...fn, arguments: JSON.parse(fn.arguments as string) } };\n } catch {\n return tc;\n }\n }\n return tc;\n });\n}\n\n// ─── Observability runtime capability (Phase 3b) ───────────────────────\n\n// OwnershipRoutingMode is defined in ./observability-routing.js (the writer\n// owns it); re-exported here so consumers of the runtime capability type keep\n// importing it from one place.\nexport type { OwnershipRoutingMode } from \"./observability-routing.js\";\n\n/**\n * Runtime-supplied observability capability, injected into `AFSAgent` at\n * construction by the host runtime (Node / CF) as an *object capability*.\n *\n * Crucially this is NEVER serialized into the JSON `AFSContext`, the agent's\n * LLM-visible args, or any client-facing response. The `spaceResolver` handle\n * lets the writer (Phase 3c) resolve a per-principal trace sink without the\n * caller being able to name or forge a space.\n */\nexport interface ObservabilityRuntime {\n /** Space selector for per-principal trace sinks (Phase 2 contract). Absent\n * ⇒ user-class writes fail-closed in Phase 3c (no `/instance` fallback). */\n spaceResolver?: SpaceResolver;\n /** Where anonymous interactive runs persist: `\"instance\"` (Node — lands in\n * the instance slice) or `\"ephemeral\"` (CF — not persisted). */\n anonymousInteractivePersistence: \"instance\" | \"ephemeral\";\n /** Fail-closed stage (Phase 3e). Defaults to `\"observe-only\"` when absent. */\n ownershipRoutingMode?: OwnershipRoutingMode;\n}\n\n// ─── executeAgentRun orchestration ─────────────────────────────────────\n\nexport interface ExecuteAgentRunOptions {\n /** AFS root used for stat / exec / read / write. Defaults to the\n * caller-supplied `_scope_afs` arg if present, else `globalAfs`. */\n globalAfs?: AFSRoot;\n /** AFS path under which the ash provider is mounted. The `runAsh` dep\n * uses `${ashMountPath}/.actions/run` to delegate ash DSL execution.\n * Default: `/ash`. */\n ashMountPath?: string;\n /** Trusted caller context from RouteContext.context (AFSContext, populated\n * server-side in Phase 3a — never client-forgeable). As of Phase 3c it\n * DRIVES ownership routing: `caller.did` (userId = legacy mirror) →\n * persistence class, `instanceDid` → the DID-Space column, `agentRunOrigin`\n * → system vs interactive. `blockletId`/`sessionId` enrich the trace record\n * and the legacy instance-class probing. */\n callerContext?: {\n userId?: string;\n blockletId?: string;\n sessionId?: string;\n caller?: { did?: string | null } | null;\n instanceDid?: string;\n agentRunOrigin?: \"interactive\" | \"system\";\n [key: string]: unknown;\n };\n /** Observability runtime capability (Phase 3b). Injected by the host at\n * provider construction and threaded here so the writer (Phase 3c) can\n * resolve per-principal trace sinks. Object capability — never serialized\n * into JSON context or LLM-visible args. Unconsumed in 3b (capability\n * injection only); the writer wires it in 3c. */\n observabilityRuntime?: ObservabilityRuntime;\n}\n\n/**\n * The full args → result pipeline. Same contract as the legacy\n * `executeAgentRunImpl` method that used to live on AFSAsh, but as a\n * standalone function with explicit deps.\n *\n * Does NOT enqueue on a session queue — that's the caller's job (see\n * AFSAgent). Throws on validation failures (bad task / bad model)\n * and returns an `AFSExecResult` envelope on runtime failures.\n */\nexport async function executeAgentRun(\n args: Record<string, unknown>,\n options: ExecuteAgentRunOptions = {},\n): Promise<AFSExecResult> {\n const ashMountPath = options.ashMountPath ?? \"/ash\";\n\n // Extract scope AFS override (forwarded from program context via _scope_afs)\n const runtimeAFSOverride = args._scope_afs as AFSRoot | undefined;\n const onToolProgress = args._on_tool_progress as ((event: ToolProgressEvent) => void) | undefined;\n const abortSignal = args._abort_signal as AbortSignal | undefined;\n const parentSession = typeof args._parent_session === \"string\" ? args._parent_session : undefined;\n const chain = Array.isArray(args._chain)\n ? args._chain.filter((value): value is string => typeof value === \"string\")\n : undefined;\n const cleanArgs = { ...args };\n delete cleanArgs._scope_afs;\n delete cleanArgs._on_tool_progress;\n delete cleanArgs._abort_signal;\n delete cleanArgs._parent_session;\n delete cleanArgs._chain;\n delete cleanArgs._ui_session;\n const writePath = cleanArgs.write_to_path as string | undefined;\n delete cleanArgs.write_to_path;\n\n const context = cleanArgs.context;\n let task = cleanArgs.task;\n if (typeof task !== \"string\" || !task) {\n if (context && typeof context === \"object\") {\n task = JSON.stringify(context);\n } else if (typeof context === \"string\" && context) {\n task = context;\n } else {\n throw new Error(\"agent-run requires 'task' parameter as string\");\n }\n }\n const model = cleanArgs.model;\n if (typeof model !== \"string\" || !model) {\n throw new Error(\"agent-run requires 'model' parameter as string\");\n }\n const rawTools = cleanArgs.tools;\n const tools = rawTools === \"none\" || rawTools === undefined ? [] : rawTools;\n if (!Array.isArray(tools)) {\n throw new Error(\"agent-run 'tools' must be an array or 'none'\");\n }\n\n const globalAFS = options.globalAfs;\n if (!globalAFS && !runtimeAFSOverride) {\n throw new Error(\"agent-run requires AFS root to be mounted\");\n }\n\n const afs: AFSRoot = runtimeAFSOverride ?? globalAFS!;\n const skillPaths = cleanArgs.skill_paths as string[] | undefined;\n\n const resolvedModel = resolveAgentModelPath(model);\n const isDirectActionPath = /\\/\\.actions\\/(chat|embed|image|video)$/.test(resolvedModel);\n\n // Fetch context window from model metadata (best-effort).\n let contextWindow: number | undefined;\n try {\n if (afs.stat) {\n const statPath = isDirectActionPath\n ? resolvedModel.replace(/\\/\\.actions\\/\\w+$/, \"\")\n : resolvedModel;\n if (statPath && statPath !== \"/dev/ai\") {\n const modelStat = await afs.stat(statPath);\n const cw = (modelStat.data as { meta?: { contextWindow?: number } } | undefined)?.meta\n ?.contextWindow;\n if (typeof cw === \"number\" && cw > 0) {\n contextWindow = cw;\n }\n }\n }\n } catch {\n // Model stat failure is non-fatal — use default in maybeCompress\n }\n\n let enrichedTask = task as string;\n if (cleanArgs.context != null) {\n if (typeof cleanArgs.context === \"string\") {\n enrichedTask += `\\n\\nMessage metadata:\\n${cleanArgs.context}`;\n } else {\n const metaStr = JSON.stringify(cleanArgs.context, null, 2);\n enrichedTask += `\\n\\nMessage metadata:\\n\\`\\`\\`json\\n${metaStr}\\n\\`\\`\\``;\n }\n }\n\n const systemPrompt = cleanArgs.system as string | undefined;\n const spawnChain = chain ?? (typeof cleanArgs.session === \"string\" ? [cleanArgs.session] : []);\n checkSpawnDepth(spawnChain);\n\n const userBudget = (cleanArgs.budget ?? {}) as Record<string, unknown>;\n const params: AgentRunParams = {\n task: enrichedTask,\n model,\n tools: tools as ToolEntry[],\n budget: {\n max_rounds: userBudget.max_rounds as number | undefined,\n actions_per_round: userBudget.actions_per_round as number | undefined,\n total_tokens: userBudget.total_tokens as number | undefined,\n context_window: contextWindow,\n max_retries: userBudget.max_retries as number | undefined,\n },\n system: systemPrompt,\n session: cleanArgs.session as string | undefined,\n skillPaths,\n toolChoice: cleanArgs.tool_choice as string | undefined,\n modelArgs:\n cleanArgs.model_args !== undefined\n ? (cleanArgs.model_args as Record<string, unknown>)\n : (cleanArgs.modelArgs as Record<string, unknown> | undefined),\n onProgress: cleanArgs.on_progress as AgentRunParams[\"onProgress\"],\n onToolProgress,\n responseSchema: cleanArgs.response_schema as string | undefined,\n execContext: cleanArgs.exec_context as Record<string, unknown> | undefined,\n parentSession,\n chain: spawnChain,\n memory: cleanArgs.memory as AgentRunParams[\"memory\"],\n index: cleanArgs.index as AgentRunParams[\"index\"],\n skipAfsHint: cleanArgs.skip_afs_hint === true || cleanArgs.skipAfsHint === true || undefined,\n abortSignal,\n parentProcId: cleanArgs.parentProcId as string | undefined,\n };\n\n // Trusted context propagated into every internal AFS call (Phase 3d). Holds\n // ONLY the ownership-relevant fields (caller / instanceDid / agentRunOrigin /\n // sessionId / blockletId) — never params/afs/logger, which the framework\n // re-sets per call. Assigned once below after ownership resolution; deps\n // callbacks only fire during runAgentLoop (after that point), so the closure\n // sees the populated value. A nested `/dev/agent/.actions/run` therefore\n // inherits the parent's owning principal instead of degrading to anonymous.\n let trustedAfsContext: Record<string, unknown> | undefined;\n /** Merge the trusted context into an AFS options object (no-op when empty). */\n const withCtx = <T extends Record<string, unknown>>(opts: T): T =>\n (trustedAfsContext ? { ...opts, context: trustedAfsContext } : opts) as T;\n\n const deps: AgentRunDeps = {\n callLLM: async (llmArgs: Record<string, unknown>) => {\n if (!afs.exec)\n return { success: false, data: { error: \"exec not supported\" } } as AFSExecResult;\n const modelPath = isDirectActionPath ? resolvedModel : `${resolvedModel}/.actions/chat`;\n\n const onChunk = llmArgs._onChunk as\n | ((chunk: { text?: string; thoughts?: string }) => void)\n | undefined;\n\n // Translate agent-run message format → AigneHub format.\n const translated = { ...llmArgs };\n delete translated._onChunk;\n if (Array.isArray(translated.messages)) {\n translated.messages = (translated.messages as Array<Record<string, unknown>>).map((msg) => {\n const m = { ...msg };\n if (m.role === \"assistant\") m.role = \"agent\";\n if (m.role === \"tool\" && m.tool_call_id && !m.toolCallId) {\n m.toolCallId = m.tool_call_id;\n delete m.tool_call_id;\n }\n const rawTCs = (m.toolCalls ?? m.tool_calls) as\n | Array<Record<string, unknown>>\n | undefined;\n if (Array.isArray(rawTCs)) {\n m.toolCalls = normalizeToolCallsToAIGNE(rawTCs);\n delete m.tool_calls;\n }\n return m;\n });\n }\n\n try {\n const raw = await afs.exec(modelPath, translated, withCtx(onChunk ? { onChunk } : {}));\n if (raw.success && raw.data) {\n const inner = raw.data as Record<string, unknown>;\n const result = inner.result as Record<string, unknown> | undefined;\n const src = result ?? inner;\n const usage = (src.usage ?? result) as Record<string, unknown> | undefined;\n const toolCalls = src.toolCalls as Array<Record<string, unknown>> | undefined;\n raw.data = {\n text: src.text,\n json: src.json,\n thoughts: src.thoughts,\n toolCalls: toolCalls ? normalizeToolCallsToAIGNE(toolCalls) : undefined,\n inputTokens: usage?.inputTokens ?? inner.inputTokens,\n outputTokens: usage?.outputTokens ?? inner.outputTokens,\n model: src.model,\n usage: src.usage ?? usage,\n // Why the model stopped: \"length\" ⇒ output truncated at the token\n // cap (a tool call's args may be cut mid-string). agent-run uses this\n // to warn instead of silently persisting truncated content.\n finishReason:\n src.finishReason ?? src.finish_reason ?? src.stopReason ?? src.stop_reason,\n // Observability: agent-run reads `data.reason.topPick.hub` to\n // record per-turn `hub`. Preserve when AI Device returns it\n // (only present when llmArgs.includeReason === true).\n reason: src.reason ?? inner.reason,\n };\n }\n return raw;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n if (errMsg.includes(\"No module found\")) {\n return {\n success: false,\n data: {\n error: `Model provider not mounted: ${resolvedModel} — check if the provider started correctly (afs service restart)`,\n },\n } as AFSExecResult;\n }\n return { success: false, data: { error: `LLM exec failed: ${errMsg}` } } as AFSExecResult;\n }\n },\n runAsh: async (source: string, runArgs: Record<string, unknown>) => {\n if (!afs.exec) {\n return {\n success: false,\n data: { error: \"exec not supported\" },\n } as AFSExecResult;\n }\n // Delegate ash DSL execution back to the ash provider via AFS\n // routing. The two underscore-prefixed flags are interpreted by\n // ash's run handler (see providers/basic/ash/src/index.ts) and\n // forwarded into the internal `runAsh` options.\n return afs.exec(\n `${ashMountPath}/.actions/run`,\n {\n source,\n ...runArgs,\n _scope_afs: afs,\n _return_written_data: true,\n _skip_write_prefix: \"/.results/\",\n },\n withCtx({}),\n );\n },\n callAFS: async (op: string, path: string, opArgs?: Record<string, unknown>) => {\n switch (op) {\n case \"read\": {\n const readEntries = opArgs?.entries as Array<{ path: string }> | undefined;\n if (readEntries && readEntries.length > 0) {\n // Cap one notch below the CF wire batchRead budget (20) so a\n // full tool-layer batch never collides with a remote backend.\n if (readEntries.length > 16) {\n return {\n success: false,\n data: {\n error: `Too many entries (${readEntries.length} > 16) — split into chunks of 16`,\n },\n } as AFSExecResult;\n }\n const paths = readEntries.map((e) => e.path);\n const batchEntries = paths.map((p) => ({ path: p }));\n const afsWithBatch = afs as {\n batchRead?: (\n entries: typeof batchEntries,\n options?: Record<string, unknown>,\n ) => Promise<unknown>;\n };\n // Like `batchWrite` below: batchRead is OPTIONAL on AFSRoot —\n // scoped views may lack it, and the concrete implementation is a\n // per-entry independent loop anyway, so fall back to one.\n if (typeof afsWithBatch.batchRead === \"function\") {\n const br = await afsWithBatch.batchRead(batchEntries, withCtx({}));\n return { success: true, data: { batch: br } } as unknown as AFSExecResult;\n }\n const results: Array<{\n path: string;\n success: boolean;\n data?: unknown;\n error?: string;\n }> = [];\n let succeeded = 0;\n let failed = 0;\n for (const p of paths) {\n try {\n const r = await afs.read!(p, withCtx({}));\n results.push({ path: p, success: true, data: r.data });\n succeeded++;\n } catch (err) {\n results.push({\n path: p,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n failed++;\n }\n }\n return {\n success: true,\n data: { batch: { results, succeeded, failed } },\n } as unknown as AFSExecResult;\n }\n const r = await afs.read!(path, withCtx(opArgs ?? {}));\n return { success: true, data: r.data } as unknown as AFSExecResult;\n }\n case \"list\": {\n const r = await afs.list(path, withCtx(opArgs ?? {}));\n return { success: true, data: r.data } as unknown as AFSExecResult;\n }\n case \"search\": {\n if (!afs.search)\n return { success: false, data: { error: \"search not supported\" } } as AFSExecResult;\n const r = await afs.search(path, (opArgs?.query as string) ?? \"\", withCtx(opArgs ?? {}));\n return { success: true, data: { results: r.data } } as AFSExecResult;\n }\n case \"write\": {\n if (!afs.write)\n return { success: false, data: { error: \"write not supported\" } } as AFSExecResult;\n const entries = opArgs?.entries as\n | Array<{ path: string; content?: string; mode?: string }>\n | undefined;\n if (entries && entries.length > 0) {\n type WriteMode =\n | \"replace\"\n | \"append\"\n | \"prepend\"\n | \"patch\"\n | \"create\"\n | \"update\"\n | undefined;\n const batchEntries = entries.map((e) => ({\n path: e.path,\n content: e.content !== undefined ? { content: e.content } : undefined,\n mode: e.mode as WriteMode,\n }));\n const afsWithBatch = afs as {\n batchWrite?: (\n entries: typeof batchEntries,\n options?: Record<string, unknown>,\n ) => Promise<unknown>;\n };\n // `batchWrite` is OPTIONAL on AFSRoot — scoped/session AFS views\n // (the per-session `_scope_afs` the agent runs under) don't\n // implement it, only the concrete `AFS` class does. Fall back to\n // sequential per-entry writes, which is exactly what the concrete\n // `batchWrite` does internally (independent failures, no abort).\n if (typeof afsWithBatch.batchWrite === \"function\") {\n const br = await afsWithBatch.batchWrite(batchEntries, withCtx({}));\n return { success: true, data: { batch: br } } as unknown as AFSExecResult;\n }\n const results: Array<{\n path: string;\n success: boolean;\n data?: unknown;\n error?: string;\n }> = [];\n let succeeded = 0;\n let failed = 0;\n for (const entry of batchEntries) {\n try {\n const r = await afs.write(\n entry.path,\n entry.content ?? {},\n withCtx(entry.mode !== undefined ? { mode: entry.mode } : {}) as Parameters<\n typeof afs.write\n >[2],\n );\n results.push({ path: entry.path, success: true, data: r.data });\n succeeded++;\n } catch (err) {\n results.push({\n path: entry.path,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n failed++;\n }\n }\n return {\n success: true,\n data: { batch: { results, succeeded, failed } },\n } as unknown as AFSExecResult;\n }\n const writePayload: Record<string, unknown> = {};\n if (opArgs?.content !== undefined) writePayload.content = opArgs.content;\n // Forward tree-* helper fields (field, by) and ifMatch so\n // tree-toggle / tree-increment / CAS writes coming from LLM\n // tool_calls actually reach the provider. Without these the\n // base provider rejects with \"options.field is required\".\n const writeOpts: Record<string, unknown> = {};\n if (opArgs?.mode !== undefined) writeOpts.mode = opArgs.mode;\n if (opArgs?.field !== undefined) writeOpts.field = opArgs.field;\n if (opArgs?.by !== undefined) writeOpts.by = opArgs.by;\n if (opArgs?.ifMatch !== undefined) writeOpts.ifMatch = opArgs.ifMatch;\n const r = await afs.write(\n path,\n writePayload,\n withCtx(writeOpts) as Parameters<typeof afs.write>[2],\n );\n return { success: true, data: { written: r.data } } as unknown as AFSExecResult;\n }\n case \"delete\": {\n if (!afs.delete)\n return { success: false, data: { error: \"delete not supported\" } } as AFSExecResult;\n // The `afs_delete` tool_call schema declares `where` as a string\n // (LLM-friendly), so parse it into the structured predicate the\n // AFS layer expects. Forward `maxItems` + optional `ifMatch`\n // verbatim.\n const deleteOpts: Record<string, unknown> = {};\n if (opArgs?.where !== undefined) {\n let where: unknown = opArgs.where;\n if (typeof where === \"string\") {\n try {\n where = JSON.parse(where);\n } catch (e) {\n return {\n success: false,\n data: {\n error: `delete: 'where' is not valid JSON: ${e instanceof Error ? e.message : String(e)}`,\n },\n } as AFSExecResult;\n }\n }\n deleteOpts.where = where;\n }\n if (typeof opArgs?.maxItems === \"number\") deleteOpts.maxItems = opArgs.maxItems;\n if (opArgs?.ifMatch !== undefined) deleteOpts.ifMatch = opArgs.ifMatch;\n const r = await afs.delete(path, withCtx(deleteOpts) as Parameters<typeof afs.delete>[1]);\n return { success: true, data: { deleted: r } } as unknown as AFSExecResult;\n }\n case \"stat\": {\n if (!afs.stat)\n return { success: false, data: { error: \"stat not supported\" } } as AFSExecResult;\n const r = await afs.stat(path, withCtx({}));\n return { success: true, data: { stat: r.data } } as unknown as AFSExecResult;\n }\n case \"explain\": {\n if (!afs.explain)\n return { success: false, data: { error: \"explain not supported\" } } as AFSExecResult;\n const r = await afs.explain(path, withCtx({}));\n return { success: true, data: { content: r.content } } as AFSExecResult;\n }\n case \"exec\": {\n if (!afs.exec)\n return { success: false, data: { error: \"exec not supported\" } } as AFSExecResult;\n const execArgs =\n opArgs?.args && typeof opArgs.args === \"object\" && !Array.isArray(opArgs.args)\n ? (opArgs.args as Record<string, unknown>)\n : (opArgs ?? {});\n if (\n path.endsWith(\"/ash/.actions/run\") ||\n path.endsWith(\"/ash/.actions/run-job\") ||\n path.endsWith(\"/dev/agent/.actions/run\")\n ) {\n execArgs._scope_afs = afs;\n }\n try {\n // Phase 3d: a nested `/dev/agent/.actions/run` (or ash exec)\n // inherits the parent's owning principal via the trusted context —\n // the child run is NOT a fresh anonymous run. Client args cannot\n // override it (context is in OPTIONS, not args; 3a strips body\n // context fields).\n return await afs.exec(path, execArgs, withCtx({}));\n } catch (execErr) {\n if (path.endsWith(\".ash\") && afs.read) {\n const readResult = await afs.read(path, withCtx({}));\n const source = String(readResult.data?.content ?? \"\");\n if (source.trim()) {\n return afs.exec(\n `${ashMountPath}/.actions/run`,\n { source, ...execArgs },\n withCtx({}),\n );\n }\n }\n throw execErr;\n }\n }\n default:\n return {\n success: false,\n data: { error: `Unsupported direct op: ${op}` },\n } as AFSExecResult;\n }\n },\n loadHistory: async (sessionPath: string) => {\n const historyPath = `${sessionPath}/history.jsonl`;\n try {\n const result = await afs.read!(historyPath, withCtx({}));\n const content = String(result.data?.content ?? \"\");\n if (!content.trim()) return [];\n return content\n .trim()\n .split(\"\\n\")\n .flatMap((line) => {\n try {\n return [JSON.parse(line)];\n } catch {\n return [];\n }\n });\n } catch {\n return [];\n }\n },\n appendHistory: async (sessionPath: string, messages: HistoryMessage[]) => {\n const historyPath = `${sessionPath}/history.jsonl`;\n const newLines = `${messages.map((m: unknown) => JSON.stringify(m)).join(\"\\n\")}\\n`;\n await afs.write!(historyPath, { content: newLines }, withCtx({ mode: \"append\" as const }));\n },\n rewriteHistory: async (sessionPath: string, messages: HistoryMessage[]) => {\n const historyPath = `${sessionPath}/history.jsonl`;\n const content = `${messages.map((m: unknown) => JSON.stringify(m)).join(\"\\n\")}\\n`;\n await afs.write!(historyPath, { content }, withCtx({}));\n },\n archiveHistory: async (sessionPath: string, messages: HistoryMessage[]) => {\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\");\n const archivePath = `${sessionPath}/history-${ts}.jsonl`;\n const content = `${messages.map((m: unknown) => JSON.stringify(m)).join(\"\\n\")}\\n`;\n await afs.write!(archivePath, { content }, withCtx({}));\n },\n };\n\n // ─── Observability: per-run jsonl event log ───────────────────────\n // One jsonl file per run, one event per line (run.start | message | turn |\n // tool | compress | run.end). Where it lands is decided by the resolved\n // TraceSink (Phase 3c): the caller's user fragment (user class), the\n // instance/system fragment via legacy probing (instance class), or nowhere\n // (ephemeral / fail-closed drop). The whole accumulated content is rewritten\n // on each emit (mode:\"replace\") — see the writeTrace note below for why.\n const runId = randomUUID();\n const shortId = runId.replace(/-/g, \"\").slice(0, 8);\n const startedAt = Date.now();\n const iso = new Date(startedAt).toISOString(); // e.g. \"2026-04-29T10:19:44.000Z\"\n const date = iso.slice(0, 10);\n const time = iso.slice(11, 19).replace(/:/g, \"\"); // \"HHMMSS\"\n\n const callerContextResolved = options.callerContext ?? {};\n const rawBlockletId =\n typeof callerContextResolved.blockletId === \"string\" ? callerContextResolved.blockletId : null;\n // Path safety: blocklet IDs are conventionally `did:abt:z…` strings,\n // but the field is caller-supplied and shows up directly in a\n // filesystem path below (`/blocklets/<id>/…`). Reject anything that\n // contains a path-separator or `..` segment so a malicious caller\n // can't redirect the run-jsonl write to an arbitrary location. The\n // raw value is still preserved on each emitted event for audit.\n const blockletIdIsSafe =\n rawBlockletId !== null &&\n rawBlockletId.length > 0 &&\n !/[\\\\/]/.test(rawBlockletId) &&\n !rawBlockletId.split(\"/\").includes(\"..\") &&\n rawBlockletId !== \".\" &&\n rawBlockletId !== \"..\";\n const blockletId = blockletIdIsSafe ? rawBlockletId : null;\n\n // Resolve where the per-run jsonl actually lands.\n //\n // For scope:app blocklets `deps.callAFS` writes through a runtime AFS\n // whose `/instance` is the blocklet's own files dir, so the canonical\n // `/instance/logs/...` path is correct. For scope:root blocklets (e.g.\n // agent-surface) `deps.callAFS` is bound to globalAFS and globalAFS has\n // no `/instance` mount — every emit there throws \"No module found\" and\n // the trace silently disappears. Probe the blocklet-scoped path first so\n // root-scoped blocklets land their logs at\n // `/blocklets/<id>/instance/logs/...` (which globalAFS does have because\n // BlockletManager flat-mounts each blocklet there).\n const runFileName = `${time}-${shortId}.jsonl`;\n\n // Legacy target-availability probing (the pre-3c behavior, now scoped to the\n // `instance` persistence class). \"Where can the current AFS binding write?\" —\n // NOT \"who owns this run\". Probes blocklet-scoped → host-inbox → legacy\n // /instance. Resolved lazily because the user class may skip it entirely.\n const probeLegacyRunPath = async (): Promise<string> => {\n const userInstanceRunPath = joinURL(\"/instance/logs/agent-runs\", date, runFileName);\n const blockletRunPath = blockletId\n ? joinURL(\"/blocklets\", blockletId, \"instance/logs/agent-runs\", date, runFileName)\n : null;\n const hostInboxRunPath = joinURL(\"/dev/observability/.host-inbox\", date, runFileName);\n let runPath = userInstanceRunPath;\n if (blockletRunPath && blockletId) {\n try {\n const probe = await deps.callAFS(\"stat\", joinURL(\"/blocklets\", blockletId, \"instance\"));\n if (probe?.success) runPath = blockletRunPath;\n } catch {\n // Stat unsupported / not found → fall through to next probe.\n }\n }\n if (runPath === userInstanceRunPath) {\n // No blocklet-scoped instance available (CLI / system caller, or a\n // scope:root blocklet on a host that doesn't flat-mount /blocklets/...).\n // The daemon mounts a writable host-inbox FS at\n // /dev/observability/.host-inbox specifically for these — observability's\n // discoverRuns scans it as a synthetic \"(host)\" blocklet.\n try {\n const probe = await deps.callAFS(\"stat\", \"/dev/observability/.host-inbox\");\n if (probe?.success) runPath = hostInboxRunPath;\n } catch {\n // No host inbox mounted (older daemon / CF Worker) → keep legacy fallback.\n }\n }\n return runPath;\n };\n\n // ─── Ownership routing (Phase 3c) ─────────────────────────────────────\n // Derive the owning principal from the trusted AFSContext (Phase 3a) +\n // injected runtime capability (Phase 3b), then resolve the TraceSink. When\n // the runtime capability is absent (legacy construction), fall back to the\n // pure legacy probing so non-3b callers are unaffected.\n const callerInfo = callerContextResolved.caller as\n | { did?: string; authSource?: string; authMethod?: string; role?: string; roles?: string[] }\n | null\n | undefined;\n const callerDid =\n (callerInfo && typeof callerInfo.did === \"string\" ? callerInfo.did : null) ??\n (typeof callerContextResolved.userId === \"string\" ? callerContextResolved.userId : null);\n // Distinguish a real authenticated caller from a synthetic guest DID the\n // Node daemon stamps on every anonymous WS connection (so the per-blocklet\n // /user overlay has a key). The daemon marks these guests with the explicit\n // `role: \"guest\"` (or `roles: [\"guest\"]`) marker; an authenticated caller\n // either has no role or a non-guest role (e.g. \"user\", \"admin\"). Without\n // this check, guest DIDs route to the user persistence class and traces\n // land in the guest's private DID Space which the observability explorer\n // doesn't scan — so anonymous chat runs appear to vanish.\n const callerRole = callerInfo?.role ?? callerInfo?.roles?.[0];\n const callerAuthenticated = Boolean(callerDid) && callerRole !== \"guest\";\n const instanceDid =\n typeof callerContextResolved.instanceDid === \"string\"\n ? callerContextResolved.instanceDid\n : null;\n const rawOrigin = callerContextResolved.agentRunOrigin;\n const agentRunOrigin: AgentRunOrigin | undefined =\n rawOrigin === \"system\" ? \"system\" : rawOrigin === \"interactive\" ? \"interactive\" : undefined;\n\n const obsRuntime = options.observabilityRuntime;\n const ownershipRoutingMode: OwnershipRoutingMode =\n obsRuntime?.ownershipRoutingMode ?? \"observe-only\";\n\n let sink: TraceSink;\n if (!obsRuntime) {\n // Legacy runtime (no capability injected) — preserve exact pre-3c behavior.\n sink = {\n kind: \"legacy-current-afs\",\n persistenceClass: \"instance\",\n path: await probeLegacyRunPath(),\n reason: \"no-observability-runtime\",\n };\n } else {\n const persistenceClass = derivePersistenceClass({\n callerDid,\n callerAuthenticated,\n agentRunOrigin,\n anonymousInteractivePersistence: obsRuntime.anonymousInteractivePersistence,\n });\n sink = await resolveTraceSink({\n persistenceClass,\n callerDid,\n instanceDid,\n spaceResolver: obsRuntime.spaceResolver,\n ownershipRoutingMode,\n fragmentRunPath: userFragmentRunPath(date, runFileName),\n legacyProbe: probeLegacyRunPath,\n });\n }\n\n // Ownership routing telemetry (Phase 3e). Warn once (not per emit):\n // - dropped (strict fail-closed) → `drop mode=… reason=…`\n // - observe-only fell through with missing → `observe mode=… reason=…`\n // fields (persisted via legacy probing, but\n // the principal was incomplete — surfaced so\n // unconnected entries don't hide silently)\n // Ephemeral is the expected CF-anonymous no-op and must stay silent. `mode=`\n // is surfaced first so the line shows which routing stage acted.\n if (sink.kind === \"none\" && sink.dropped) {\n log.warn(\n `[observability] drop mode=${ownershipRoutingMode} persistenceClass=${sink.persistenceClass} reason=${sink.reason}`,\n );\n } else if (sink.reason.includes(\"missing\")) {\n log.warn(\n `[observability] observe mode=${ownershipRoutingMode} persistenceClass=${sink.persistenceClass} reason=${sink.reason}`,\n );\n }\n\n const userDid =\n callerDid ??\n (typeof callerContextResolved.userId === \"string\" ? callerContextResolved.userId : null);\n // Prefer the trusted callerContext.sessionId; fall back to the `_ui_session`\n // run arg. The trusted-context resolver strips client-supplied `sessionId`\n // (security), which drops the UI surface id needed to route an `ask_user`\n // tool call back to the originating terminal/chat. `_ui_session` is set by\n // the trusted host (agent-terminal handler / agent-core), not the LLM, so\n // it's a safe surface-routing hint (not an ownership principal).\n const sessionIdFromCtx =\n (typeof callerContextResolved.sessionId === \"string\"\n ? callerContextResolved.sessionId\n : null) ?? (typeof args._ui_session === \"string\" ? args._ui_session : null);\n\n // Phase 3d: populate the trusted context the deps callbacks propagate into\n // every internal AFS call. Only ownership fields — a nested run reuses this\n // exact principal. Assigned here (after derivation) but before runAgentLoop,\n // so the `withCtx` closure already sees it on first tool dispatch. Built only\n // when at least one ownership field is present (else stays undefined → no-op,\n // preserving the legacy no-context behavior for anonymous runs).\n {\n const ctx: Record<string, unknown> = {};\n if (callerInfo && typeof callerInfo.did === \"string\") ctx.caller = callerInfo;\n if (callerDid) ctx.userId = callerDid;\n if (instanceDid) ctx.instanceDid = instanceDid;\n if (agentRunOrigin) ctx.agentRunOrigin = agentRunOrigin;\n if (sessionIdFromCtx) ctx.sessionId = sessionIdFromCtx;\n if (rawBlockletId) ctx.blockletId = rawBlockletId;\n if (Object.keys(ctx).length > 0) trustedAfsContext = ctx;\n }\n\n const inputSnapshot = {\n task: params.task,\n model: params.model,\n tools: (params.tools ?? []).map((t) => ({ path: t.path, ops: t.ops })),\n budget: userBudget,\n systemPrompt: params.system,\n };\n\n // Per-run monotonic seq counter (orchestration owns it; agent-run.ts reads\n // it via deps.nextSeq for message/turn/tool/compress events).\n let seq = 0;\n const nextSeq = () => seq++;\n\n // Persist the per-run jsonl by accumulating every event line in memory\n // and writing the full accumulated content with mode:\"replace\" on each\n // emit.\n //\n // Why not mode:\"append\": the AFS base provider implements append as a\n // read-modify-write (`read existing → concat → write replace`). Even\n // with the calls serialized via a promise chain, providers whose\n // underlying write resolves before the bytes are durable (some buffered\n // fs adapters; runtime AFSes that route through ProjectionProvider /\n // remote stat caches; HTTP-fronted instance provider) can return a\n // stale `read` on the next emit, which then overwrites the trace with\n // a truncated version that drops the early rounds — exactly the\n // \"Round 1-3 disappear, only Round 4 visible\" symptom. Since the\n // orchestration layer already has every event in hand (we synthesized\n // them), keeping the canonical copy in memory and rewriting the whole\n // file each time bypasses the RMW race entirely. The cost is one\n // extra string concat + write per emit, which is negligible for the\n // ~10-20KB jsonl files we produce.\n // Persist the accumulated jsonl through the resolved sink:\n // afs → write to the resolver-provided user/system fragment\n // legacy-current-afs → write through deps.callAFS (the run's current AFS)\n // none → in-memory only (ephemeral / fail-closed drop)\n const writeTrace = async (content: string): Promise<void> => {\n if (sink.kind === \"none\") return; // ephemeral / dropped — no AFS write\n if (sink.kind === \"afs\") {\n try {\n await sink.afs.write!(sink.path, { content }, { mode: \"replace\" });\n } catch (err) {\n log.warn(\n `[observability] user-space emit threw: ${sink.path} — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return;\n }\n // legacy-current-afs\n try {\n const result = await deps.callAFS(\"write\", sink.path, { content, mode: \"replace\" });\n if (!result.success) {\n const err = (result as { error?: { message?: string } }).error?.message;\n log.warn(`[observability] emit failed: ${sink.path} — ${err ?? \"unknown\"}`);\n }\n } catch (err) {\n log.warn(\n `[observability] emit threw: ${sink.path} — ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n };\n\n const emittedLines: string[] = [];\n let emitChain: Promise<unknown> = Promise.resolve();\n const emit = (event: LogEvent): Promise<void> => {\n const line = safeStringifyLine(event);\n emittedLines.push(line);\n const next = emitChain.then(() => writeTrace(`${emittedLines.join(\"\\n\")}\\n`));\n // Swallow rejections so a single failure doesn't poison the chain.\n emitChain = next.catch(() => {});\n return next;\n };\n\n deps.emit = emit;\n deps.nextSeq = nextSeq;\n\n // Entry: emit run.start as seq 0.\n await emit({\n type: \"run.start\",\n seq: nextSeq(),\n ts: startedAt,\n runId,\n // Audit field — keep the caller-supplied value verbatim even when it\n // got rejected as a path component above (so misuse / abuse traces\n // are visible in the log).\n blockletId: rawBlockletId,\n userDid,\n sessionId: sessionIdFromCtx,\n input: inputSnapshot,\n ownership: {\n persistenceClass: sink.persistenceClass,\n agentRunOrigin: agentRunOrigin ?? \"interactive\",\n ownershipRoutingMode,\n instanceDid,\n sinkKind: sink.kind,\n sinkReason: sink.reason,\n },\n });\n\n const emitRunEnd = async (\n status: \"ok\" | \"budget_exhausted\" | \"error\",\n resultData: unknown,\n resultError: string | null,\n totalsSnap: AgentRunResult[\"totals\"],\n ) => {\n const endedAt = Date.now();\n await emit({\n type: \"run.end\",\n seq: nextSeq(),\n ts: endedAt,\n runId,\n durationMs: endedAt - startedAt,\n status,\n result: { data: resultData, errorMessage: resultError },\n totals: totalsSnap ?? {\n rounds: 0,\n totalTokensIn: 0,\n totalTokensOut: 0,\n totalCost: 0,\n modelsUsed: [],\n hubsUsed: [],\n toolsUsed: [],\n },\n });\n };\n\n let result: AgentRunResult;\n try {\n result = await runAgentLoop(params, deps);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n await emitRunEnd(\"error\", null, errMsg, undefined);\n return {\n success: false,\n data: { status: \"error\", error: `agent-run crashed: ${errMsg}` },\n } as unknown as AFSExecResult;\n }\n\n const obsStatus =\n result.status === \"completed\"\n ? \"ok\"\n : result.status === \"budget_exhausted\"\n ? \"budget_exhausted\"\n : \"error\";\n await emitRunEnd(obsStatus, result.result ?? null, result.error ?? null, result.totals);\n\n // Budget exhaustion is a graceful stop, not a crash. The agent ran out\n // of rounds or token budget but the loop captured whatever partial\n // text it produced into `result.result`. Surface it as a structured\n // error code so callers (terminal renderers, tests, downstream\n // agents) can distinguish \"budget exhausted, here's the partial\n // answer\" from \"runner blew up\". Without this the caller only sees\n // success: false and falls through to a generic\n // \"Runner reported failure\" — eight rounds of work thrown away.\n if (result.status === \"budget_exhausted\") {\n return {\n success: false,\n error: {\n code: \"BUDGET_EXHAUSTED\",\n message: `Budget exhausted at round ${result.rounds}/${params.budget?.max_rounds ?? \"?\"} (${result.total_tokens} tokens). Increase budget.max_rounds or budget.total_tokens in agent.json to continue.`,\n },\n data: result as unknown as Record<string, unknown>,\n };\n }\n\n if (writePath && result.status === \"completed\" && typeof result.result === \"string\") {\n if (!afs.write) {\n return {\n success: false,\n error: {\n code: \"WRITE_TO_PATH_FAILED\",\n message: `write_to_path '${writePath}' failed: write not supported on this AFS`,\n },\n data: result as unknown as Record<string, unknown>,\n } as unknown as AFSExecResult;\n }\n const writeResult = result.result;\n try {\n await afs.write(\n writePath,\n { content: writeResult },\n withCtx({ mode: \"replace\" }) as Parameters<typeof afs.write>[2],\n );\n } catch (writeErr) {\n const writeErrMsg = writeErr instanceof Error ? writeErr.message : String(writeErr);\n return {\n success: false,\n error: {\n code: \"WRITE_TO_PATH_FAILED\",\n message: `write_to_path '${writePath}' failed: ${writeErrMsg}`,\n },\n data: result as unknown as Record<string, unknown>,\n } as unknown as AFSExecResult;\n }\n return {\n success: true,\n data: {\n path: writePath,\n byteCount: Buffer.byteLength(writeResult, \"utf8\"),\n summary: writeResult.slice(0, 200),\n },\n } as unknown as AFSExecResult;\n }\n\n return {\n success: result.status === \"completed\",\n data: result as unknown as Record<string, unknown>,\n };\n}\n","/**\n * Per-key Promise chain queue for serializing async operations.\n *\n * Used by ASHProvider to ensure same-session agent-run calls execute\n * sequentially, preventing history file race conditions.\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nexport function deriveChildSession(parentSessionId: string): string {\n if (typeof parentSessionId !== \"string\" || parentSessionId.length === 0) {\n throw new TypeError(\"parentSessionId must be a non-empty string\");\n }\n if (parentSessionId.includes(\"..\")) {\n throw new Error(\"path traversal disallowed in session id\");\n }\n if (parentSessionId.includes(\"\\0\")) {\n throw new Error(\"null bytes disallowed in session id\");\n }\n return `${parentSessionId}/sub/${randomUUID()}`;\n}\n\nconst DEFAULT_MAX_DEPTH = 20;\n\nexport function createSessionQueue(maxDepth = DEFAULT_MAX_DEPTH) {\n const queues = new Map<string, Promise<unknown>>();\n const depths = new Map<string, number>();\n\n return {\n queues,\n depths,\n\n /**\n * Enqueue an async function for serial execution within a session.\n *\n * - If session is undefined, executes directly (no queuing).\n * - If the session queue is full, throws an Error with message starting with \"QUEUE_FULL\".\n * - Otherwise, chains onto the session's Promise tail and awaits the result.\n */\n async enqueue<T>(session: string | undefined, fn: () => Promise<T>): Promise<T> {\n if (!session) return fn();\n\n const depth = depths.get(session) ?? 0;\n if (depth >= maxDepth) {\n throw new Error(`QUEUE_FULL: session queue full (max ${maxDepth})`);\n }\n\n depths.set(session, depth + 1);\n const prev = queues.get(session) ?? Promise.resolve();\n const current = prev.catch(() => {}).then(() => fn());\n queues.set(session, current);\n\n try {\n return await current;\n } finally {\n const d = (depths.get(session) ?? 1) - 1;\n if (d <= 0) depths.delete(session);\n else depths.set(session, d);\n if (queues.get(session) === current) queues.delete(session);\n }\n },\n\n /** Clear all queue state. Does not await in-progress executions. */\n destroy() {\n queues.clear();\n depths.clear();\n },\n };\n}\n","/**\n * AFSAgent — LLM agent runtime provider, mounted at /dev/agent/.\n *\n * Owns the orchestration directly (Step C of the namespace decoupling):\n * the @Actions.Exec(\"/\") handler enqueues per-session via the package's\n * own SessionQueue, then calls `executeAgentRun` which builds params +\n * deps and invokes `runAgentLoop`. ash is no longer in the dispatch path\n * for the agent loop itself — only the `runAsh` dep delegates to\n * `${ashMountPath}/.actions/run` for ash DSL execution invoked by tools.\n */\n\nimport type {\n AFSAccessMode,\n AFSExecResult,\n AFSListResult,\n AFSModuleLoadParams,\n AFSRoot,\n AFSStatResult,\n ProviderManifest,\n} from \"@aigne/afs\";\nimport { ASH_EVENT_TYPES } from \"@aigne/afs\";\nimport { Actions, AFSBaseProvider, type RouteContext, Stat } from \"@aigne/afs/provider\";\nimport { z } from \"zod\";\nimport { executeAgentRun, type ObservabilityRuntime } from \"./orchestration.js\";\nimport { createSessionQueue } from \"./session-queue.js\";\n\nexport interface AFSAgentOptions {\n name?: string;\n description?: string;\n /**\n * AFS path under which the ash provider is mounted. The `runAsh` dep\n * inside agent-run delegates ash DSL execution to\n * `${ashMountPath}/.actions/run`. Default `/ash` matches the canonical\n * system mount.\n */\n ashMountPath?: string;\n /**\n * Maximum queued agent-run calls per session. Default 20.\n */\n maxSessionQueueDepth?: number;\n /**\n * Observability runtime capability (Phase 3b). The host runtime injects a\n * `SpaceResolver` + anonymous-persistence policy here at construction so the\n * writer (Phase 3c) can route each run's trace to the correct owning\n * principal's space. This is an *object capability*: it is never read from\n * the config JSON (`load`/`manifest.schema` ignore it) and never serialized\n * into any client-visible context or LLM args.\n */\n observabilityRuntime?: ObservabilityRuntime;\n}\n\nexport class AFSAgent extends AFSBaseProvider {\n static manifest(): ProviderManifest {\n return {\n name: \"agent-run\",\n description:\n \"LLM agent runtime: multi-round inference + tool_call dispatch loop. Wraps a single agent manifest, model, and tool whitelist into a single-shot agentic execution.\",\n uriTemplate: \"agent-run://\",\n category: \"compute\",\n schema: z.object({\n name: z.string().optional(),\n description: z.string().optional(),\n ashMountPath: z.string().optional(),\n maxSessionQueueDepth: z.number().int().positive().optional(),\n }),\n tags: [\"llm\", \"agent\", \"ai\", \"runtime\"],\n capabilityTags: [\"read-write\", \"auth:none\", \"local\"],\n security: {\n riskLevel: \"system\",\n resourceAccess: [\"process-spawn\"],\n dataSensitivity: [\"code\"],\n notes: [\n \"Executes LLM-driven multi-round agentic loops with tool dispatch. Uses @aigne/afs-ash's path-validator for tool whitelist enforcement and delegates ash DSL execution to the ash provider via AFS routing.\",\n ],\n },\n };\n }\n\n static async load({ config }: AFSModuleLoadParams = {}) {\n return new AFSAgent(config as AFSAgentOptions);\n }\n\n override readonly name: string;\n override readonly description?: string;\n override readonly accessMode: AFSAccessMode = \"readwrite\";\n\n private readonly ashMountPath: string;\n private readonly sessionQueue: ReturnType<typeof createSessionQueue>;\n private readonly observabilityRuntime?: ObservabilityRuntime;\n private afsRoot?: AFSRoot;\n\n constructor(options: AFSAgentOptions = {}) {\n super();\n this.name = options.name ?? \"agent-run\";\n this.description = options.description;\n this.ashMountPath = options.ashMountPath ?? \"/ash\";\n this.sessionQueue = createSessionQueue(options.maxSessionQueueDepth);\n this.observabilityRuntime = options.observabilityRuntime;\n }\n\n onMount(afs: AFSRoot): void {\n this.afsRoot = afs;\n }\n\n destroy(): void {\n this.sessionQueue.destroy();\n }\n\n // Root MUST be stat-able: the mount health check (afs.ts checkProviderOnMount,\n // fail-closed since #449) stats \"/\" before firing onMount — without a root\n // stat it throws \"Path not found: /\", the mount is flagged error, onMount is\n // skipped and `afsRoot` is never set, so every run() returns\n // AGENT_RUN_NOT_INITIALIZED. This provider exposes the `run` ACTION\n // (@Actions(\"/\") → /.actions/run), not regular file children, and has no\n // list(\"/\") handler — so childrenCount MUST be 0, otherwise the check's\n // \"has children → verify list\" step calls list(\"/\") and fails the same way.\n @Stat(\"/\")\n async statRoot(_ctx: RouteContext): Promise<AFSStatResult> {\n return {\n data: {\n id: \"agent\",\n path: \"/\",\n meta: {\n kind: \"afs:node\",\n kinds: [\"afs:node\"],\n name: \"agent\",\n description: \"Agentic run provider — exposes the `run` action\",\n childrenCount: 0,\n },\n },\n };\n }\n\n @Stat(\"/.actions/run\")\n async statRunAction(_ctx: RouteContext): Promise<AFSStatResult> {\n return {\n data: {\n id: \"run\",\n path: \"/.actions/run\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: \"run\",\n description: \"Run a single-task agentic loop\",\n },\n },\n };\n }\n\n @Actions(\"/\")\n async listRootActions(_ctx: RouteContext): Promise<AFSListResult> {\n return {\n data: [\n {\n id: \"run\",\n path: \"/.actions/run\",\n summary: \"Run a single-task agentic loop\",\n meta: {\n kind: \"afs:executable\",\n kinds: [\"afs:executable\", \"afs:node\"],\n name: \"run\",\n description:\n \"Execute a multi-round agentic loop: LLM inference → tool_call validation → tool execution → result feedback. Stops when the LLM returns text or budget exhausts.\",\n inputSchema: {\n type: \"object\",\n properties: {\n task: { type: \"string\", description: \"The task for the agent to accomplish\" },\n model: {\n type: \"string\",\n description: \"AI model path, e.g. /dev/ai/.actions/chat\",\n },\n tools: {\n description:\n \"AFS path patterns the LLM may call. `none` or empty array → LLM-only mode (no tool calling).\",\n },\n budget: {\n type: \"object\",\n description: \"Budget caps: { max_rounds?, total_tokens? }\",\n },\n session: { type: \"string\", description: \"Session id for queue + history\" },\n system: { type: \"string\", description: \"System prompt prefix\" },\n skill_paths: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Paths to skill SKILL.md files for prompt augmentation\",\n },\n write_to_path: {\n type: \"string\",\n description:\n \"AFS path to write the completed result text. When set and the agent completes successfully with text output, the text is written to this path and the response returns { path, byteCount, summary } instead of the full result.\",\n },\n },\n required: [\"task\", \"model\"],\n },\n },\n },\n ],\n } as AFSListResult;\n }\n\n @Actions.Exec(\"/\", undefined, undefined, { effect: \"write\" })\n async execRootAction(\n ctx: RouteContext<{ action: string }>,\n args: Record<string, unknown>,\n ): Promise<AFSExecResult> {\n const actionName = ctx.params.action;\n\n // Test-only introspection hook (Phase 3b). Echoes whether the\n // observability runtime capability was injected and which policy is in\n // effect — WITHOUT serializing the resolver handle (object capabilities\n // never leave the host). The `@Actions.Exec(\"/\")` decorator registers at\n // class-definition time and cannot be conditionally omitted, so the action\n // is always routable; the handler refuses outside test mode to avoid\n // leaking runtime wiring in production.\n if (actionName === \"__debug-runtime\") {\n return this.execDebugRuntime();\n }\n\n if (actionName !== \"run\") {\n return {\n success: false,\n error: {\n code: \"ACTION_NOT_FOUND\",\n message: `Unknown action '${actionName}' on agent-run provider; only 'run' is supported`,\n },\n } as AFSExecResult;\n }\n\n if (!this.afsRoot) {\n return {\n success: false,\n error: {\n code: \"AGENT_RUN_NOT_INITIALIZED\",\n message: \"AFSAgent has not been mounted yet — onMount has not fired\",\n },\n } as AFSExecResult;\n }\n\n const session = args.session as string | undefined;\n let result: AFSExecResult;\n try {\n result = await this.sessionQueue.enqueue(session, () =>\n executeAgentRun(args, {\n globalAfs: this.afsRoot,\n ashMountPath: this.ashMountPath,\n callerContext: ctx.context,\n observabilityRuntime: this.observabilityRuntime,\n }),\n );\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"QUEUE_FULL\")) {\n return {\n success: false,\n error: { code: \"QUEUE_FULL\", message: err.message },\n } as AFSExecResult;\n }\n throw err;\n }\n\n // Heartbeat self-check (issue #559, Phase 1). Emitted for every resolved\n // AFSExecResult (success AND failure) — a failed task is exactly the kind\n // of signal a self-check should be able to react to. Pre-execution throws\n // (QUEUE_FULL above, or executeAgentRun's own synchronous validation\n // throws for missing task/model/AFS root) never reach this point, so they\n // correctly produce no event — there's no completed task to report.\n // callerBlockletId comes from the top-level AFSContext.blockletId field\n // (NOT anything under `caller`/CallerInfo — that identifies the logged-in\n // user, not which blocklet's runtime dispatched this call, and using it\n // here would silently misattribute events across blocklets).\n this.emit({\n type: ASH_EVENT_TYPES.TASK_COMPLETE,\n path: \"/\",\n data: {\n success: result.success,\n errorCode: result.error?.code,\n model: typeof args.model === \"string\" ? args.model : undefined,\n durationMs: result.usage?.durationMs,\n callerBlockletId: ctx.context?.blockletId ?? undefined,\n session,\n },\n });\n\n return result;\n }\n\n /**\n * Handler for the test-only `__debug-runtime` action (Phase 3b). Returns a\n * boolean/string projection of the injected `observabilityRuntime` so E2E\n * tests can assert the capability reached `/dev/agent` — but it deliberately\n * omits the `spaceResolver` handle itself (object capability must not leave\n * the host). Outside `AFS_TEST_MODE` it refuses with `AFS_PERMISSION` so\n * production never exposes runtime wiring.\n */\n private execDebugRuntime(): AFSExecResult {\n if (!process.env.AFS_TEST_MODE) {\n return {\n success: false,\n error: {\n code: \"AFS_PERMISSION\",\n message: \"__debug-runtime is only available under AFS_TEST_MODE\",\n },\n } as AFSExecResult;\n }\n const rt = this.observabilityRuntime;\n return {\n success: true,\n data: {\n observabilityRuntime: {\n hasResolver: Boolean(rt?.spaceResolver),\n anonymousInteractivePersistence: rt?.anonymousInteractivePersistence ?? null,\n ownershipRoutingMode: rt?.ownershipRoutingMode ?? \"observe-only\",\n },\n },\n } as AFSExecResult;\n }\n}\n","/**\n * Scratchpad provisioning — allocates per-run scratch directories under\n * a session-scoped memory path.\n *\n * Provider internal: direct fs calls are allowed here (see CLAUDE.md).\n */\n\n// biome-ignore lint/style/noRestrictedImports: provider-internal (direct fs for atomic scratchpad ops)\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\n// biome-ignore lint/style/noRestrictedImports: provider-internal (filesystem path joining)\nimport { join } from \"node:path\";\nimport { load as parseYAML } from \"js-yaml\";\n\nexport interface ScratchLayout {\n basePath: string;\n stateYml: string;\n messagesJsonl: string;\n eventsJsonl: string;\n historyJsonl: string;\n}\n\nexport type ScratchRetention = \"run\" | \"session\" | \"forever\";\n\nfunction validatePathComponent(value: string, label: string): void {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new TypeError(`${label} must be a non-empty string`);\n }\n if (value.includes(\"..\")) {\n throw new Error(`path traversal disallowed in ${label}`);\n }\n if (value.includes(\"\\0\")) {\n throw new Error(`null byte disallowed in ${label}`);\n }\n}\n\nexport function allocateScratch(\n memoryBasePath: string,\n session: string,\n runId: string,\n): ScratchLayout {\n validatePathComponent(session, \"session\");\n validatePathComponent(runId, \"runId\");\n\n const basePath = join(memoryBasePath, \"runs\", session, \"subruns\", runId);\n mkdirSync(basePath, { recursive: true });\n\n const layout: ScratchLayout = {\n basePath,\n stateYml: join(basePath, \"state.yml\"),\n messagesJsonl: join(basePath, \"messages.jsonl\"),\n eventsJsonl: join(basePath, \"events.jsonl\"),\n historyJsonl: join(basePath, \"history.jsonl\"),\n };\n\n if (!existsSync(layout.stateYml)) writeFileSync(layout.stateYml, \"\");\n if (!existsSync(layout.messagesJsonl)) writeFileSync(layout.messagesJsonl, \"\");\n if (!existsSync(layout.eventsJsonl)) writeFileSync(layout.eventsJsonl, \"\");\n if (!existsSync(layout.historyJsonl)) writeFileSync(layout.historyJsonl, \"\");\n\n return layout;\n}\n\nexport function getStateProxy(layout: ScratchLayout): Record<string, any> {\n const raw = readFileSync(layout.stateYml, \"utf8\").trim();\n if (!raw) return Object.freeze({});\n\n let parsed: unknown;\n try {\n parsed = parseYAML(raw);\n } catch {\n return Object.freeze({});\n }\n\n if (parsed === null || parsed === undefined || typeof parsed !== \"object\") {\n return Object.freeze({});\n }\n\n return deepFreeze(parsed as Record<string, any>);\n}\n\nfunction deepFreeze<T extends Record<string, any>>(obj: T): T {\n for (const value of Object.values(obj)) {\n if (value && typeof value === \"object\" && !Object.isFrozen(value)) {\n deepFreeze(value);\n }\n }\n return Object.freeze(obj);\n}\n\nexport function teardownSession(\n memoryBasePath: string,\n session: string,\n retention: ScratchRetention = \"session\",\n): void {\n if (retention === \"forever\") return;\n\n const sessionSubrunsDir = join(memoryBasePath, \"runs\", session, \"subruns\");\n\n if (!existsSync(sessionSubrunsDir)) return;\n\n if (retention === \"session\") {\n rmSync(sessionSubrunsDir, { recursive: true, force: true });\n const sessionDir = join(memoryBasePath, \"runs\", session);\n try {\n rmSync(sessionDir, { recursive: true, force: true });\n } catch {\n // session dir may have other content\n }\n }\n // retention === \"run\": preserve everything (GC handles cleanup later)\n}\n"],"mappings":"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"}