loopforge 1.0.0 → 1.1.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.
@@ -0,0 +1,84 @@
1
+ /** LoopForge — Autonomous loop driver (v1.1).
2
+ *
3
+ * Closes the feedback loop: compile → agent executes → extract self-eval →
4
+ * auto-feedback → compile next → ... until task complete or circuit breaker.
5
+ *
6
+ * Zero API dependencies — LoopForge does NOT call AI APIs. The caller
7
+ * provides an execute callback or feeds agent output round by round.
8
+ */
9
+ import { type LoopHealth, type SelfEvaluation } from "./protocol.js";
10
+ import { LoopForgeEngine } from "./engine.js";
11
+ export interface AutonomousConfig {
12
+ /** The task description — becomes the loop objective. */
13
+ task: string;
14
+ /** Kebab-case loop identifier. */
15
+ loopId: string;
16
+ /** Optional explicit goal ID. Derived from task if omitted. */
17
+ goalId?: string;
18
+ /** Maximum rounds before forced stop. Default 20. */
19
+ maxRounds?: number;
20
+ /** Health check interval (rounds). Default 3. */
21
+ healthCheckInterval?: number;
22
+ /** Optional path to a plan/spec file for constraint extraction. */
23
+ planSource?: string;
24
+ /** Constraints extracted from the plan (provided by caller). */
25
+ constraintsFromPlan?: string[];
26
+ /** Domain hint for technique routing. */
27
+ domain?: string;
28
+ }
29
+ export interface RoundOutput {
30
+ round: number;
31
+ /** The compiled prompt — ready for agent execution. */
32
+ prompt: string;
33
+ /** L0 | L1 | L2 */
34
+ recompileLevel: string;
35
+ /** Selected prompting technique. */
36
+ techniqueUsed: string;
37
+ /** Cross-round health snapshot (null on round 1 if no prior data). */
38
+ health: LoopHealth | null;
39
+ /** Quality score from the PREVIOUS round (null on round 1). */
40
+ lastQualityScore: number | null;
41
+ }
42
+ export type StopReason = "task_complete" | "circuit_breaker" | "max_rounds" | "stalled" | "extraction_failed";
43
+ export interface AutonomousResult {
44
+ /** Total rounds completed. */
45
+ roundsCompleted: number;
46
+ /** Why the loop stopped. */
47
+ stopReason: StopReason;
48
+ /** Health snapshot at stop. */
49
+ healthAtStop: LoopHealth | null;
50
+ /** Quality trajectory [round1_score, round2_score, ...]. */
51
+ qualityTrajectory: number[];
52
+ /** Whether the loop achieved its objective. */
53
+ success: boolean;
54
+ }
55
+ export interface RunOneRoundResult {
56
+ /** If stopNow is true, the loop should terminate. */
57
+ stopNow: boolean;
58
+ stopReason: StopReason | null;
59
+ /** The compiled prompt (null if stopping). */
60
+ roundOutput: RoundOutput | null;
61
+ /** Extracted self-evaluation (null on round 1 or if extraction failed). */
62
+ selfEval: SelfEvaluation | null;
63
+ /** Whether structured extraction succeeded. */
64
+ extractionSucceeded: boolean;
65
+ }
66
+ /** Run one round of the autonomous loop.
67
+ *
68
+ * Round 1 (agentOutput = null): compile the first prompt (L2 full build).
69
+ * Round N (agentOutput = string): extract self-eval, record auto-feedback,
70
+ * compile next prompt (L0/L1/L2 decided by the 4-gate router).
71
+ *
72
+ * Returns stopNow = true when the loop should terminate. */
73
+ export declare function runOneRound(engine: LoopForgeEngine, config: AutonomousConfig, currentRound: number, agentOutput: string | null): RunOneRoundResult;
74
+ /** Execute callback: takes a compiled prompt, returns the agent's output. */
75
+ export type AgentExecutor = (prompt: string, round: number) => Promise<string>;
76
+ /** Run a fully autonomous loop from start to finish.
77
+ *
78
+ * The `execute` callback is called with each compiled prompt.
79
+ * LoopForge does NOT call any AI API — the caller provides execution.
80
+ *
81
+ * Stops when: task complete, circuit breaker triggered, max rounds
82
+ * reached, or self-eval extraction fails. */
83
+ export declare function runAutonomousLoop(engine: LoopForgeEngine, config: AutonomousConfig, execute: AgentExecutor): Promise<AutonomousResult>;
84
+ //# sourceMappingURL=autonomous.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autonomous.d.ts","sourceRoot":"","sources":["../src/autonomous.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EAIhB,MAAM,aAAa,CAAC;AAMrB,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,iBAAiB,GACjB,YAAY,GACZ,SAAS,GACT,mBAAmB,CAAC;AAExB,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,4BAA4B;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,+BAA+B;IAC/B,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,4DAA4D;IAC5D,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,8CAA8C;IAC9C,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,+CAA+C;IAC/C,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;6DAM6D;AAC7D,wBAAgB,WAAW,CACzB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,gBAAgB,EACxB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,iBAAiB,CAwLnB;AAMD,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE/E;;;;;;8CAM8C;AAC9C,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAiE3B"}
@@ -0,0 +1,250 @@
1
+ /** LoopForge — Autonomous loop driver (v1.1).
2
+ *
3
+ * Closes the feedback loop: compile → agent executes → extract self-eval →
4
+ * auto-feedback → compile next → ... until task complete or circuit breaker.
5
+ *
6
+ * Zero API dependencies — LoopForge does NOT call AI APIs. The caller
7
+ * provides an execute callback or feeds agent output round by round.
8
+ */
9
+ import { makeLoopCompileRequest, makeLoopRoundResult, makeVaultConfig, } from "./protocol.js";
10
+ import { extractSelfEvaluation, heuristicSelfEvaluation, } from "./engine.js";
11
+ /** Run one round of the autonomous loop.
12
+ *
13
+ * Round 1 (agentOutput = null): compile the first prompt (L2 full build).
14
+ * Round N (agentOutput = string): extract self-eval, record auto-feedback,
15
+ * compile next prompt (L0/L1/L2 decided by the 4-gate router).
16
+ *
17
+ * Returns stopNow = true when the loop should terminate. */
18
+ export function runOneRound(engine, config, currentRound, agentOutput) {
19
+ const maxRounds = config.maxRounds ?? 20;
20
+ const healthInterval = config.healthCheckInterval ?? 3;
21
+ // ── Check max rounds before doing anything ──────────────────────────
22
+ if (currentRound > maxRounds) {
23
+ return {
24
+ stopNow: true,
25
+ stopReason: "max_rounds",
26
+ roundOutput: null,
27
+ selfEval: null,
28
+ extractionSucceeded: false,
29
+ };
30
+ }
31
+ // ── Round N (N > 1): Extract self-eval and record feedback ──────────
32
+ let selfEval = null;
33
+ let extractionSucceeded = false;
34
+ if (agentOutput !== null && currentRound > 1) {
35
+ // Try structured extraction first
36
+ selfEval = extractSelfEvaluation(agentOutput);
37
+ extractionSucceeded = selfEval !== null;
38
+ // Fallback to heuristic if structured extraction failed
39
+ const usedHeuristic = selfEval === null;
40
+ if (selfEval === null) {
41
+ selfEval = heuristicSelfEvaluation(agentOutput);
42
+ }
43
+ // Record auto-feedback (even heuristic — best effort for vault audit trail)
44
+ if (selfEval !== null) {
45
+ engine.autoFeedback(selfEval, config.loopId, currentRound - 1, // feedback is for the PREVIOUS round
46
+ config.task);
47
+ }
48
+ // Stop if structured extraction failed — heuristic is too low-confidence
49
+ // to continue the loop autonomously
50
+ if (usedHeuristic) {
51
+ return {
52
+ stopNow: true,
53
+ stopReason: "extraction_failed",
54
+ roundOutput: null,
55
+ selfEval,
56
+ extractionSucceeded: false,
57
+ };
58
+ }
59
+ // Check stop conditions from agent's self-eval (structured only)
60
+ if (selfEval !== null && !selfEval.should_continue) {
61
+ return {
62
+ stopNow: true,
63
+ stopReason: "task_complete",
64
+ roundOutput: null,
65
+ selfEval,
66
+ extractionSucceeded,
67
+ };
68
+ }
69
+ // Check circuit breaker after recording feedback
70
+ if (engine.shouldBreak()) {
71
+ return {
72
+ stopNow: true,
73
+ stopReason: "circuit_breaker",
74
+ roundOutput: null,
75
+ selfEval,
76
+ extractionSucceeded,
77
+ };
78
+ }
79
+ // Check if extraction failed entirely
80
+ if (selfEval === null) {
81
+ return {
82
+ stopNow: true,
83
+ stopReason: "extraction_failed",
84
+ roundOutput: null,
85
+ selfEval: null,
86
+ extractionSucceeded: false,
87
+ };
88
+ }
89
+ }
90
+ // ── Compile the next prompt ────────────────────────────────────────
91
+ const lcr = makeLoopCompileRequest({
92
+ loop_id: config.loopId,
93
+ round: currentRound,
94
+ goal_id: config.goalId ?? "",
95
+ task: config.task,
96
+ domain: config.domain ?? "",
97
+ plan_source: config.planSource ?? null,
98
+ constraints_from_plan: config.constraintsFromPlan ?? [],
99
+ health_check_interval: healthInterval,
100
+ vault_config: makeVaultConfig(),
101
+ });
102
+ // Attach last round result if we have self-eval data
103
+ if (selfEval !== null && currentRound > 1) {
104
+ lcr.last_round_result = makeLoopRoundResult({
105
+ round: currentRound - 1,
106
+ success: selfEval.success,
107
+ output_summary: selfEval.output_summary,
108
+ constraint_violations: selfEval.constraint_violations,
109
+ manual_fixes_needed: "",
110
+ quality_score: 0, // Will be backfilled from vault
111
+ });
112
+ }
113
+ const result = engine.invokeLoopCompile({
114
+ task: config.task,
115
+ mode: "loop_compile",
116
+ vault_config: makeVaultConfig(),
117
+ feedback: null,
118
+ skill_name: null,
119
+ task_id: null,
120
+ loop_id: config.loopId,
121
+ round: currentRound,
122
+ goal_id: config.goalId ?? "",
123
+ domain: config.domain ?? "",
124
+ plan_source: config.planSource ?? null,
125
+ constraints_from_plan: config.constraintsFromPlan ?? [],
126
+ health_check_interval: healthInterval,
127
+ last_round_result: lcr.last_round_result ?? undefined,
128
+ });
129
+ if (result.status === "error" || !result.response?.prompt) {
130
+ return {
131
+ stopNow: true,
132
+ stopReason: "stalled",
133
+ roundOutput: null,
134
+ selfEval,
135
+ extractionSucceeded,
136
+ };
137
+ }
138
+ // Extract health from the response (it's embedded in the prompt text as markdown)
139
+ // The health data is in the LoopCompileResponse, but we need to get it from the engine
140
+ const context = engine.hydrateLoopContext(config.loopId);
141
+ let health = null;
142
+ if (context) {
143
+ const results = context.results ?? [];
144
+ const latest = results[results.length - 1];
145
+ if (latest) {
146
+ const lineage = (latest.loop_lineage ?? {});
147
+ // Health is computed per-round, not stored directly in lineage
148
+ // We'll report null for simplicity — the prompt text contains health info
149
+ }
150
+ }
151
+ // Determine last quality score
152
+ let lastQuality = null;
153
+ if (selfEval !== null) {
154
+ const fb = selfEval;
155
+ // Recompute using the same formula as scoreQuality
156
+ if (fb.success && fb.constraint_violations.length === 0)
157
+ lastQuality = 5;
158
+ else if (fb.success && fb.constraint_violations.length === 0)
159
+ lastQuality = 4;
160
+ else if (fb.success)
161
+ lastQuality = 3;
162
+ else if (fb.constraint_violations.length > 0)
163
+ lastQuality = 2;
164
+ else
165
+ lastQuality = 1;
166
+ }
167
+ return {
168
+ stopNow: false,
169
+ stopReason: null,
170
+ roundOutput: {
171
+ round: currentRound,
172
+ prompt: result.response.prompt,
173
+ recompileLevel: result.response.analysis?.rationale?.includes("l0")
174
+ ? "l0"
175
+ : result.response.analysis?.rationale?.includes("l1")
176
+ ? "l1"
177
+ : "l2",
178
+ techniqueUsed: result.response.analysis?.technique ?? "unknown",
179
+ health,
180
+ lastQualityScore: lastQuality,
181
+ },
182
+ selfEval,
183
+ extractionSucceeded,
184
+ };
185
+ }
186
+ /** Run a fully autonomous loop from start to finish.
187
+ *
188
+ * The `execute` callback is called with each compiled prompt.
189
+ * LoopForge does NOT call any AI API — the caller provides execution.
190
+ *
191
+ * Stops when: task complete, circuit breaker triggered, max rounds
192
+ * reached, or self-eval extraction fails. */
193
+ export async function runAutonomousLoop(engine, config, execute) {
194
+ const maxRounds = config.maxRounds ?? 20;
195
+ const qualityTrajectory = [];
196
+ let agentOutput = null;
197
+ let finalStopReason = "max_rounds";
198
+ for (let round = 1; round <= maxRounds; round++) {
199
+ const roundResult = runOneRound(engine, config, round, agentOutput);
200
+ if (roundResult.stopNow) {
201
+ finalStopReason = roundResult.stopReason ?? "stalled";
202
+ break;
203
+ }
204
+ if (!roundResult.roundOutput) {
205
+ finalStopReason = "stalled";
206
+ break;
207
+ }
208
+ // Track quality
209
+ if (roundResult.roundOutput.lastQualityScore !== null) {
210
+ qualityTrajectory.push(roundResult.roundOutput.lastQualityScore);
211
+ }
212
+ // Execute the prompt
213
+ try {
214
+ agentOutput = await execute(roundResult.roundOutput.prompt, round);
215
+ }
216
+ catch {
217
+ finalStopReason = "stalled";
218
+ break;
219
+ }
220
+ // If this was the last round and we didn't stop earlier
221
+ if (round === maxRounds) {
222
+ finalStopReason = "max_rounds";
223
+ }
224
+ }
225
+ // Get final health snapshot
226
+ let healthAtStop = null;
227
+ try {
228
+ const context = engine.hydrateLoopContext(config.loopId);
229
+ if (context) {
230
+ const results = context.results ?? [];
231
+ if (results.length > 0) {
232
+ const latest = results[results.length - 1];
233
+ const lineage = (latest.loop_lineage ?? {});
234
+ // Health is in the lineage if it was stored
235
+ healthAtStop = lineage.loop_health ?? null;
236
+ }
237
+ }
238
+ }
239
+ catch {
240
+ // Best effort
241
+ }
242
+ return {
243
+ roundsCompleted: qualityTrajectory.length,
244
+ stopReason: finalStopReason,
245
+ healthAtStop,
246
+ qualityTrajectory,
247
+ success: finalStopReason === "task_complete",
248
+ };
249
+ }
250
+ //# sourceMappingURL=autonomous.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autonomous.js","sourceRoot":"","sources":["../src/autonomous.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /** LoopForge — Anthropic API backend (v1.1).
2
+ *
3
+ * Calls Claude API via Node.js built-in fetch. Zero additional dependencies.
4
+ * Uses ANTHROPIC_API_KEY from environment. Falls back gracefully on failure.
5
+ */
6
+ export interface AiConfig {
7
+ /** Anthropic API key. Default: process.env.ANTHROPIC_API_KEY */
8
+ apiKey?: string;
9
+ /** Model ID. Default: claude-sonnet-4-6 */
10
+ model?: string;
11
+ /** Max output tokens. Default: 8192 */
12
+ maxTokens?: number;
13
+ /** Base URL override (for proxies / alternative endpoints). */
14
+ baseUrl?: string;
15
+ /** Timeout in ms. Default: 300_000 (5 min). */
16
+ timeoutMs?: number;
17
+ }
18
+ export interface AiResult {
19
+ /** The model's text response, or null on failure. */
20
+ text: string | null;
21
+ /** True if the API call succeeded. */
22
+ ok: boolean;
23
+ /** Error message if !ok. */
24
+ error: string | null;
25
+ /** Model used. */
26
+ model: string;
27
+ }
28
+ /** Call Claude with a single user message. Returns the text response. */
29
+ export declare function callClaude(prompt: string, config?: AiConfig): Promise<AiResult>;
30
+ import type { AgentExecutor } from "../autonomous.js";
31
+ /** Create an AgentExecutor backed by Claude API.
32
+ * Usage:
33
+ * const executor = createClaudeExecutor({ apiKey: "sk-ant-..." });
34
+ * const result = await runAutonomousLoop(engine, config, executor);
35
+ */
36
+ export declare function createClaudeExecutor(aiConfig?: AiConfig): AgentExecutor;
37
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/backends/ai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,QAAQ;IACvB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,sCAAsC;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,4BAA4B;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,yEAAyE;AACzE,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,QAAa,GACpB,OAAO,CAAC,QAAQ,CAAC,CA+EnB;AAMD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,QAAa,GAAG,aAAa,CAQ3E"}
@@ -0,0 +1,98 @@
1
+ /** LoopForge — Anthropic API backend (v1.1).
2
+ *
3
+ * Calls Claude API via Node.js built-in fetch. Zero additional dependencies.
4
+ * Uses ANTHROPIC_API_KEY from environment. Falls back gracefully on failure.
5
+ */
6
+ // ═══════════════════════════════════════════════════════════════════════════
7
+ // API call
8
+ // ═══════════════════════════════════════════════════════════════════════════
9
+ const DEFAULT_BASE_URL = "https://api.anthropic.com/v1";
10
+ /** Call Claude with a single user message. Returns the text response. */
11
+ export async function callClaude(prompt, config = {}) {
12
+ const apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
13
+ const model = config.model ?? process.env.LOOPFORGE_MODEL ?? "claude-sonnet-4-6";
14
+ const maxTokens = config.maxTokens ?? 8192;
15
+ const baseUrl = config.baseUrl ?? process.env.ANTHROPIC_BASE_URL ?? DEFAULT_BASE_URL;
16
+ const timeoutMs = config.timeoutMs ?? 300_000;
17
+ if (!apiKey) {
18
+ return {
19
+ text: null,
20
+ ok: false,
21
+ error: "ANTHROPIC_API_KEY not set. Export it or pass apiKey in config.",
22
+ model,
23
+ };
24
+ }
25
+ const controller = new AbortController();
26
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
27
+ try {
28
+ const resp = await fetch(`${baseUrl}/messages`, {
29
+ method: "POST",
30
+ headers: {
31
+ "x-api-key": apiKey,
32
+ "anthropic-version": "2023-06-01",
33
+ "content-type": "application/json",
34
+ },
35
+ body: JSON.stringify({
36
+ model,
37
+ max_tokens: maxTokens,
38
+ messages: [{ role: "user", content: prompt }],
39
+ }),
40
+ signal: controller.signal,
41
+ });
42
+ clearTimeout(timer);
43
+ if (!resp.ok) {
44
+ const body = await resp.text().catch(() => "");
45
+ return {
46
+ text: null,
47
+ ok: false,
48
+ error: `API returned ${resp.status}: ${body.slice(0, 300)}`,
49
+ model,
50
+ };
51
+ }
52
+ const data = (await resp.json());
53
+ const content = data.content;
54
+ if (!Array.isArray(content) || content.length === 0) {
55
+ return {
56
+ text: null, ok: false,
57
+ error: `Unexpected response shape: ${JSON.stringify(data).slice(0, 200)}`,
58
+ model,
59
+ };
60
+ }
61
+ const first = content[0];
62
+ const text = String(first.text ?? "");
63
+ if (!text) {
64
+ return {
65
+ text: null, ok: false,
66
+ error: "Empty response text from model.",
67
+ model,
68
+ };
69
+ }
70
+ return { text, ok: true, error: null, model };
71
+ }
72
+ catch (err) {
73
+ clearTimeout(timer);
74
+ if (err instanceof DOMException && err.name === "AbortError") {
75
+ return { text: null, ok: false, error: `Request timed out after ${timeoutMs}ms`, model };
76
+ }
77
+ return {
78
+ text: null, ok: false,
79
+ error: `Fetch error: ${err instanceof Error ? err.message : String(err)}`,
80
+ model,
81
+ };
82
+ }
83
+ }
84
+ /** Create an AgentExecutor backed by Claude API.
85
+ * Usage:
86
+ * const executor = createClaudeExecutor({ apiKey: "sk-ant-..." });
87
+ * const result = await runAutonomousLoop(engine, config, executor);
88
+ */
89
+ export function createClaudeExecutor(aiConfig = {}) {
90
+ return async (prompt, _round) => {
91
+ const result = await callClaude(prompt, aiConfig);
92
+ if (!result.ok || result.text === null) {
93
+ throw new Error(`Claude API error (round ${_round}): ${result.error}`);
94
+ }
95
+ return result.text;
96
+ };
97
+ }
98
+ //# sourceMappingURL=ai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/backends/ai.ts"],"names":[],"mappings":"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"}