@bluecopa/harness 1.0.0 → 2.0.1-snapshot.1

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.
Files changed (84) hide show
  1. package/README.md +212 -117
  2. package/dist/arc/index.d.ts +1107 -0
  3. package/dist/arc/index.js +4986 -0
  4. package/dist/arc/index.js.map +1 -0
  5. package/dist/observability/otel.d.ts +36 -0
  6. package/dist/observability/otel.js +73 -0
  7. package/dist/observability/otel.js.map +1 -0
  8. package/dist/shared-types-vZuVoy_H.d.ts +147 -0
  9. package/dist/skills/index.d.ts +67 -0
  10. package/dist/skills/index.js +282 -0
  11. package/dist/skills/index.js.map +1 -0
  12. package/package.json +25 -1
  13. package/AGENTS.md +0 -18
  14. package/docs/guides/observability.md +0 -32
  15. package/docs/guides/providers.md +0 -51
  16. package/docs/guides/skills.md +0 -25
  17. package/docs/security/skill-sandbox-threat-model.md +0 -20
  18. package/src/agent/create-agent.ts +0 -884
  19. package/src/agent/create-tools.ts +0 -33
  20. package/src/agent/step-executor.ts +0 -15
  21. package/src/agent/types.ts +0 -57
  22. package/src/context/llm-compaction-strategy.ts +0 -37
  23. package/src/context/prepare-step.ts +0 -65
  24. package/src/context/token-tracker.ts +0 -26
  25. package/src/extracted/manifest.json +0 -10
  26. package/src/extracted/prompts/compaction.md +0 -5
  27. package/src/extracted/prompts/system.md +0 -5
  28. package/src/extracted/tools.json +0 -82
  29. package/src/hooks/hook-runner.ts +0 -22
  30. package/src/hooks/tool-wrappers.ts +0 -64
  31. package/src/interfaces/compaction-strategy.ts +0 -18
  32. package/src/interfaces/hooks.ts +0 -24
  33. package/src/interfaces/sandbox-provider.ts +0 -29
  34. package/src/interfaces/session-store.ts +0 -48
  35. package/src/interfaces/tool-provider.ts +0 -70
  36. package/src/loop/bridge.ts +0 -363
  37. package/src/loop/context-store.ts +0 -207
  38. package/src/loop/lcm-tool-loop.ts +0 -163
  39. package/src/loop/vercel-agent-loop.ts +0 -279
  40. package/src/observability/context.ts +0 -17
  41. package/src/observability/metrics.ts +0 -27
  42. package/src/observability/otel.ts +0 -105
  43. package/src/observability/tracing.ts +0 -13
  44. package/src/optimization/agent-evaluator.ts +0 -40
  45. package/src/optimization/config-serializer.ts +0 -16
  46. package/src/optimization/optimization-runner.ts +0 -39
  47. package/src/optimization/trace-collector.ts +0 -33
  48. package/src/permissions/permission-manager.ts +0 -34
  49. package/src/providers/composite-tool-provider.ts +0 -72
  50. package/src/providers/control-plane-e2b-executor.ts +0 -218
  51. package/src/providers/e2b-tool-provider.ts +0 -68
  52. package/src/providers/local-tool-provider.ts +0 -190
  53. package/src/providers/skill-sandbox-provider.ts +0 -46
  54. package/src/sessions/file-session-store.ts +0 -61
  55. package/src/sessions/in-memory-session-store.ts +0 -39
  56. package/src/sessions/session-manager.ts +0 -44
  57. package/src/skills/skill-loader.ts +0 -52
  58. package/src/skills/skill-manager.ts +0 -175
  59. package/src/skills/skill-router.ts +0 -99
  60. package/src/skills/skill-types.ts +0 -26
  61. package/src/subagents/subagent-manager.ts +0 -22
  62. package/src/subagents/task-tool.ts +0 -13
  63. package/tests/integration/agent-loop-basic.spec.ts +0 -56
  64. package/tests/integration/agent-skill-default-from-sandbox.spec.ts +0 -66
  65. package/tests/integration/concurrency-single-turn.spec.ts +0 -35
  66. package/tests/integration/otel-metrics-emission.spec.ts +0 -62
  67. package/tests/integration/otel-trace-propagation.spec.ts +0 -48
  68. package/tests/integration/parity-benchmark.spec.ts +0 -45
  69. package/tests/integration/provider-local-smoke.spec.ts +0 -63
  70. package/tests/integration/session-resume.spec.ts +0 -30
  71. package/tests/integration/skill-install-rollback.spec.ts +0 -64
  72. package/tests/integration/skill-sandbox-file-blob.spec.ts +0 -54
  73. package/tests/integration/skills-progressive-disclosure.spec.ts +0 -61
  74. package/tests/integration/streaming-compaction-boundary.spec.ts +0 -43
  75. package/tests/integration/structured-messages-agent.spec.ts +0 -265
  76. package/tests/integration/subagent-isolation.spec.ts +0 -24
  77. package/tests/security/skill-sandbox-isolation.spec.ts +0 -51
  78. package/tests/unit/create-tools-schema-parity.spec.ts +0 -22
  79. package/tests/unit/extracted-manifest.spec.ts +0 -41
  80. package/tests/unit/interfaces-contract.spec.ts +0 -101
  81. package/tests/unit/structured-messages.spec.ts +0 -176
  82. package/tests/unit/token-tracker.spec.ts +0 -22
  83. package/tsconfig.json +0 -14
  84. package/vitest.config.ts +0 -7
@@ -0,0 +1,1107 @@
1
+ import { A as AnyTool, T as ToolProvider, a as ToolResult, M as ModelFactory, b as ToolResultArtifact } from '../shared-types-vZuVoy_H.js';
2
+ export { c as ActionType, B as BashOptions, d as BatchOp, e as BatchResult, G as GlobOptions, f as GrepOptions, R as ReadOptions, g as TextEditorRequest, h as ThreadStatus, i as ToolProviderCapabilities, W as WebFetchOptions } from '../shared-types-vZuVoy_H.js';
3
+ import { HarnessTelemetry } from '../observability/otel.js';
4
+ import 'ai';
5
+
6
+ /** Long-running job orchestration primitives. Generic; no coding-agent assumptions. */
7
+ type JobKind = "local" | "remote";
8
+ /** Discriminated on `kind` so remote-only fields only exist on remote transports. */
9
+ type JobTransport = {
10
+ kind: "local";
11
+ } | {
12
+ kind: "remote";
13
+ host: string;
14
+ user?: string | undefined;
15
+ keyPath?: string | undefined;
16
+ };
17
+ interface JobSpec {
18
+ id: string;
19
+ label: string;
20
+ command: string;
21
+ cwd?: string | undefined;
22
+ env?: Record<string, string> | undefined;
23
+ transport: JobTransport;
24
+ startedAt: number;
25
+ startedBy?: {
26
+ tupleId?: string | undefined;
27
+ turn?: number | undefined;
28
+ } | undefined;
29
+ }
30
+ type JobState = "running" | "exited" | "failed" | "killed" | "unknown";
31
+ interface JobStatus {
32
+ spec: JobSpec;
33
+ state: JobState;
34
+ /** Local supervisor PID. */
35
+ pid?: number | undefined;
36
+ /** Remote parent PID (only set when transport.kind === "remote"). */
37
+ remotePid?: number | undefined;
38
+ exitCode?: number | undefined;
39
+ /** Mirrors spec.startedAt; kept on the status for convenience when reading status without spec unpacking. */
40
+ startedAt: number;
41
+ endedAt?: number | undefined;
42
+ lastSeenAliveAt: number;
43
+ tailLines: string[];
44
+ bytesWritten: number;
45
+ }
46
+ type JobEvent = {
47
+ type: "job_started";
48
+ status: JobStatus;
49
+ } | {
50
+ type: "job_output";
51
+ id: string;
52
+ chunk: string;
53
+ at: number;
54
+ } | {
55
+ type: "job_exited";
56
+ status: JobStatus;
57
+ } | {
58
+ type: "job_failed";
59
+ status: JobStatus;
60
+ error: string;
61
+ } | {
62
+ type: "job_killed";
63
+ status: JobStatus;
64
+ reason: string;
65
+ };
66
+ interface JobStartOptions {
67
+ label: string;
68
+ command: string;
69
+ transport?: JobTransport | undefined;
70
+ cwd?: string | undefined;
71
+ env?: Record<string, string> | undefined;
72
+ }
73
+ interface JobRegistry {
74
+ start(opts: JobStartOptions, startedBy?: JobSpec["startedBy"]): Promise<JobStatus>;
75
+ check(id: string): Promise<JobStatus | null>;
76
+ cancel(id: string, signal?: "TERM" | "KILL"): Promise<JobStatus | null>;
77
+ list(): Promise<JobStatus[]>;
78
+ tail(id: string, lines?: number): Promise<string[]>;
79
+ waitFor(id: string, signal?: AbortSignal): Promise<JobStatus>;
80
+ subscribe(handler: (e: JobEvent) => void): () => void;
81
+ /** Cheap synchronous snapshot — suitable for orchestrator context each turn. */
82
+ snapshot(): JobStatus[];
83
+ /** Remove completed/killed/failed jobs older than `olderThanMs` (default 24h). Returns count removed. */
84
+ prune(olderThanMs?: number): Promise<number>;
85
+ }
86
+
87
+ interface ToolCallInfo {
88
+ toolCallId: string;
89
+ toolName: string;
90
+ args: Record<string, unknown>;
91
+ /** Provider-specific metadata preserved across round-trips (e.g., Gemini thought signatures). */
92
+ providerMetadata?: Record<string, unknown>;
93
+ }
94
+ interface ToolResultInfo {
95
+ toolCallId: string;
96
+ toolName: string;
97
+ result: string;
98
+ isError?: boolean;
99
+ durationMs?: number;
100
+ }
101
+ type ContentPart = {
102
+ type: "text";
103
+ text: string;
104
+ } | {
105
+ type: "image";
106
+ image: Buffer | Uint8Array;
107
+ mimeType: string;
108
+ };
109
+ interface AgentMessage {
110
+ role: "system" | "user" | "assistant" | "tool";
111
+ content: string | ContentPart[];
112
+ toolCalls?: ToolCallInfo[];
113
+ toolResults?: ToolResultInfo[];
114
+ /** Provider-specific metadata preserved across round-trips (e.g., Gemini thought signatures). */
115
+ providerMetadata?: Record<string, unknown>;
116
+ }
117
+
118
+ /**
119
+ * Tool registry: the Tool contract and schema extraction.
120
+ *
121
+ * Agent tool definitions (Bash, Read, Write, etc.) live in the consumer
122
+ * (truecode). The harness only provides the Tool contract and helpers.
123
+ */
124
+
125
+ type ToolExecutionMode = "serial" | "parallel";
126
+ /** A registered tool: schema for the model, execute for the worker */
127
+ interface Tool {
128
+ name: string;
129
+ /** AI SDK tool schema. Optional for ARC-internal tools (ReadEpisode, LCM_*, ScratchPad_*). */
130
+ schema?: AnyTool | undefined;
131
+ /** Worker execution mode for batched tool calls. Defaults to serial. */
132
+ executionMode?: ToolExecutionMode | ((args: Record<string, unknown>) => ToolExecutionMode);
133
+ /** Execute using the ToolProvider. If not set, tool is handled externally (e.g. ARC tools). */
134
+ execute?: (provider: ToolProvider, args: Record<string, unknown>, workDir: string) => Promise<ToolResult>;
135
+ /**
136
+ * When true, this tool may yield the worker loop if the operation is incomplete.
137
+ * After execution, the worker checks if the target thread is still running.
138
+ * If it is and `waitForThread` is available on the ToolProvider, the worker
139
+ * suspends (does not count a step) until the thread completes.
140
+ * The tool args must include a `threadId` field for the worker to track.
141
+ */
142
+ yieldsOnIncomplete?: boolean | undefined;
143
+ }
144
+
145
+ /**
146
+ * Serialized attachment form suitable for JSON persistence. Unlike the in-flight
147
+ * `ContentPart` (which carries a `Buffer`), the stored form keeps image bytes
148
+ * base64-encoded so messages round-trip cleanly through session snapshots.
149
+ * Converted to a real `ContentPart` only when building AgentMessage[] for the model.
150
+ */
151
+ interface StoredAttachment {
152
+ type: "image";
153
+ imageBase64: string;
154
+ mimeType: string;
155
+ }
156
+ interface StoredMessage {
157
+ id: string;
158
+ conversationId: string;
159
+ index: number;
160
+ role: "user" | "assistant" | "tool";
161
+ content: string;
162
+ toolCalls?: ToolCallInfo[];
163
+ toolResults?: ToolResultInfo[];
164
+ /** Multimodal image attachments. Persisted as base64; converted to ContentPart[] at model-call time. */
165
+ attachments?: StoredAttachment[];
166
+ timestamp: number;
167
+ }
168
+ interface GrepResult {
169
+ messageId: string;
170
+ conversationId: string;
171
+ messageIndex: number;
172
+ excerpt: string;
173
+ matchContext: string;
174
+ }
175
+ interface MessageStore {
176
+ append(message: StoredMessage): void;
177
+ getConversation(conversationId: string): StoredMessage[];
178
+ getMessage(conversationId: string, index: number): StoredMessage | null;
179
+ grep(pattern: string, opts?: {
180
+ conversationId?: string;
181
+ maxResults?: number;
182
+ }): GrepResult[];
183
+ /** Serialize all messages for session persistence. */
184
+ serialize(): StoredMessage[];
185
+ /** Load serialized messages into this store (for session hydration). */
186
+ loadFrom(messages: StoredMessage[]): void;
187
+ }
188
+ declare class MemoryMessageStore implements MessageStore {
189
+ private messages;
190
+ private byConversation;
191
+ append(message: StoredMessage): void;
192
+ getConversation(conversationId: string): StoredMessage[];
193
+ getMessage(conversationId: string, index: number): StoredMessage | null;
194
+ serialize(): StoredMessage[];
195
+ loadFrom(messages: StoredMessage[]): void;
196
+ static hydrate(messages: StoredMessage[]): MemoryMessageStore;
197
+ grep(pattern: string, opts?: {
198
+ conversationId?: string;
199
+ maxResults?: number;
200
+ }): GrepResult[];
201
+ }
202
+
203
+ interface SummaryNode {
204
+ id: string;
205
+ depth: number;
206
+ sourceIds: string[];
207
+ sourceConversationIds: string[];
208
+ summary: string;
209
+ artifacts: string[];
210
+ operations: string[];
211
+ outcome: string;
212
+ tokenCount: number;
213
+ createdAt: number;
214
+ }
215
+ interface CompactionOpts {
216
+ /** Minimum number of uncovered children before compaction triggers (default: 4) */
217
+ minChildren?: number;
218
+ /** Soft token budget — compact when total tokens at a depth exceed this (default: 8000) */
219
+ softTokenBudget?: number;
220
+ }
221
+ interface SummaryDAG {
222
+ addLeaf(node: SummaryNode): void;
223
+ compact(opts?: CompactionOpts): SummaryNode[];
224
+ getNode(id: string): SummaryNode | null;
225
+ getLineage(id: string, visited?: Set<string>): string[];
226
+ getFrontier(budget: number): {
227
+ frontier: SummaryNode[];
228
+ coveredIds: Set<string>;
229
+ };
230
+ getAllNodes(): SummaryNode[];
231
+ /** Serialize DAG state for session persistence. */
232
+ serialize(): {
233
+ nodes: SummaryNode[];
234
+ coveredBy: [string, string][];
235
+ };
236
+ /** Load serialized DAG state into this instance (for session hydration). */
237
+ loadFrom(data: {
238
+ nodes: SummaryNode[];
239
+ coveredBy: [string, string][];
240
+ }): void;
241
+ }
242
+ declare class MemorySummaryDAG implements SummaryDAG {
243
+ private nodes;
244
+ /** Tracks which source IDs have been covered by a parent node */
245
+ private coveredBy;
246
+ serialize(): {
247
+ nodes: SummaryNode[];
248
+ coveredBy: [string, string][];
249
+ };
250
+ loadFrom(data: {
251
+ nodes: SummaryNode[];
252
+ coveredBy: [string, string][];
253
+ }): void;
254
+ static hydrate(data: {
255
+ nodes: SummaryNode[];
256
+ coveredBy: [string, string][];
257
+ }): MemorySummaryDAG;
258
+ addLeaf(node: SummaryNode): void;
259
+ compact(opts?: CompactionOpts): SummaryNode[];
260
+ getNode(id: string): SummaryNode | null;
261
+ getLineage(id: string, visited?: Set<string>): string[];
262
+ getFrontier(budget: number): {
263
+ frontier: SummaryNode[];
264
+ coveredIds: Set<string>;
265
+ };
266
+ getAllNodes(): SummaryNode[];
267
+ }
268
+
269
+ interface GhostCue {
270
+ summaryId: string;
271
+ conversationIds: string[];
272
+ depth: number;
273
+ label: string;
274
+ }
275
+ interface AssembledContext {
276
+ messages: AgentMessage[];
277
+ ghostCues: GhostCue[];
278
+ tokenEstimate: number;
279
+ /** Structured sections for downstream consumers (avoids string matching) */
280
+ frontierText?: string;
281
+ ghostCueText?: string;
282
+ }
283
+
284
+ type HookEventName = 'PreToolUse' | 'PostToolUse' | 'BeforeWorker' | 'AfterWorker';
285
+ interface HookContext {
286
+ event: HookEventName;
287
+ toolName?: string;
288
+ input?: Record<string, unknown>;
289
+ output?: ToolResult;
290
+ metadata?: Record<string, unknown>;
291
+ }
292
+ interface HookDecision {
293
+ allow: boolean;
294
+ reason?: string;
295
+ }
296
+ type HookCallback = (context: HookContext) => Promise<HookDecision | void>;
297
+
298
+ declare class HookRunner {
299
+ private readonly hooks;
300
+ register(event: HookContext['event'], callback: HookCallback): void;
301
+ run(context: HookContext): Promise<HookDecision>;
302
+ }
303
+
304
+ /** Raw worker transcript, append-only storage */
305
+ interface Transcript {
306
+ id: string;
307
+ tupleId: string;
308
+ instruction: string;
309
+ messages: AgentMessage[];
310
+ timestamp: number;
311
+ }
312
+ /** Artifact produced by a worker dispatch */
313
+ interface Artifact {
314
+ id: string;
315
+ tupleId: string;
316
+ /** File path or returned value */
317
+ output: string | null;
318
+ /** Full textual worker result, preserved even when expected file artifacts are missing */
319
+ textOutput?: string | undefined;
320
+ status: "complete" | "incomplete" | "failed" | "interrupted";
321
+ /** One-line summary from worker's final message */
322
+ summary: string;
323
+ stepsUsed: number;
324
+ /** Tool calls with results (for orchestrator reasoning) */
325
+ actions?: string[];
326
+ /** The dispatch instruction that produced this artifact */
327
+ instruction?: string;
328
+ }
329
+ interface ExpectedArtifact {
330
+ type: "file" | "directory" | "value" | "unknown";
331
+ path?: string | undefined;
332
+ description?: string | undefined;
333
+ }
334
+ interface ExpectedOutputContract {
335
+ artifacts: ExpectedArtifact[];
336
+ successCriteria?: string[] | undefined;
337
+ verification?: string | undefined;
338
+ description?: string | undefined;
339
+ }
340
+ /** Worker model tier for dispatch routing. */
341
+ type DispatchTier = "fast" | "medium" | "strong";
342
+ /** Worker instruction tuple */
343
+ interface Tuple {
344
+ id: string;
345
+ instruction: string;
346
+ /** Artifact IDs to provide as input */
347
+ inputs: string[];
348
+ /** Structured contract for what the worker should produce */
349
+ expectedOutput: ExpectedOutputContract;
350
+ /** Tool names available to worker */
351
+ tools: string[];
352
+ /** Step budget */
353
+ steps: number;
354
+ /** Worker model tier. Omitted dispatches use the default step budget and strong worker model. */
355
+ tier?: DispatchTier | undefined;
356
+ /** Semantic role label for this worker (e.g. "Debugger", "Researcher", "Sysadmin").
357
+ * Shown in the TUI instead of the generic tier name to give the user a clear
358
+ * mental model of what the worker is doing. */
359
+ role?: string | undefined;
360
+ /** Public orchestrator rationale that preceded this dispatch */
361
+ orchestratorContext?: string | undefined;
362
+ /** Prior tuple this dispatch is continuing from, when ARC resumes internally. */
363
+ continuationOf?: string | undefined;
364
+ /** Why ARC created this continuation dispatch. */
365
+ continuationReason?: "step_budget" | "user_steering" | undefined;
366
+ /** Compact user-facing checkpoint summary for continuation UI. */
367
+ continuationSummary?: string | undefined;
368
+ }
369
+ interface DispatchRecord {
370
+ tuple: Tuple;
371
+ artifact: Artifact;
372
+ /** Reference to transcript in TranscriptStore — NOT the full transcript body. */
373
+ transcriptId: string;
374
+ progress: WorkerProgressEvent[];
375
+ completedAt: number;
376
+ /** Worker execution result (artifacts, actions, status) */
377
+ workerResult?: WorkerResult | undefined;
378
+ }
379
+ interface OodaSnapshot {
380
+ observations: string[];
381
+ beliefs: string[];
382
+ disprovenApproaches: string[];
383
+ blockers: string[];
384
+ decisionPressure: {
385
+ turn: number;
386
+ maxTurns: number;
387
+ turnsRemaining: number;
388
+ dispatchCount: number;
389
+ allIncomplete: boolean;
390
+ };
391
+ }
392
+ type ReadEpisodeDetail = "summary" | "trace" | "artifacts";
393
+ interface ReadEpisodeArgs {
394
+ id: string;
395
+ detail?: ReadEpisodeDetail | undefined;
396
+ artifactKey?: string | undefined;
397
+ maxTokens?: number | undefined;
398
+ }
399
+ interface TraceToolCall {
400
+ toolName: string;
401
+ toolCallId?: string | undefined;
402
+ args: Record<string, unknown>;
403
+ }
404
+ type ArcTraceEvent = {
405
+ scope: "orchestrator";
406
+ phase: "context_assembled";
407
+ turn: number;
408
+ totalChars: number;
409
+ estimatedTokens: number;
410
+ sections: Record<string, {
411
+ chars: number;
412
+ estimatedTokens: number;
413
+ }>;
414
+ } | {
415
+ scope: "orchestrator";
416
+ phase: "model_input";
417
+ turn: number;
418
+ model: string;
419
+ system: string;
420
+ /** Full AgentMessage context before SDK conversion. */
421
+ messages: AgentMessage[];
422
+ /** Full SDK-facing messages after conversion. */
423
+ modelMessages: unknown[];
424
+ toolNames: string[];
425
+ } | {
426
+ scope: "orchestrator";
427
+ phase: "model_output";
428
+ turn: number;
429
+ text: string;
430
+ toolCalls: TraceToolCall[];
431
+ } | {
432
+ scope: "orchestrator";
433
+ phase: "public_rationale_missing";
434
+ turn: number;
435
+ toolCalls: TraceToolCall[];
436
+ } | {
437
+ scope: "orchestrator";
438
+ phase: "tool_call";
439
+ turn: number;
440
+ toolName: string;
441
+ args: Record<string, unknown>;
442
+ } | {
443
+ scope: "orchestrator";
444
+ phase: "tool_result";
445
+ turn: number;
446
+ toolName: string;
447
+ args: Record<string, unknown>;
448
+ result: unknown;
449
+ } | {
450
+ scope: "worker";
451
+ phase: "model_input";
452
+ tupleId: string;
453
+ step: number;
454
+ model: string;
455
+ system: string;
456
+ messages: AgentMessage[];
457
+ toolNames: string[];
458
+ } | {
459
+ scope: "worker";
460
+ phase: "model_output";
461
+ tupleId: string;
462
+ step: number;
463
+ action: unknown;
464
+ } | {
465
+ scope: "worker";
466
+ phase: "public_rationale_missing";
467
+ tupleId: string;
468
+ step: number;
469
+ toolNames: string[];
470
+ } | {
471
+ scope: "worker";
472
+ phase: "textual_tool_call_rescued";
473
+ tupleId: string;
474
+ step: number;
475
+ toolNames: string[];
476
+ } | {
477
+ scope: "worker";
478
+ phase: "tool_call";
479
+ tupleId: string;
480
+ step: number;
481
+ toolCallId: string;
482
+ toolName: string;
483
+ args: Record<string, unknown>;
484
+ } | {
485
+ scope: "worker";
486
+ phase: "tool_result";
487
+ tupleId: string;
488
+ step: number;
489
+ toolCallId: string;
490
+ toolName: string;
491
+ result: unknown;
492
+ resultText: string;
493
+ } | {
494
+ scope: "worker";
495
+ phase: "worker_result";
496
+ tupleId: string;
497
+ result: unknown;
498
+ };
499
+ interface TranscriptStore {
500
+ append(transcript: Transcript): Promise<void>;
501
+ getAll(): Promise<Transcript[]>;
502
+ get(id: string): Promise<Transcript | null>;
503
+ }
504
+ interface VectorIndex {
505
+ add(id: string, text: string): Promise<void>;
506
+ search(query: string, k: number): Promise<string[]>;
507
+ load(): Promise<void>;
508
+ save(): Promise<void>;
509
+ /** Number of documents currently indexed. Used to detect empty index on session resume. */
510
+ size(): Promise<number>;
511
+ }
512
+ interface ArtifactStore {
513
+ set(id: string, artifact: Artifact): Promise<void>;
514
+ get(id: string): Promise<Artifact | null>;
515
+ getAll(): Promise<Record<string, Artifact>>;
516
+ }
517
+ interface ScratchPad {
518
+ write(key: string, content: string): Promise<void>;
519
+ read(key: string): Promise<string | null>;
520
+ list(): Promise<string[]>;
521
+ clear(): Promise<void>;
522
+ }
523
+ /** Serialized session state — everything needed to hydrate an ArcLoop. */
524
+ interface SessionSnapshot {
525
+ messages: StoredMessage[];
526
+ dispatches: DispatchRecord[];
527
+ dagNodes: SummaryNode[];
528
+ dagCoveredBy: [string, string][];
529
+ turn: number;
530
+ dispatchCount: number;
531
+ orchestratorMessageIndex: number;
532
+ }
533
+ /** Lightweight session metadata for listing/picking. */
534
+ interface SessionMeta {
535
+ id: string;
536
+ slug: string;
537
+ createdAt: number;
538
+ lastActiveAt: number;
539
+ taskCount?: number;
540
+ summary: string;
541
+ }
542
+ interface SessionStore {
543
+ load(id: string): Promise<SessionSnapshot | null>;
544
+ save(id: string, snapshot: SessionSnapshot): Promise<void>;
545
+ getMeta(id: string): Promise<SessionMeta | null>;
546
+ saveMeta(id: string, meta: SessionMeta): Promise<void>;
547
+ list(): Promise<SessionMeta[]>;
548
+ }
549
+ /** What the orchestrator sees each turn */
550
+ interface OrchestratorContext {
551
+ task: string;
552
+ artifacts: Record<string, Artifact>;
553
+ lastResult: Artifact | null;
554
+ /** Rolling window of recent orchestrator messages */
555
+ recentTurns: AgentMessage[];
556
+ /** Current turn number */
557
+ turn: number;
558
+ /** Max turns allowed */
559
+ maxTurns: number;
560
+ /** Turns remaining after the current turn */
561
+ turnsRemaining: number;
562
+ /** Number of dispatches so far */
563
+ dispatchCount: number;
564
+ /** Artifact status counts across all completed dispatches */
565
+ artifactStatusCounts: Record<Artifact["status"], number>;
566
+ /** True when no dispatch artifact has reached complete status */
567
+ allIncomplete: boolean;
568
+ /** Completed dispatches in chronological order */
569
+ dispatches: DispatchRecord[];
570
+ /** Current observe/orient state rendered into the orchestrator prompt */
571
+ ooda: OodaSnapshot;
572
+ /** LCM message store (all conversations) */
573
+ messageStore?: MessageStore | undefined;
574
+ /** LCM summary DAG */
575
+ summaryDAG?: SummaryDAG | undefined;
576
+ }
577
+
578
+ interface ArcConfig {
579
+ task: string;
580
+ /**
581
+ * Image attachments to inject alongside the initial task when the orchestrator
582
+ * model is multimodal. Subsequent task attachments flow through pushTask instead.
583
+ */
584
+ initialAttachments?: StoredAttachment[] | undefined;
585
+ workDir: string;
586
+ /** Model ID for the orchestrator */
587
+ model: string;
588
+ /** Model ID for workers */
589
+ workerModel: string;
590
+ /** Optional per-tier worker model overrides. Falls back to workerModel when a tier is missing. */
591
+ workerModelMap?: Partial<Record<DispatchTier, string>> | undefined;
592
+ /** Optional per-tier worker step budgets. Falls back to ARC defaults when unset. */
593
+ workerStepBudgets?: Partial<Record<DispatchTier, number>> | undefined;
594
+ /** Optional cheap model for post-dispatch completion gating. Falls back to workerModelMap.fast, then workerModel. */
595
+ doneGateModel?: string | undefined;
596
+ createModel?: ModelFactory;
597
+ toolProvider: ToolProvider;
598
+ /** Agent-provided tool definitions (Bash, Read, Write, etc.) with schemas, execute, and artifact metadata. Harness adds ARC framework tools internally. */
599
+ tools?: Map<string, Tool> | undefined;
600
+ /** Max orchestrator turns before stopping (default: 12) */
601
+ maxTurns?: number;
602
+ /** Max steps per untiered worker (default: 30). Explicit tiers use workerStepBudgets/default tier budgets. */
603
+ maxStepsPerWorker?: number;
604
+ /** Rolling window size for orchestrator context (default: 10) */
605
+ orchestratorWindowSize?: number;
606
+ /** Directory where agent memory lives (default: workDir/.arc) */
607
+ memDir?: string;
608
+ /** Injected vector index (default: in-memory for tests) */
609
+ vectorIndex?: VectorIndex;
610
+ /** Injected scratch pad for inter-worker note sharing (default: in-memory for tests) */
611
+ scratchPad?: ScratchPad;
612
+ /** Injected transcript store (default: in-memory) */
613
+ transcriptStore?: TranscriptStore;
614
+ /** Injected artifact store (default: in-memory) */
615
+ artifactStore?: ArtifactStore;
616
+ /** Custom orchestrator system prompt (appended to default) */
617
+ orchestratorSystemPromptSuffix?: string | undefined;
618
+ /** Custom worker system prompt (appended to default) */
619
+ workerSystemPromptSuffix?: string | undefined;
620
+ /** Custom messages after the core task/budget block */
621
+ formatOrchestratorContext?: ((context: OrchestratorContext) => AgentMessage[]) | undefined;
622
+ /** Provider options passed to generateText (e.g. reasoningEffort for OpenAI). */
623
+ providerOptions?: Record<string, unknown> | undefined;
624
+ /** Optional hook runner for PreToolUse/PostToolUse/BeforeWorker/AfterWorker events */
625
+ hookRunner?: HookRunner | undefined;
626
+ /** Optional telemetry collector for profiling spans and metrics. */
627
+ telemetry?: HarnessTelemetry | undefined;
628
+ /** Callback for AskUser orchestrator tool. If provided, AskUser is available to the orchestrator. */
629
+ askUser?: ((question: string, options?: string[]) => Promise<string>) | undefined;
630
+ /** Session store for persistence across restarts. */
631
+ sessionStore?: SessionStore | undefined;
632
+ /** Session ID to resume. If provided with sessionStore, loop hydrates from saved state. */
633
+ sessionId?: string | undefined;
634
+ /** Job registry for long-running process orchestration. Default: MemoryJobRegistry. */
635
+ jobRegistry?: JobRegistry | undefined;
636
+ /** Per model-call timeout in milliseconds. Applied to both orchestrator and worker generateText. Default: 180000 (3 min). */
637
+ modelCallTimeoutMs?: number | undefined;
638
+ }
639
+ type ArcEvent = {
640
+ type: "orchestrator_turn";
641
+ turn: number;
642
+ contextTokens: number;
643
+ } | {
644
+ type: "trace";
645
+ trace: ArcTraceEvent;
646
+ } | {
647
+ type: "dispatch";
648
+ tupleId: string;
649
+ instruction: string;
650
+ } | {
651
+ type: "dispatch_full";
652
+ tuple: Tuple;
653
+ } | {
654
+ type: "worker_continuation";
655
+ tupleId: string;
656
+ fromTupleId: string;
657
+ reason: "step_budget" | "user_steering";
658
+ summary: string;
659
+ } | {
660
+ type: "worker_progress";
661
+ tupleId: string;
662
+ progress: WorkerProgressEvent;
663
+ } | {
664
+ type: "worker_complete";
665
+ tupleId: string;
666
+ status: Artifact["status"];
667
+ summary: string;
668
+ stepsUsed: number;
669
+ actions?: string[] | undefined;
670
+ } | {
671
+ type: "recall";
672
+ query: string;
673
+ answer: string;
674
+ } | {
675
+ type: "read_episode";
676
+ id: string;
677
+ detail: ReadEpisodeDetail;
678
+ output: string;
679
+ } | {
680
+ type: "ask_user";
681
+ question: string;
682
+ options?: string[] | undefined;
683
+ } | {
684
+ type: "interrupt_status";
685
+ summary: string;
686
+ } | {
687
+ type: "orchestrator_usage";
688
+ turn: number;
689
+ inputTokens?: number;
690
+ outputTokens?: number;
691
+ } | {
692
+ type: "done";
693
+ output: string;
694
+ } | {
695
+ type: "session_saved";
696
+ sessionId: string;
697
+ } | {
698
+ type: "text_delta";
699
+ text: string;
700
+ } | {
701
+ type: "reasoning_delta";
702
+ text: string;
703
+ } | {
704
+ type: "job_event";
705
+ event: JobEvent;
706
+ } | {
707
+ type: "interjection_queued";
708
+ position: number;
709
+ text: string;
710
+ } | {
711
+ type: "interjection_delivered";
712
+ position: number;
713
+ turn: number;
714
+ };
715
+ type WorkerProgressEvent = {
716
+ kind: "model_start";
717
+ step: number;
718
+ maxSteps: number;
719
+ } | {
720
+ kind: "model_complete";
721
+ step: number;
722
+ actionType: "final" | "tool" | "tool_batch";
723
+ durationMs: number;
724
+ toolNames?: string[] | undefined;
725
+ publicRationale?: string | undefined;
726
+ missingPublicRationale?: boolean | undefined;
727
+ outputSummary?: string | undefined;
728
+ inputTokens?: number | undefined;
729
+ outputTokens?: number | undefined;
730
+ } | {
731
+ kind: "model_error";
732
+ step: number;
733
+ durationMs: number;
734
+ error: string;
735
+ } | {
736
+ kind: "tool_start";
737
+ step: number;
738
+ toolCallId: string;
739
+ toolName: string;
740
+ argsSummary?: string | undefined;
741
+ } | {
742
+ kind: "tool_complete";
743
+ step: number;
744
+ toolCallId: string;
745
+ toolName: string;
746
+ success: boolean;
747
+ durationMs: number;
748
+ outputSummary: string;
749
+ output?: string | undefined;
750
+ artifact?: ToolResultArtifact | undefined;
751
+ exitCode?: unknown;
752
+ metadata?: Record<string, unknown> | undefined;
753
+ } | {
754
+ kind: "tool_error";
755
+ step: number;
756
+ toolCallId: string;
757
+ toolName: string;
758
+ durationMs: number;
759
+ error: string;
760
+ } | {
761
+ kind: "worker_result";
762
+ status: "complete" | "incomplete" | "failed" | "interrupted";
763
+ stepsUsed: number;
764
+ summary: string;
765
+ } | {
766
+ kind: "yield_start";
767
+ step: number;
768
+ toolCallId: string;
769
+ toolName: string;
770
+ threadId: string;
771
+ } | {
772
+ kind: "yield_resume";
773
+ step: number;
774
+ toolCallId: string;
775
+ toolName: string;
776
+ threadId: string;
777
+ };
778
+ interface RunWorkerConfig {
779
+ /** Original top-level task */
780
+ task?: string | undefined;
781
+ instruction: string;
782
+ /** Structured contract for this dispatch */
783
+ expectedOutput?: ExpectedOutputContract | undefined;
784
+ /** LCM-assembled context for this worker */
785
+ lcmContext?: AssembledContext | undefined;
786
+ /** Artifact ID -> file content */
787
+ inputArtifacts: Map<string, string>;
788
+ tools: Record<string, AnyTool>;
789
+ /** Tool registry with execute/artifact metadata for dispatch and episode projection */
790
+ toolRegistry: Map<string, Tool>;
791
+ maxSteps: number;
792
+ toolProvider: ToolProvider;
793
+ createModel: ModelFactory;
794
+ model: string;
795
+ workDir: string;
796
+ signal?: AbortSignal | undefined;
797
+ /** Extra text prefixed to worker system prompt */
798
+ systemPromptPrefix?: string | undefined;
799
+ /** Semantic role label for TUI display (e.g. "Debugger", "Researcher"). */
800
+ role?: string | undefined;
801
+ /** Extra text appended to worker system prompt */
802
+ systemPromptSuffix?: string | undefined;
803
+ /** Provider options passed to generateText (e.g. reasoning config). */
804
+ providerOptions?: Record<string, unknown> | undefined;
805
+ /** Public orchestrator rationale that preceded this dispatch */
806
+ orchestratorContext?: string | undefined;
807
+ /** Tuple id for full-fidelity trace events */
808
+ tupleId?: string | undefined;
809
+ /** Optional diagnostic hook for streaming worker internals to the caller */
810
+ onProgress?: ((event: WorkerProgressEvent) => void) | undefined;
811
+ /** Optional full-fidelity trace hook for raw model/tool IO */
812
+ onTrace?: ((event: ArcTraceEvent) => void) | undefined;
813
+ /** Optional hook runner for PreToolUse/PostToolUse events */
814
+ hookRunner?: HookRunner | undefined;
815
+ /** Optional telemetry collector for profiling spans and metrics. */
816
+ telemetry?: HarnessTelemetry | undefined;
817
+ /** Current sub-dispatch depth (0 = top-level worker). Used to enforce max depth. */
818
+ dispatchDepth?: number | undefined;
819
+ /** Existing messages to resume from (for continuations). When set, the worker
820
+ * appends `instruction` as a user message to these messages instead of building
821
+ * a fresh initial prompt. */
822
+ resumeMessages?: AgentMessage[] | undefined;
823
+ /** Steps already consumed before this resume (for accurate step counting). */
824
+ stepsAlreadyUsed?: number | undefined;
825
+ /** Per model-call timeout in milliseconds. Default: 180000 (3 min). */
826
+ modelCallTimeoutMs?: number | undefined;
827
+ }
828
+ interface WorkerResult {
829
+ transcript: AgentMessage[];
830
+ output: string | null;
831
+ status: "complete" | "incomplete" | "failed" | "interrupted";
832
+ stepsUsed: number;
833
+ /** Last message content for summary */
834
+ lastMessage: string;
835
+ /** All tool calls with results for orchestrator visibility */
836
+ actions: string[];
837
+ /** Artifacts touched during execution (from ToolResult.artifact) */
838
+ artifacts: ToolResultArtifact[];
839
+ }
840
+
841
+ interface ArcRunResult {
842
+ output: string;
843
+ events: ArcEvent[];
844
+ }
845
+ type PushResult = {
846
+ delivered: "as_task";
847
+ } | {
848
+ delivered: "as_interjection";
849
+ position: number;
850
+ } | {
851
+ delivered: "dropped";
852
+ reason: "in_ask_user";
853
+ };
854
+ interface PushTaskOptions {
855
+ /** Multimodal attachments to attach to the resulting user message. */
856
+ attachments?: StoredAttachment[];
857
+ }
858
+ declare class ArcLoop {
859
+ private config;
860
+ private readonly transcriptStore;
861
+ private readonly vectorIndex;
862
+ private readonly scratchPad;
863
+ private readonly artifactStore;
864
+ private readonly jobRegistry;
865
+ /** Non-output job events queued for orchestrator turn-boundary injection. */
866
+ private pendingJobEvents;
867
+ /** Events that need to flow out of the async generator stream (job events, interjection lifecycle). */
868
+ private pendingArcEvents;
869
+ private jobUnsubscribe;
870
+ private readonly telemetry;
871
+ private messageStore;
872
+ private summaryDAG;
873
+ private readonly createModel;
874
+ private readonly windowSize;
875
+ private readonly model;
876
+ private readonly doneGateModel;
877
+ /** Full orchestrator system prompt (base + optional suffix). */
878
+ private readonly orchestratorSystem;
879
+ /** Orchestrator tool schemas (for the model) */
880
+ private readonly orchestratorToolSchemas;
881
+ /** Orchestrator tool registry (for execute) — excludes dispatch/done (control flow) */
882
+ private readonly orchestratorToolRegistry;
883
+ /** ARC framework tools that are always available to workers. */
884
+ private readonly workerArcTools;
885
+ /** Dispatcher deps + mutable state — shared with dispatcher.ts functions */
886
+ private readonly dispatchDeps;
887
+ private readonly dispatchState;
888
+ private orchestratorMessageIndex;
889
+ private turn;
890
+ private maxTurns;
891
+ private readonly inFlightDispatches;
892
+ private readonly historySearchesThisTask;
893
+ private readonly historyReadsThisTask;
894
+ private readonly historyExpansionsThisTask;
895
+ private readonly historyExpansionSummaryCache;
896
+ private lastSessionCheckpointAt;
897
+ /** Per-turn abort controller — cancelled by interrupt(), refreshed each turn. */
898
+ private turnController;
899
+ /** Resolver for the next task — set when the loop is waiting between tasks. */
900
+ private taskResolve;
901
+ private pendingInterjections;
902
+ /** Image attachments for the currently active task. Injected into orchestrator prompts. */
903
+ private currentTaskAttachments;
904
+ /** Consecutive dispatch rounds where every dispatch ended in failed/incomplete. Forces done at threshold. */
905
+ private consecutiveFailedDispatchRounds;
906
+ private askUserPending;
907
+ private readonly modelCallTimeoutMs;
908
+ constructor(config: ArcConfig);
909
+ /**
910
+ * Replace agent-provided worker tools for future dispatches.
911
+ * Already-running workers keep the tool set they started with.
912
+ */
913
+ refreshWorkerTools(tools: Map<string, Tool>): void;
914
+ /** Drain events from asynchronous sources (job registry, interjections) into the generator stream. */
915
+ private drainPendingArcEvents;
916
+ private drainPendingJobEvents;
917
+ private drainPendingInterjections;
918
+ /** Release subscriptions and free resources held by this loop. */
919
+ dispose(): void;
920
+ /**
921
+ * Interrupt the current turn — cancels in-flight model calls and workers.
922
+ * The orchestrator loop stays alive and will prompt for user steering.
923
+ */
924
+ interrupt(): void;
925
+ private refreshTurnSignal;
926
+ /** True when the loop is waiting for the next task (between done boundaries). */
927
+ get idle(): boolean;
928
+ /** Serialize current loop state for UI-level checkpoints. */
929
+ getSessionSnapshot(): SessionSnapshot;
930
+ /** Restore loop state from a prior UI-level checkpoint. */
931
+ restoreSessionSnapshot(snapshot: SessionSnapshot | null): void;
932
+ /**
933
+ * Deliver a message to the orchestrator regardless of loop state.
934
+ * - Idle (waiting for next task): resolves waitForNextTask → becomes next task.
935
+ * - Running: queued as [user interjection], drained at next turn boundary.
936
+ * - Inside askUser: dropped; caller should resolve the askUser promise directly.
937
+ */
938
+ pushTask(msg: string, options?: PushTaskOptions): PushResult;
939
+ private wrappedAskUser;
940
+ private waitForNextTask;
941
+ /** Save session snapshot + update meta if a session store is configured. */
942
+ private saveSession;
943
+ private buildSessionSnapshot;
944
+ private checkpointSession;
945
+ private checkpointAfterDispatchEvent;
946
+ private clearCompletedInFlightDispatches;
947
+ /** Reset per-task state while keeping full conversation history. */
948
+ private resetForNewTask;
949
+ /**
950
+ * Stream events from the orchestration loop.
951
+ */
952
+ stream(signal?: AbortSignal): AsyncGenerator<ArcEvent>;
953
+ /**
954
+ * Run a single task to completion (for headless/test use).
955
+ * Breaks after the first `done` event — does not wait for follow-up tasks.
956
+ */
957
+ run(signal?: AbortSignal): Promise<ArcRunResult>;
958
+ private runDispatchCalls;
959
+ private continueStepBudgetDispatches;
960
+ private buildContinuationDispatchArgs;
961
+ private runDoneGate;
962
+ private completeCurrentTask;
963
+ /** Append a message to the LCM message store (single source of truth) */
964
+ private appendOrchestratorMessage;
965
+ private findEpisodeRecordBySummaryId;
966
+ private searchHistoryWithGuardrails;
967
+ private readHistoryWithGuardrails;
968
+ private expandHistoryWithGuardrails;
969
+ private summarizeHistoryExpansion;
970
+ private buildContext;
971
+ private buildOrchestratorMessages;
972
+ private buildTaskContextText;
973
+ private buildAttachmentMessage;
974
+ private readEpisode;
975
+ /**
976
+ * Handle a turn interrupt without routing every follow-up through the
977
+ * orchestrator. Status questions are answered from the saved worker record;
978
+ * steering/continue become an internal worker continuation.
979
+ */
980
+ private handleInterrupt;
981
+ private formatInterruptStatus;
982
+ }
983
+
984
+ /**
985
+ * Episode projection: minimal formatting for orchestrator context.
986
+ *
987
+ * The worker collects artifacts and actions during execution.
988
+ * This module just formats DispatchRecords for the orchestrator prompt.
989
+ */
990
+
991
+ /** Format a single dispatch record for the orchestrator prompt */
992
+ declare function formatDispatchForPrompt(record: DispatchRecord, options?: {
993
+ compact?: boolean;
994
+ maxChars?: number;
995
+ }): string;
996
+
997
+ declare function cloneForTrace<T>(value: T): T;
998
+
999
+ /** Default budget for dispatches that do not request a tier. */
1000
+ declare const DEFAULT_MAX_STEPS_PER_WORKER = 30;
1001
+ /** Per-tier initial budgets. Strong is intentionally larger for implementation loops. */
1002
+ declare const DEFAULT_WORKER_STEP_BUDGETS: Record<DispatchTier, number>;
1003
+ /** Hard ceiling on worker steps after RequestMoreSteps extensions. */
1004
+ declare const ABSOLUTE_MAX_WORKER_STEPS = 60;
1005
+ /** Recommended extension size when workers need to keep their current context. */
1006
+ declare const REQUEST_MORE_STEPS_INCREMENT = 15;
1007
+
1008
+ /** In-memory transcript store for testing */
1009
+ declare class MemoryTranscriptStore implements TranscriptStore {
1010
+ private transcripts;
1011
+ private byId;
1012
+ append(transcript: Transcript): Promise<void>;
1013
+ getAll(): Promise<Transcript[]>;
1014
+ get(id: string): Promise<Transcript | null>;
1015
+ }
1016
+ /** In-memory vector index for testing (no actual embeddings) */
1017
+ declare class MemoryVectorIndex implements VectorIndex {
1018
+ private entries;
1019
+ add(id: string, text: string): Promise<void>;
1020
+ search(query: string, k: number): Promise<string[]>;
1021
+ load(): Promise<void>;
1022
+ save(): Promise<void>;
1023
+ size(): Promise<number>;
1024
+ }
1025
+ /** In-memory scratch pad for testing */
1026
+ declare class MemoryScratchPad implements ScratchPad {
1027
+ private entries;
1028
+ write(key: string, content: string): Promise<void>;
1029
+ read(key: string): Promise<string | null>;
1030
+ list(): Promise<string[]>;
1031
+ clear(): Promise<void>;
1032
+ }
1033
+ /** In-memory artifact store for testing */
1034
+ declare class MemoryArtifactStore implements ArtifactStore {
1035
+ private artifacts;
1036
+ set(id: string, artifact: Artifact): Promise<void>;
1037
+ get(id: string): Promise<Artifact | null>;
1038
+ getAll(): Promise<Record<string, Artifact>>;
1039
+ }
1040
+ /** In-memory session store for testing */
1041
+ declare class MemorySessionStore implements SessionStore {
1042
+ private snapshots;
1043
+ private metas;
1044
+ load(id: string): Promise<SessionSnapshot | null>;
1045
+ save(id: string, snapshot: SessionSnapshot): Promise<void>;
1046
+ getMeta(id: string): Promise<SessionMeta | null>;
1047
+ saveMeta(id: string, meta: SessionMeta): Promise<void>;
1048
+ list(): Promise<SessionMeta[]>;
1049
+ }
1050
+
1051
+ /**
1052
+ * File-based transcript store.
1053
+ * Stores transcripts as individual JSON files in a directory.
1054
+ */
1055
+ declare class FsTranscriptStore implements TranscriptStore {
1056
+ private readonly dir;
1057
+ private readonly indexPath;
1058
+ private index;
1059
+ private loaded;
1060
+ constructor(dir: string);
1061
+ append(transcript: Transcript): Promise<void>;
1062
+ getAll(): Promise<Transcript[]>;
1063
+ get(id: string): Promise<Transcript | null>;
1064
+ private ensureLoaded;
1065
+ }
1066
+ /**
1067
+ * File-based artifact store.
1068
+ * Stores artifacts in a single JSON file.
1069
+ */
1070
+ declare class FsArtifactStore implements ArtifactStore {
1071
+ private readonly filePath;
1072
+ private artifacts;
1073
+ private loaded;
1074
+ constructor(filePath: string);
1075
+ set(id: string, artifact: Artifact): Promise<void>;
1076
+ get(id: string): Promise<Artifact | null>;
1077
+ getAll(): Promise<Record<string, Artifact>>;
1078
+ private ensureLoaded;
1079
+ private save;
1080
+ }
1081
+
1082
+ /**
1083
+ * In-memory reference implementation of JobRegistry.
1084
+ *
1085
+ * Jobs here never actually spawn processes — callers use `simulateExit` /
1086
+ * `simulateOutput` / `simulateFailure` to drive state. Intended for tests
1087
+ * and agents that don't need filesystem-backed persistence.
1088
+ */
1089
+ declare class MemoryJobRegistry implements JobRegistry {
1090
+ private jobs;
1091
+ private handlers;
1092
+ private seq;
1093
+ start(opts: JobStartOptions, startedBy?: JobSpec["startedBy"]): Promise<JobStatus>;
1094
+ check(id: string): Promise<JobStatus | null>;
1095
+ cancel(id: string, _signal?: "TERM" | "KILL"): Promise<JobStatus | null>;
1096
+ list(): Promise<JobStatus[]>;
1097
+ tail(id: string, lines?: number): Promise<string[]>;
1098
+ waitFor(id: string, signal?: AbortSignal): Promise<JobStatus>;
1099
+ subscribe(handler: (e: JobEvent) => void): () => void;
1100
+ snapshot(): JobStatus[];
1101
+ prune(_olderThanMs?: number): Promise<number>;
1102
+ simulateOutput(id: string, chunk: string): void;
1103
+ simulateExit(id: string, exitCode: number): void;
1104
+ private emit;
1105
+ }
1106
+
1107
+ export { ABSOLUTE_MAX_WORKER_STEPS, AnyTool, type ArcConfig, type ArcEvent, ArcLoop, type ArcRunResult, type ArcTraceEvent, type Artifact, type ArtifactStore, DEFAULT_MAX_STEPS_PER_WORKER, DEFAULT_WORKER_STEP_BUDGETS, type DispatchRecord, type DispatchTier, type ExpectedArtifact, type ExpectedOutputContract, FsArtifactStore, FsTranscriptStore, type JobEvent, type JobKind, type JobRegistry, type JobSpec, type JobStartOptions, type JobState, type JobStatus, type JobTransport, MemoryArtifactStore, MemoryJobRegistry, MemoryMessageStore, MemoryScratchPad, MemorySessionStore, MemorySummaryDAG, MemoryTranscriptStore, MemoryVectorIndex, type MessageStore, ModelFactory, type OodaSnapshot, type OrchestratorContext, type PushResult, REQUEST_MORE_STEPS_INCREMENT, type ReadEpisodeArgs, type ReadEpisodeDetail, type RunWorkerConfig, type ScratchPad, type SessionMeta, type SessionSnapshot, type SessionStore, type StoredAttachment, type StoredMessage, type SummaryDAG, type SummaryNode, type Tool, type ToolExecutionMode, ToolProvider, ToolResult, ToolResultArtifact, type TraceToolCall, type Transcript, type TranscriptStore, type Tuple, type VectorIndex, type WorkerProgressEvent, type WorkerResult, cloneForTrace, formatDispatchForPrompt };