@bluecopa/harness 0.1.0-snapshot.99 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,308 +0,0 @@
1
- import { tool, generateText, stepCountIs, streamText } from 'ai';
2
- import { anthropic } from '@ai-sdk/anthropic';
3
- import { z } from 'zod';
4
-
5
- // src/loop/vercel-agent-loop.ts
6
-
7
- // src/agent/types.ts
8
- function getTextContent(content) {
9
- if (typeof content === "string") return content;
10
- return content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
11
- }
12
-
13
- // src/arc/types.ts
14
- function resolveToolChoice(config, turn) {
15
- if (!config) return "auto";
16
- return typeof config === "function" ? config(turn) : config;
17
- }
18
- var builtinTools = {
19
- Bash: tool({
20
- description: "Run a shell command",
21
- inputSchema: z.object({
22
- command: z.string().describe("The shell command to run"),
23
- cwd: z.string().optional().describe("Working directory"),
24
- timeout: z.number().optional().describe("Timeout in milliseconds")
25
- })
26
- }),
27
- Read: tool({
28
- description: "Read a file from the filesystem",
29
- inputSchema: z.object({
30
- path: z.string().describe("Absolute path to the file")
31
- })
32
- }),
33
- Write: tool({
34
- description: "Write content to a file (creates or overwrites)",
35
- inputSchema: z.object({
36
- path: z.string().describe("Absolute path to the file"),
37
- content: z.string().describe("Content to write")
38
- })
39
- }),
40
- Edit: tool({
41
- description: "Replace text in a file (exact match)",
42
- inputSchema: z.object({
43
- path: z.string().describe("Absolute path to the file"),
44
- old_text: z.string().describe("Exact text to find"),
45
- new_text: z.string().describe("Replacement text")
46
- })
47
- }),
48
- Glob: tool({
49
- description: "Find files matching a glob pattern",
50
- inputSchema: z.object({
51
- pattern: z.string().describe("Glob pattern (e.g. **/*.ts)")
52
- })
53
- }),
54
- Grep: tool({
55
- description: "Search file contents with a regex pattern",
56
- inputSchema: z.object({
57
- pattern: z.string().describe("Regex pattern to search for"),
58
- path: z.string().optional().describe("Directory or file to search in")
59
- })
60
- }),
61
- WebFetch: tool({
62
- description: "Fetch content from a URL",
63
- inputSchema: z.object({
64
- url: z.string().describe("URL to fetch"),
65
- selector: z.string().optional().describe("CSS selector to extract"),
66
- maxContentLength: z.number().optional().describe("Max content length")
67
- })
68
- }),
69
- WebSearch: tool({
70
- description: "Search the web",
71
- inputSchema: z.object({
72
- query: z.string().describe("Search query")
73
- })
74
- }),
75
- AskUser: tool({
76
- description: "Ask the user a question and wait for their response",
77
- inputSchema: z.object({
78
- question: z.string().describe("The question to ask"),
79
- options: z.array(z.string()).optional().describe("Optional choices")
80
- })
81
- }),
82
- TellUser: tool({
83
- description: "Display a message to the user (no response expected)",
84
- inputSchema: z.object({
85
- message: z.string().describe("The message to display")
86
- })
87
- }),
88
- DownloadRawFile: tool({
89
- description: "Download a file from the sandbox to the local machine",
90
- inputSchema: z.object({
91
- path: z.string().describe("Sandbox path to download")
92
- })
93
- })
94
- };
95
- function toModelMessages(messages) {
96
- const out = [];
97
- for (const msg of messages) {
98
- if (msg.role === "system") {
99
- out.push({ role: "system", content: typeof msg.content === "string" ? msg.content : getTextContent(msg.content) });
100
- continue;
101
- }
102
- if (msg.role === "user") {
103
- out.push({ role: "user", content: msg.content });
104
- continue;
105
- }
106
- if (msg.role === "assistant") {
107
- const textContent = typeof msg.content === "string" ? msg.content : getTextContent(msg.content);
108
- if (msg.toolCalls && msg.toolCalls.length > 0) {
109
- const parts = [];
110
- if (textContent) {
111
- parts.push({ type: "text", text: textContent });
112
- }
113
- for (const tc of msg.toolCalls) {
114
- parts.push({
115
- type: "tool-call",
116
- toolCallId: tc.toolCallId,
117
- toolName: tc.toolName,
118
- input: tc.args
119
- });
120
- }
121
- out.push({ role: "assistant", content: parts });
122
- } else {
123
- out.push({ role: "assistant", content: textContent });
124
- }
125
- continue;
126
- }
127
- if (msg.role === "tool") {
128
- if (msg.toolResults && msg.toolResults.length > 0) {
129
- const parts = msg.toolResults.map((tr) => ({
130
- type: "tool-result",
131
- toolCallId: tr.toolCallId,
132
- toolName: tr.toolName,
133
- output: tr.isError ? { type: "error-text", value: tr.result } : { type: "text", value: tr.result }
134
- }));
135
- out.push({ role: "tool", content: parts });
136
- } else {
137
- const textContent = typeof msg.content === "string" ? msg.content : getTextContent(msg.content);
138
- out.push({ role: "user", content: `[Tool result]: ${textContent}` });
139
- }
140
- continue;
141
- }
142
- }
143
- return out;
144
- }
145
- var VercelAgentLoop = class _VercelAgentLoop {
146
- model;
147
- createModel;
148
- systemPrompt;
149
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
- tools;
151
- validToolNames;
152
- toolChoiceConfig;
153
- providerOptions;
154
- prepareStep;
155
- /** Track tool names called across steps for prepareStep context. */
156
- toolCallHistory = [];
157
- step = 0;
158
- /** Last step's token usage — read after nextAction/streamAction completes. */
159
- lastUsage;
160
- constructor(config = {}) {
161
- this.toolChoiceConfig = config.toolChoice;
162
- this.model = config.model ?? process.env.HARNESS_MODEL ?? "claude-sonnet-4-5";
163
- this.createModel = config.createModel ?? anthropic;
164
- this.tools = config.tools ?? builtinTools;
165
- this.validToolNames = new Set(Object.keys(this.tools));
166
- this.providerOptions = config.providerOptions;
167
- this.prepareStep = config.prepareStep;
168
- this.systemPrompt = config.systemPrompt ?? [
169
- "You are an agent that accomplishes tasks using tools.",
170
- "You may call multiple independent tools in a single turn.",
171
- "Use tools when shell or filesystem access is required.",
172
- "For file-generation tasks, prefer one-shot execution with a single Bash command (heredoc/script + run + verify) instead of repeated Write rewrites.",
173
- "Avoid rewriting the same file multiple times unless a previous run returned an error that requires a fix.",
174
- "When the task is fully complete, respond with a brief text summary (no tool call)."
175
- ].join(" ");
176
- if (config.apiKey) {
177
- process.env.ANTHROPIC_API_KEY = config.apiKey;
178
- }
179
- }
180
- /** Build the `system` parameter for generateText/streamText. */
181
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
- buildSystemParam() {
183
- if (typeof this.systemPrompt === "string") return this.systemPrompt;
184
- return this.systemPrompt.map((block) => ({
185
- role: "system",
186
- content: block.text,
187
- ...block.cacheControl ? { providerOptions: { anthropic: { cacheControl: block.cacheControl } } } : {}
188
- }));
189
- }
190
- /** Resolve model + tools for this step via prepareStep callback. */
191
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
192
- resolveStep(stepNumber) {
193
- if (!this.prepareStep) {
194
- return { model: this.model, tools: this.tools, validNames: this.validToolNames };
195
- }
196
- const overrides = this.prepareStep({ stepNumber, toolCallHistory: this.toolCallHistory });
197
- if (!overrides) {
198
- return { model: this.model, tools: this.tools, validNames: this.validToolNames };
199
- }
200
- const model = overrides.model ?? this.model;
201
- let tools = this.tools;
202
- let validNames = this.validToolNames;
203
- if (overrides.activeTools) {
204
- const allowed = new Set(overrides.activeTools);
205
- tools = Object.fromEntries(Object.entries(this.tools).filter(([k]) => allowed.has(k)));
206
- validNames = new Set(Object.keys(tools));
207
- }
208
- return { model, tools, validNames };
209
- }
210
- /** Extract StepUsage from AI SDK usage object. */
211
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
212
- static extractUsage(usage) {
213
- if (!usage) return void 0;
214
- const u = {};
215
- if (usage.inputTokens != null) u.inputTokens = usage.inputTokens;
216
- if (usage.outputTokens != null) u.outputTokens = usage.outputTokens;
217
- const inputDetails = usage.inputTokenDetails ?? usage;
218
- const outputDetails = usage.outputTokenDetails ?? usage;
219
- if (inputDetails.cacheReadTokens != null) u.cacheReadTokens = inputDetails.cacheReadTokens;
220
- if (inputDetails.cacheWriteTokens != null) u.cacheWriteTokens = inputDetails.cacheWriteTokens;
221
- if (outputDetails.reasoningTokens != null) u.reasoningTokens = outputDetails.reasoningTokens;
222
- return Object.keys(u).length > 0 ? u : void 0;
223
- }
224
- async nextAction(messages) {
225
- const currentStep = this.step++;
226
- const { model, tools, validNames } = this.resolveStep(currentStep + 1);
227
- const result = await generateText({
228
- model: this.createModel(model),
229
- tools,
230
- toolChoice: resolveToolChoice(this.toolChoiceConfig, currentStep),
231
- system: this.buildSystemParam(),
232
- messages: toModelMessages(messages),
233
- stopWhen: stepCountIs(1),
234
- ...this.providerOptions ? { providerOptions: this.providerOptions } : {}
235
- });
236
- this.lastUsage = _VercelAgentLoop.extractUsage(result.usage);
237
- if (result.toolCalls && result.toolCalls.length > 0) {
238
- const validCalls = [];
239
- for (const call of result.toolCalls) {
240
- const name = call.toolName;
241
- if (validNames.has(name)) {
242
- const toolCallId = call.toolCallId;
243
- validCalls.push({
244
- type: "tool",
245
- name,
246
- args: call.input,
247
- ...toolCallId != null ? { toolCallId } : {}
248
- });
249
- this.toolCallHistory.push(name);
250
- }
251
- }
252
- if (validCalls.length === 0) {
253
- return { type: "final", content: `Unknown tool: ${result.toolCalls[0].toolName}` };
254
- }
255
- if (validCalls.length === 1) {
256
- return validCalls[0];
257
- }
258
- return { type: "tool_batch", calls: validCalls };
259
- }
260
- const text = result.text?.trim();
261
- return { type: "final", content: text || "Done." };
262
- }
263
- async *streamAction(messages) {
264
- const currentStep = this.step++;
265
- const { model, tools, validNames } = this.resolveStep(currentStep + 1);
266
- const result = streamText({
267
- model: this.createModel(model),
268
- tools,
269
- toolChoice: resolveToolChoice(this.toolChoiceConfig, currentStep),
270
- system: this.buildSystemParam(),
271
- messages: toModelMessages(messages),
272
- stopWhen: stepCountIs(1),
273
- ...this.providerOptions ? { providerOptions: this.providerOptions } : {}
274
- });
275
- const toolArgs = /* @__PURE__ */ new Map();
276
- for await (const part of result.fullStream) {
277
- if (part.type === "text-delta") {
278
- yield { type: "text_delta", text: part.text };
279
- }
280
- if (part.type === "tool-input-start") {
281
- toolArgs.set(part.id, "");
282
- }
283
- if (part.type === "tool-input-delta") {
284
- toolArgs.set(part.id, (toolArgs.get(part.id) ?? "") + part.delta);
285
- }
286
- if (part.type === "tool-call") {
287
- const name = part.toolName;
288
- if (validNames.has(name)) {
289
- const p = part;
290
- const args = p.args ?? p.input ?? {};
291
- const toolCallId = p.toolCallId;
292
- yield { type: "tool_start", name, args, ...toolCallId != null ? { toolCallId } : {} };
293
- this.toolCallHistory.push(name);
294
- }
295
- }
296
- }
297
- try {
298
- const usage = await result.usage;
299
- this.lastUsage = _VercelAgentLoop.extractUsage(usage);
300
- } catch {
301
- this.lastUsage = void 0;
302
- }
303
- }
304
- };
305
-
306
- export { VercelAgentLoop, builtinTools };
307
- //# sourceMappingURL=vercel-agent-loop.js.map
308
- //# sourceMappingURL=vercel-agent-loop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/agent/types.ts","../../src/arc/types.ts","../../src/loop/vercel-agent-loop.ts"],"names":["defaultAnthropicProvider"],"mappings":"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","file":"vercel-agent-loop.js","sourcesContent":["export interface ToolCallInfo {\n toolCallId: string;\n toolName: string;\n args: Record<string, unknown>;\n /** Provider-specific metadata preserved across round-trips (e.g., Gemini thought signatures). */\n providerMetadata?: Record<string, unknown>;\n}\n\nexport interface ToolResultInfo {\n toolCallId: string;\n toolName: string;\n result: string;\n isError?: boolean;\n}\n\nexport type ContentPart =\n | { type: 'text'; text: string }\n | { type: 'image'; image: Buffer | Uint8Array; mimeType: string };\n\nexport interface AgentMessage {\n role: 'system' | 'user' | 'assistant' | 'tool';\n content: string | ContentPart[];\n toolCalls?: ToolCallInfo[]; // assistant messages: what tools were called\n toolResults?: ToolResultInfo[]; // tool messages: results keyed by toolCallId\n /** Provider-specific metadata preserved across round-trips (e.g., Gemini thought signatures). */\n providerMetadata?: Record<string, unknown>;\n}\n\n/** Extract plain text from content (string or ContentPart[]). */\nexport function getTextContent(content: string | ContentPart[]): string {\n if (typeof content === 'string') return content;\n return content\n .filter((p): p is Extract<ContentPart, { type: 'text' }> => p.type === 'text')\n .map((p) => p.text)\n .join('\\n');\n}\n\nexport interface ToolCallAction {\n type: 'tool';\n name: string;\n args: Record<string, unknown>;\n toolCallId?: string;\n}\n\nexport interface FinalAction {\n type: 'final';\n content: string;\n}\n\nexport interface ToolBatchAction {\n type: 'tool_batch';\n calls: ToolCallAction[];\n}\n\nexport type AgentAction = ToolCallAction | FinalAction | ToolBatchAction;\n\nexport interface AgentRunResult {\n messages: AgentMessage[];\n output: string;\n steps: number;\n}\n\n/** Token usage breakdown for a single LLM step. */\nexport interface StepUsage {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}\n\nexport type AgentStreamEvent =\n | { type: 'text_delta'; text: string }\n | { type: 'tool_start'; name: string; args: Record<string, unknown>; toolCallId?: string }\n | { type: 'tool_end'; name: string; result: { success: boolean; output: string; error?: string; [key: string]: unknown } }\n | { type: 'step_start'; step: number }\n | { type: 'step_end'; step: number; usage?: StepUsage }\n | { type: 'done'; output: string; steps: number };\n\nexport interface AgentLoop {\n nextAction(messages: AgentMessage[]): Promise<AgentAction>;\n streamAction?(messages: AgentMessage[]): AsyncIterable<AgentStreamEvent>;\n}\n\n/** Context passed to `prepareStep` before each LLM call. */\nexport interface PrepareStepContext {\n stepNumber: number;\n toolCallHistory: string[];\n}\n\n/** Overrides returned by `prepareStep`. All fields optional — omit to keep defaults. */\nexport interface PrepareStepResult {\n model?: string;\n activeTools?: string[];\n}\n","// ── Re-exports from shared types ──\n\nexport type {\n Episode,\n EpisodeTrace,\n SessionMemo,\n LongTermMemory,\n EpisodeStore,\n SessionMemoStore,\n LongTermStore,\n AnyTool,\n} from './arc-types';\n\nexport { DEFAULT_MODEL_MAP, resolveModel } from './arc-types';\nexport type { ModelTier } from './arc-types';\n\nexport type {\n AgentMessage,\n ToolCallAction,\n ToolCallInfo,\n ToolResultInfo,\n ContentPart,\n AgentRunResult,\n StepUsage,\n} from '../agent/types';\nexport { getTextContent } from '../agent/types';\n\nexport type { ToolProvider, ToolResult } from '../interfaces/tool-provider';\nexport type { SandboxProvider } from '../interfaces/sandbox-provider';\nexport type { HarnessTelemetry } from '../observability/otel';\nexport type { HookRunner } from '../hooks/hook-runner';\nexport type { PermissionManager } from '../permissions/permission-manager';\nexport type { SkillManager } from '../skills/skill-manager';\n\n// ── Episode artifacts ──\n\nexport interface EpisodeArtifact {\n key: string; // e.g. 'error_output', 'modified_code', 'test_result'\n content: string; // verbatim extracted content\n}\n\n// ── Model factory ──\n\n/** Creates an ai-sdk LanguageModel from a model ID string. Defaults to anthropic(). */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ModelFactory = (modelId: string) => any;\n\n// ── Tool choice ──\n\n/** Static tool choice value for LLM calls. */\nexport type ToolChoiceValue = 'auto' | 'required' | 'none' | { type: 'tool'; toolName: string };\n\n/**\n * Tool choice configuration — static value or per-turn callback.\n *\n * As a callback, receives the turn/step number (0-indexed) and returns the choice for that turn.\n * This enables patterns like forcing tool use on the first turn only:\n * `(turn) => turn === 0 ? 'required' : 'auto'`\n */\nexport type ToolChoiceConfig = ToolChoiceValue | ((turn: number) => ToolChoiceValue);\n\n/** Resolve a ToolChoiceConfig to a concrete value for a given turn. */\nexport function resolveToolChoice(config: ToolChoiceConfig | undefined, turn: number): ToolChoiceValue {\n if (!config) return 'auto';\n return typeof config === 'function' ? config(turn) : config;\n}\n\n// ── ArcLoop v2 Config ──\n\nexport interface ArcLoopConfig {\n // Orchestrator\n /** Orchestrator model (default: 'claude-opus-4-6'). Accepts a model ID or tier name. */\n model?: string;\n /** Model tier mapping. Override to use different models for fast/medium/strong. */\n modelMap?: Record<import('./arc-types').ModelTier, string>;\n /** Model factory — creates an ai-sdk LanguageModel from a model ID. Defaults to anthropic(). */\n createModel?: ModelFactory;\n /** @deprecated Use createModel instead. Anthropic API key (set via ANTHROPIC_API_KEY env var). */\n apiKey?: string;\n /** Custom orchestrator system prompt */\n systemPrompt?: string;\n /** Max orchestrator turns before stopping (default: 30) */\n maxTurns?: number;\n /** Extra orchestrator tools beyond Thread/Check/Cancel/Remember */\n extraOrchestratorTools?: Record<string, import('./arc-types').AnyTool>;\n /** Handler for extra orchestrator tools. Return an AgentAction (typically FinalAction with directive). */\n onOrchestratorTool?: (name: string, args: Record<string, unknown>) => Promise<import('../agent/types').AgentAction>;\n /** Optional resilience policy applied to LLM calls (retry, circuit breaker, timeout, etc.). */\n resilience?: import('./resilience/types').ResiliencePolicy;\n\n /** Tool choice for orchestrator LLM calls. Supports per-turn callbacks. Default: 'auto'. */\n orchestratorToolChoice?: ToolChoiceConfig;\n /** Default tool choice for all processes. Individual profiles can override. Default: 'auto'. */\n processToolChoice?: ToolChoiceConfig;\n\n /** ResultPager for storing large tool results externally in processes. */\n resultPager?: import('./result-pager').ResultPager;\n /** Character threshold above which tool results are paged. Default: 4000. */\n resultPageThreshold?: number;\n /** Tool names to never page (e.g., ['Read', 'Edit']). */\n pagingExclude?: string[];\n /** Hard cap on tool result length (chars) when no resultPager is configured. Truncates with a note. */\n maxToolResultLength?: number;\n /** Structured facts injected into process system prompts (e.g., from long-term memory). */\n contextFacts?: string[];\n /** Max context tokens for worker threads. When set, stubs old tool results to keep within budget. */\n maxContextTokens?: number;\n /**\n * Seed context injected into every process as a system message.\n * Use this to pass the user's original request, attachment metadata,\n * or other context that threads need but the orchestrator may not include\n * in the Thread action text.\n */\n processSeedContext?: string | import('../agent/types').AgentMessage[];\n\n // Processes\n /** Per-process timeout in ms (default: 120_000) */\n processTimeout?: number;\n /** Per-process max steps (default: 20) */\n processMaxSteps?: number;\n /** Default system prompt for all processes (overrides the built-in default) */\n processSystemPrompt?: string;\n /** Named process profiles. Accepts ProfileDeclaration (new, declarative) or ProcessProfile (legacy). */\n processProfiles?: Record<string, ProfileConfig>;\n /** Tools available inside processes (default: builtinTools) */\n processTools?: Record<string, import('./arc-types').AnyTool>;\n\n // Context\n /** Context window size in tokens (default: 200_000) */\n contextWindowSize?: number;\n /** Tokens reserved for output (default: 20_000) */\n outputReserve?: number;\n /**\n * Enable dynamic context window detection via OpenRouter API.\n * When true, fetches model-specific context_length from OpenRouter.\n * Falls back to 128K tokens for unknown models.\n * Overrides contextWindowSize if both are set.\n * @default false\n */\n dynamicContextWindow?: boolean;\n\n // Stores (required)\n episodeStore: import('./arc-types').EpisodeStore;\n sessionMemoStore: import('./arc-types').SessionMemoStore;\n longTermStore: import('./arc-types').LongTermStore;\n\n // Identity (required)\n taskId: string;\n sessionId: string;\n\n // Memory\n /** Enable auto-memory detection and promotion (default: true) */\n autoMemory?: boolean;\n\n // Dependency injection\n /** Pre-built SkillResolver instance. If omitted, one is created from skillIndexPath (if provided). */\n skillResolver?: import('./skill-resolver').SkillResolver;\n\n // Tools & providers\n toolProvider: import('../interfaces/tool-provider').ToolProvider;\n /** Tool provider for skill-matched processes (sandbox) */\n skillToolProvider?: import('../interfaces/tool-provider').ToolProvider;\n /** Local directory to sync sandbox output artifacts to (default: './outputs') */\n localOutputDir?: string;\n\n // Runtime (passed through to processes)\n sandboxProvider?: import('../interfaces/sandbox-provider').SandboxProvider;\n skillManager?: import('../skills/skill-manager').SkillManager;\n skillIndexPath?: string;\n telemetry?: import('../observability/otel').HarnessTelemetry;\n hookRunner?: import('../hooks/hook-runner').HookRunner;\n permissionManager?: import('../permissions/permission-manager').PermissionManager;\n executeToolAction?: (action: import('../agent/types').ToolCallAction) => Promise<import('../interfaces/tool-provider').ToolResult | null>;\n}\n\n// ── Process types ──\n\nexport interface Process {\n id: string;\n action: string;\n model: string;\n status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';\n\n /** Outbox: observable stream of events from this process. */\n outbox: AsyncIterable<ProcessEvent>;\n\n /** Inbox: send messages or signals to a running process. */\n inbox: {\n send(message: import('../agent/types').AgentMessage): void;\n cancel(): void;\n };\n\n /** Result (available after completion). */\n result?: ProcessResult;\n}\n\nexport type ProcessEvent =\n | { type: 'activity'; activity: Activity }\n | { type: 'text_delta'; text: string }\n | { type: 'step_start'; step: number }\n | { type: 'step_end'; step: number; usage?: import('../agent/types').StepUsage }\n | { type: 'episode'; episode: import('./arc-types').Episode }\n | { type: 'done'; result: ProcessResult }\n | { type: 'failed'; error: string };\n\nexport interface ProcessResult {\n episode: import('./arc-types').Episode;\n trace: import('./arc-types').EpisodeTrace;\n artifacts: EpisodeArtifact[];\n success: boolean;\n durationMs: number;\n resolvedModel: string;\n error?: string;\n}\n\nexport interface ProcessRequest {\n action: string;\n contextEpisodeIds?: string[];\n model?: import('./arc-types').ModelTier;\n maxSteps?: number;\n label?: string;\n /** Named profile to use for this process (looked up from ArcLoopConfig.processProfiles). */\n profile?: string;\n}\n\n/**\n * ProfileDeclaration — typed, declarative profile definition.\n *\n * Replaces hand-written system prompts with structured declarations.\n * The system generates prompts from the declaration and enforces tool constraints.\n *\n * @example\n * const visual: ProfileDeclaration = {\n * name: 'visual',\n * signature: 'description -> compiledArtifact',\n * tools: ['CompileJsx', 'Read', 'ListFiles'],\n * skills: ['visual-explainer'],\n * };\n */\nexport interface ProfileDeclaration {\n /** Profile name (matches the Thread tool's profile parameter). */\n name: string;\n /** Typed signature: \"input -> output\". Describes what this profile produces. */\n signature: string;\n /** Tool names this profile can use. Only these tools are available — enforced at schema + executor level. */\n tools: string[];\n /** Domain knowledge injected into system prompt (skill content, color systems, etc.). */\n background?: string;\n /** Default model tier. */\n model?: import('./arc-types').ModelTier;\n /** Max LLM steps. */\n maxSteps?: number;\n /** Skill names this profile can use. SkillRouter is constrained to this set. Omit for all skills. */\n skills?: string[];\n /** Few-shot demonstration examples. Rendered as user/assistant message pairs in the prompt. */\n demos?: Array<{\n input: Record<string, string>;\n output: Record<string, unknown>;\n }>;\n}\n\n/** A named process profile — runtime form with resolved prompt and tools. */\nexport interface ProcessProfile {\n /** System prompt for processes using this profile. */\n systemPrompt: string;\n /** Tools available to processes using this profile (overrides processTools). */\n tools?: Record<string, import('./arc-types').AnyTool>;\n /** Default model tier for this profile (Thread tool's explicit model overrides this). */\n model?: import('./arc-types').ModelTier;\n /** Max steps for this profile (Thread tool's explicit maxSteps overrides this). */\n maxSteps?: number;\n /** Allowed tool names for executor-level validation (populated from ProfileDeclaration.tools). */\n allowedToolNames?: string[];\n /** Zod schema for structured output on the terminal step (generated from typed signatures). */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n outputSchema?: import('zod').ZodObject<any>;\n /** Few-shot demo messages rendered before the task prompt. */\n demoMessages?: import('../agent/types').AgentMessage[];\n}\n\n/** A profile config can be either a declaration (new) or a raw ProcessProfile (backward compat). */\nexport type ProfileConfig = ProfileDeclaration | ProcessProfile;\n\n/** Type guard: check if a profile config is a declaration. */\nexport function isProfileDeclaration(p: ProfileConfig): p is ProfileDeclaration {\n return 'signature' in p && typeof (p as ProfileDeclaration).signature === 'string';\n}\n\nexport type Activity =\n | { type: 'tool_start'; name: string; args: Record<string, unknown>; ts: number }\n | { type: 'tool_end'; name: string; ok: boolean; ms: number; preview?: string; ts: number };\n\n// ── Context window types ──\n\nexport interface Turn {\n role: 'orchestrator' | 'process_result' | 'user';\n messages: import('../agent/types').AgentMessage[];\n tokenEstimate: number;\n timestamp: number;\n}\n\nexport interface TokenBudget {\n limit: number;\n used: number;\n layers: {\n system: number;\n memories: number;\n episodes: number;\n conversation: number;\n };\n}\n\nexport interface PreparedContext {\n messages: import('../agent/types').AgentMessage[];\n budget: TokenBudget;\n}\n\n// ── Compression types ──\n\nexport interface CompressInput {\n taskId: string;\n sessionId: string;\n index: number;\n threadAction: string;\n messages: import('../agent/types').AgentMessage[];\n model: string;\n parentEpisodeIds: string[];\n success: boolean;\n}\n\nexport interface CompressOutput {\n episode: import('./arc-types').Episode;\n trace: import('./arc-types').EpisodeTrace;\n artifacts: EpisodeArtifact[];\n}\n\n// ── Event protocol ──\n\nexport type ArcEvent =\n | { type: 'text_delta'; text: string }\n | { type: 'turn_start'; turn: number }\n | { type: 'turn_end'; turn: number }\n | { type: 'process_dispatched'; id: string; action: string; model: string; label?: string; profile?: string }\n | { type: 'thread_rejected'; action: string; reason: string }\n | { type: 'skill_resolved'; processId: string; skillName: string; skillPath: string }\n | { type: 'process_activity'; id: string; activity: Activity }\n | { type: 'process_text_delta'; id: string; text: string }\n | { type: 'process_step_start'; id: string; step: number }\n | { type: 'process_step_end'; id: string; step: number; usage?: import('../agent/types').StepUsage }\n | { type: 'process_completed'; id: string; episodeId: string; summary: string; durationMs: number }\n | { type: 'process_failed'; id: string; error: string }\n | { type: 'process_cancelled'; id: string }\n | { type: 'memory_stored'; id: string; content: string }\n | { type: 'context_compressed'; tier: 'template' | 'episode_group' | 'llm'; tokensSaved: number }\n | { type: 'done'; output: string; stats: RunStats };\n\nexport interface RunStats {\n turns: number;\n processes: number;\n durationMs: number;\n}\n\nexport interface ArcRunResult {\n output: string;\n events: ArcEvent[];\n}\n\n// ── Trace types (for Stateright verification bridge) ──\n\nexport interface TraceEvent {\n ts: number;\n kind: TraceEventKind;\n}\n\nexport type TraceEventKind =\n | { type: 'turn_start'; turn: number }\n | { type: 'turn_end'; turn: number }\n | { type: 'llm_call_start' }\n | { type: 'llm_call_end'; response_type: string }\n | { type: 'process_created'; id: string; status: string }\n | { type: 'process_transition'; id: string; from: string; to: string }\n | { type: 'tool_call'; tool: string; process_id?: string }\n | { type: 'context_prepare'; used: number; limit: number; compression_tier: string }\n | { type: 'abort_signal'; target?: string }\n | { type: 'done' };\n","import { generateText, streamText, stepCountIs, tool, type Tool } from 'ai';\nimport { anthropic as defaultAnthropicProvider } from '@ai-sdk/anthropic';\nimport type { ModelFactory, ToolChoiceConfig } from '../arc/types';\nimport { resolveToolChoice } from '../arc/types';\nimport { z } from 'zod';\n\nimport type { AgentAction, AgentMessage, AgentLoop, AgentStreamEvent, StepUsage, ToolCallAction, ToolBatchAction, PrepareStepContext, PrepareStepResult } from '../agent/types';\nimport { getTextContent } from '../agent/types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyTool = Tool<any, any>;\n\n// ── Native tool definitions (no execute — harness runs them) ──\n\n/** Built-in tool schemas. Merge with custom tools: `{ ...builtinTools, ...myTools }` */\nexport const builtinTools = {\n Bash: tool({\n description: 'Run a shell command',\n inputSchema: z.object({\n command: z.string().describe('The shell command to run'),\n cwd: z.string().optional().describe('Working directory'),\n timeout: z.number().optional().describe('Timeout in milliseconds'),\n }),\n }),\n Read: tool({\n description: 'Read a file from the filesystem',\n inputSchema: z.object({\n path: z.string().describe('Absolute path to the file'),\n }),\n }),\n Write: tool({\n description: 'Write content to a file (creates or overwrites)',\n inputSchema: z.object({\n path: z.string().describe('Absolute path to the file'),\n content: z.string().describe('Content to write'),\n }),\n }),\n Edit: tool({\n description: 'Replace text in a file (exact match)',\n inputSchema: z.object({\n path: z.string().describe('Absolute path to the file'),\n old_text: z.string().describe('Exact text to find'),\n new_text: z.string().describe('Replacement text'),\n }),\n }),\n Glob: tool({\n description: 'Find files matching a glob pattern',\n inputSchema: z.object({\n pattern: z.string().describe('Glob pattern (e.g. **/*.ts)'),\n }),\n }),\n Grep: tool({\n description: 'Search file contents with a regex pattern',\n inputSchema: z.object({\n pattern: z.string().describe('Regex pattern to search for'),\n path: z.string().optional().describe('Directory or file to search in'),\n }),\n }),\n WebFetch: tool({\n description: 'Fetch content from a URL',\n inputSchema: z.object({\n url: z.string().describe('URL to fetch'),\n selector: z.string().optional().describe('CSS selector to extract'),\n maxContentLength: z.number().optional().describe('Max content length'),\n }),\n }),\n WebSearch: tool({\n description: 'Search the web',\n inputSchema: z.object({\n query: z.string().describe('Search query'),\n }),\n }),\n AskUser: tool({\n description: 'Ask the user a question and wait for their response',\n inputSchema: z.object({\n question: z.string().describe('The question to ask'),\n options: z.array(z.string()).optional().describe('Optional choices'),\n }),\n }),\n TellUser: tool({\n description: 'Display a message to the user (no response expected)',\n inputSchema: z.object({\n message: z.string().describe('The message to display'),\n }),\n }),\n DownloadRawFile: tool({\n description: 'Download a file from the sandbox to the local machine',\n inputSchema: z.object({\n path: z.string().describe('Sandbox path to download'),\n }),\n }),\n};\n\n// ── Convert AgentMessage[] to Vercel AI SDK ModelMessage[] ──\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype ModelMessage = any;\n\nfunction toModelMessages(messages: AgentMessage[]): ModelMessage[] {\n const out: ModelMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === 'system') {\n // System messages are always text\n out.push({ role: 'system', content: typeof msg.content === 'string' ? msg.content : getTextContent(msg.content) });\n continue;\n }\n\n if (msg.role === 'user') {\n // Pass through ContentPart[] directly for multimodal (images)\n out.push({ role: 'user', content: msg.content });\n continue;\n }\n\n if (msg.role === 'assistant') {\n const textContent = typeof msg.content === 'string' ? msg.content : getTextContent(msg.content);\n if (msg.toolCalls && msg.toolCalls.length > 0) {\n // Structured assistant message with tool calls\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const parts: any[] = [];\n if (textContent) {\n parts.push({ type: 'text', text: textContent });\n }\n for (const tc of msg.toolCalls) {\n parts.push({\n type: 'tool-call',\n toolCallId: tc.toolCallId,\n toolName: tc.toolName,\n input: tc.args,\n });\n }\n out.push({ role: 'assistant', content: parts });\n } else {\n out.push({ role: 'assistant', content: textContent });\n }\n continue;\n }\n\n if (msg.role === 'tool') {\n if (msg.toolResults && msg.toolResults.length > 0) {\n // Structured tool result message\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const parts: any[] = msg.toolResults.map(tr => ({\n type: 'tool-result',\n toolCallId: tr.toolCallId,\n toolName: tr.toolName,\n output: tr.isError\n ? { type: 'error-text', value: tr.result }\n : { type: 'text', value: tr.result },\n }));\n out.push({ role: 'tool', content: parts });\n } else {\n // Fallback: no structured fields — wrap as user message\n const textContent = typeof msg.content === 'string' ? msg.content : getTextContent(msg.content);\n out.push({ role: 'user', content: `[Tool result]: ${textContent}` });\n }\n continue;\n }\n }\n\n return out;\n}\n\n/** A system prompt block with optional Anthropic cache control. */\nexport interface SystemPromptBlock {\n text: string;\n cacheControl?: { type: 'ephemeral' };\n}\n\nexport interface VercelAgentLoopConfig {\n model?: string;\n /** System prompt — string or structured blocks with cache control markers. */\n systemPrompt?: string | SystemPromptBlock[];\n createModel?: ModelFactory;\n /** @deprecated Prefer createModel. */\n apiKey?: string;\n /** Custom tool definitions. If provided, replaces built-in agentTools for LLM calls. */\n tools?: Record<string, AnyTool>;\n /** Tool choice for LLM calls. Supports per-turn callbacks. Default: 'auto'. */\n toolChoice?: ToolChoiceConfig;\n /** Provider options passed to generateText/streamText (e.g. anthropic thinking config). */\n providerOptions?: Record<string, unknown>;\n /** Per-step callback to override model and active tools before each LLM call. */\n prepareStep?: (context: PrepareStepContext) => PrepareStepResult | void;\n}\n\nexport class VercelAgentLoop implements AgentLoop {\n private readonly model: string;\n private readonly createModel: ModelFactory;\n private readonly systemPrompt: string | SystemPromptBlock[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private readonly tools: Record<string, AnyTool>;\n private readonly validToolNames: Set<string>;\n private readonly toolChoiceConfig: ToolChoiceConfig | undefined;\n private readonly providerOptions: Record<string, unknown> | undefined;\n private readonly prepareStep: VercelAgentLoopConfig['prepareStep'];\n /** Track tool names called across steps for prepareStep context. */\n private toolCallHistory: string[] = [];\n private step = 0;\n\n /** Last step's token usage — read after nextAction/streamAction completes. */\n public lastUsage: StepUsage | undefined;\n\n constructor(config: VercelAgentLoopConfig = {}) {\n this.toolChoiceConfig = config.toolChoice;\n this.model = config.model ?? process.env.HARNESS_MODEL ?? 'claude-sonnet-4-5';\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.createModel = config.createModel ?? defaultAnthropicProvider;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.tools = config.tools ?? builtinTools as any;\n this.validToolNames = new Set(Object.keys(this.tools));\n this.providerOptions = config.providerOptions;\n this.prepareStep = config.prepareStep;\n this.systemPrompt =\n config.systemPrompt ??\n [\n 'You are an agent that accomplishes tasks using tools.',\n 'You may call multiple independent tools in a single turn.',\n 'Use tools when shell or filesystem access is required.',\n 'For file-generation tasks, prefer one-shot execution with a single Bash command (heredoc/script + run + verify) instead of repeated Write rewrites.',\n 'Avoid rewriting the same file multiple times unless a previous run returned an error that requires a fix.',\n 'When the task is fully complete, respond with a brief text summary (no tool call).',\n ].join(' ');\n\n if (config.apiKey) {\n process.env.ANTHROPIC_API_KEY = config.apiKey;\n }\n }\n\n /** Build the `system` parameter for generateText/streamText. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private buildSystemParam(): any {\n if (typeof this.systemPrompt === 'string') return this.systemPrompt;\n // Structured blocks → AI SDK v6 SystemModelMessage format\n return this.systemPrompt.map(block => ({\n role: 'system' as const,\n content: block.text,\n ...(block.cacheControl\n ? { providerOptions: { anthropic: { cacheControl: block.cacheControl } } }\n : {}),\n }));\n }\n\n /** Resolve model + tools for this step via prepareStep callback. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private resolveStep(stepNumber: number): { model: string; tools: Record<string, any>; validNames: Set<string> } {\n if (!this.prepareStep) {\n return { model: this.model, tools: this.tools, validNames: this.validToolNames };\n }\n const overrides = this.prepareStep({ stepNumber, toolCallHistory: this.toolCallHistory });\n if (!overrides) {\n return { model: this.model, tools: this.tools, validNames: this.validToolNames };\n }\n const model = overrides.model ?? this.model;\n let tools: Record<string, AnyTool> = this.tools;\n let validNames = this.validToolNames;\n if (overrides.activeTools) {\n const allowed = new Set(overrides.activeTools);\n tools = Object.fromEntries(Object.entries(this.tools).filter(([k]) => allowed.has(k)));\n validNames = new Set(Object.keys(tools));\n }\n return { model, tools, validNames };\n }\n\n /** Extract StepUsage from AI SDK usage object. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private static extractUsage(usage: any): StepUsage | undefined {\n if (!usage) return undefined;\n const u: StepUsage = {};\n if (usage.inputTokens != null) u.inputTokens = usage.inputTokens;\n if (usage.outputTokens != null) u.outputTokens = usage.outputTokens;\n // AI SDK v6 nests cache/reasoning under inputTokenDetails/outputTokenDetails\n const inputDetails = usage.inputTokenDetails ?? usage;\n const outputDetails = usage.outputTokenDetails ?? usage;\n if (inputDetails.cacheReadTokens != null) u.cacheReadTokens = inputDetails.cacheReadTokens;\n if (inputDetails.cacheWriteTokens != null) u.cacheWriteTokens = inputDetails.cacheWriteTokens;\n if (outputDetails.reasoningTokens != null) u.reasoningTokens = outputDetails.reasoningTokens;\n return Object.keys(u).length > 0 ? u : undefined;\n }\n\n async nextAction(messages: AgentMessage[]): Promise<AgentAction> {\n const currentStep = this.step++;\n\n const { model, tools, validNames } = this.resolveStep(currentStep + 1);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await (generateText as any)({\n model: this.createModel(model),\n tools,\n toolChoice: resolveToolChoice(this.toolChoiceConfig, currentStep),\n system: this.buildSystemParam(),\n messages: toModelMessages(messages),\n stopWhen: stepCountIs(1),\n ...(this.providerOptions ? { providerOptions: this.providerOptions } : {}),\n });\n\n // Capture usage\n this.lastUsage = VercelAgentLoop.extractUsage(result.usage);\n\n // If the model made tool calls, extract them\n if (result.toolCalls && result.toolCalls.length > 0) {\n const validCalls: ToolCallAction[] = [];\n for (const call of result.toolCalls) {\n const name = call.toolName;\n if (validNames.has(name)) {\n const toolCallId = (call as { toolCallId?: string }).toolCallId;\n validCalls.push({\n type: 'tool',\n name,\n args: (call as { input: Record<string, unknown> }).input,\n ...(toolCallId != null ? { toolCallId } : {}),\n });\n this.toolCallHistory.push(name);\n }\n }\n\n if (validCalls.length === 0) {\n return { type: 'final', content: `Unknown tool: ${result.toolCalls[0]!.toolName}` };\n }\n\n // Single call → backward-compatible ToolCallAction\n if (validCalls.length === 1) {\n return validCalls[0]!;\n }\n\n // Multiple calls → ToolBatchAction\n return { type: 'tool_batch', calls: validCalls } satisfies ToolBatchAction;\n }\n\n // No tool call — model responded with text (task complete)\n const text = result.text?.trim();\n return { type: 'final', content: text || 'Done.' };\n }\n\n async *streamAction(messages: AgentMessage[]): AsyncGenerator<AgentStreamEvent> {\n const currentStep = this.step++;\n\n const { model, tools, validNames } = this.resolveStep(currentStep + 1);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (streamText as any)({\n model: this.createModel(model),\n tools,\n toolChoice: resolveToolChoice(this.toolChoiceConfig, currentStep),\n system: this.buildSystemParam(),\n messages: toModelMessages(messages),\n stopWhen: stepCountIs(1),\n ...(this.providerOptions ? { providerOptions: this.providerOptions } : {}),\n });\n\n const toolArgs = new Map<string, string>();\n\n for await (const part of result.fullStream) {\n if (part.type === 'text-delta') {\n yield { type: 'text_delta', text: part.text };\n }\n if (part.type === 'tool-input-start') {\n toolArgs.set(part.id, '');\n }\n if (part.type === 'tool-input-delta') {\n toolArgs.set(part.id, (toolArgs.get(part.id) ?? '') + part.delta);\n }\n if (part.type === 'tool-call') {\n const name = part.toolName;\n if (validNames.has(name)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const p = part as any;\n const args: Record<string, unknown> = p.args ?? p.input ?? {};\n const toolCallId: string | undefined = p.toolCallId;\n yield { type: 'tool_start', name, args, ...(toolCallId != null ? { toolCallId } : {}) };\n this.toolCallHistory.push(name);\n }\n }\n }\n\n // Capture usage after stream completes\n try {\n const usage = await result.usage;\n this.lastUsage = VercelAgentLoop.extractUsage(usage);\n } catch {\n this.lastUsage = undefined;\n }\n }\n}\n"]}