@aiden-ade/sandbox-agent 0.1.6 → 0.1.7

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,769 +1,2 @@
1
- import { spawn } from "node:child_process";
2
- import { createInterface } from "node:readline";
3
- function formatCliSpawnError(command, error) {
4
- if (error.code === "ENOENT") {
5
- return new Error(`CLI command not found: ${command}. Install it or configure this provider with the full executable path.`);
6
- }
7
- return error;
8
- }
9
- function buildPromptWithSystem(config, promptText) {
10
- const parts = [
11
- config.systemPrompt?.trim(),
12
- config.systemPromptAppend?.trim(),
13
- promptText.trim(),
14
- ].filter((value) => Boolean(value && value.length > 0));
15
- return parts.join("\n\n");
16
- }
17
- function buildPlanModePrefix(promptText) {
18
- return [
19
- "You are in plan-only mode.",
20
- "Do not make code changes or execute write operations.",
21
- "Focus on analysis, planning, and explaining the next steps.",
22
- "",
23
- promptText,
24
- ].join("\n");
25
- }
26
- function spawnCli(command, args, context) {
27
- const spawnWithShell = process.platform === "win32";
28
- return spawn(command, args, {
29
- cwd: context.cwd,
30
- env: context.env,
31
- stdio: ["pipe", "pipe", "pipe"],
32
- shell: spawnWithShell,
33
- signal: context.abortController.signal,
34
- });
35
- }
36
- function createGenericCliBackend(options) {
37
- return {
38
- kind: options.kind,
39
- supportTier: options.supportTier,
40
- async run(context) {
41
- const presenter = context.presenter;
42
- const state = {
43
- process: null,
44
- iterations: 0,
45
- summary: "",
46
- };
47
- const prompt = options.augmentPrompt?.(context) ??
48
- (context.config.mode === "plan"
49
- ? buildPlanModePrefix(buildPromptWithSystem(context.config, context.promptText))
50
- : buildPromptWithSystem(context.config, context.promptText));
51
- const args = options.buildArgs?.(context, prompt) ??
52
- options.args.map((arg) => (arg === "{{prompt}}" ? prompt : arg));
53
- const child = spawnCli(options.command, args, context);
54
- state.process = child;
55
- const safeArgs = args.map((a, i) =>
56
- // Redact API keys but show everything else for debugging
57
- (i > 0 && args[i - 1] === "--system-prompt") ? `"<system-prompt ${a.length} chars>"` : a);
58
- console.info(`[${options.kind}] Spawning: ${options.command} ${safeArgs.join(" ")}`);
59
- presenter.recordRawTranscript?.("system", `${options.command} ${args.join(" ")}`, {
60
- backendKind: options.kind,
61
- });
62
- if (options.promptViaStdin) {
63
- child.stdin.write(prompt);
64
- child.stdin.end();
65
- }
66
- else {
67
- child.stdin.end();
68
- }
69
- const stdoutRl = createInterface({ input: child.stdout });
70
- const stderrRl = createInterface({ input: child.stderr });
71
- const stderrLines = [];
72
- stdoutRl.on("line", (line) => {
73
- presenter.recordRawTranscript?.("stdout", line);
74
- if (options.parseStructuredLine) {
75
- options.parseStructuredLine(line, context, state);
76
- return;
77
- }
78
- if (line.trim().length > 0) {
79
- state.summary += `${line}\n`;
80
- void presenter.onAssistantText(`${line}\n`);
81
- }
82
- });
83
- stderrRl.on("line", (line) => {
84
- presenter.recordRawTranscript?.("stderr", line);
85
- if (line.trim().length > 0) {
86
- stderrLines.push(line);
87
- void presenter.onLog(`[${options.kind}] ${line}`);
88
- }
89
- });
90
- const exitCode = await new Promise((resolve, reject) => {
91
- child.on("error", (error) => {
92
- reject(formatCliSpawnError(options.command, error));
93
- });
94
- child.on("exit", (code) => resolve(code ?? 0));
95
- });
96
- if (exitCode !== 0) {
97
- console.error(`[${options.kind}] Process exited with code ${exitCode}`, {
98
- stderrLines: stderrLines.slice(-10),
99
- summaryPreview: state.summary.slice(0, 200),
100
- error: state.error,
101
- runtimeSessionId: state.runtimeSessionId,
102
- });
103
- }
104
- const hasRenderableTurn = state.summary.trim().length > 0 ||
105
- state.iterations > 0;
106
- if (hasRenderableTurn) {
107
- await presenter.onTurnComplete([]);
108
- }
109
- const summary = state.summary.trim() ||
110
- state.error?.trim() ||
111
- (exitCode === 0 ? "Task completed" : "Task failed");
112
- return {
113
- success: exitCode === 0,
114
- summary,
115
- filesModified: [],
116
- planFilesCreated: [],
117
- iterations: Math.max(state.iterations, 1),
118
- error: exitCode === 0
119
- ? undefined
120
- : state.error?.trim() ||
121
- (stderrLines.length > 0 ? stderrLines.join("\n").trim() : undefined) ||
122
- `${options.command} exited with code ${exitCode}`,
123
- providerSessionId: state.runtimeSessionId,
124
- runtimeSessionId: state.runtimeSessionId,
125
- backendKind: options.kind,
126
- supportTier: options.supportTier,
127
- usage: state.usage,
128
- };
129
- },
130
- };
131
- }
132
- function extractToolResultContent(content) {
133
- if (typeof content === "string") {
134
- return content;
135
- }
136
- if (!Array.isArray(content)) {
137
- return "";
138
- }
139
- return content
140
- .map((block) => {
141
- if (typeof block === "object" &&
142
- block !== null &&
143
- "type" in block &&
144
- block.type === "text" &&
145
- "text" in block &&
146
- typeof block.text === "string") {
147
- return block.text;
148
- }
149
- return "";
150
- })
151
- .filter(Boolean)
152
- .join("\n");
153
- }
154
- function parseClaudeStructuredLine(line, context, state) {
155
- const presenter = context.presenter;
156
- let parsed = null;
157
- try {
158
- parsed = JSON.parse(line);
159
- }
160
- catch {
161
- state.summary += `${line}\n`;
162
- void presenter.onAssistantText(`${line}\n`);
163
- return;
164
- }
165
- const type = typeof parsed.type === "string" ? parsed.type : "";
166
- if (!type)
167
- return;
168
- if (typeof parsed.session_id === "string") {
169
- state.runtimeSessionId = parsed.session_id;
170
- }
171
- switch (type) {
172
- case "system": {
173
- if (parsed.subtype === "init") {
174
- const model = typeof parsed.model === "string" ? parsed.model : "claude";
175
- void presenter.onLog(`[claude_cli] Session initialized with ${model}`);
176
- }
177
- break;
178
- }
179
- case "assistant": {
180
- state.iterations += 1;
181
- const message = typeof parsed.message === "object" && parsed.message !== null
182
- ? parsed.message
183
- : null;
184
- const content = Array.isArray(message?.content) ? message.content : [];
185
- for (const block of content) {
186
- if (typeof block !== "object" || block === null || !("type" in block)) {
187
- continue;
188
- }
189
- if (block.type === "text" && typeof block.text === "string") {
190
- const text = block.text;
191
- state.summary += `${text}\n`;
192
- void presenter.onAssistantText(text);
193
- continue;
194
- }
195
- if (block.type === "thinking" &&
196
- typeof block.thinking === "string") {
197
- void presenter.onThinking(block.thinking);
198
- continue;
199
- }
200
- if (block.type === "tool_use" &&
201
- typeof block.id === "string" &&
202
- typeof block.name === "string") {
203
- const toolBlock = block;
204
- void presenter.onToolUse(toolBlock.name, toolBlock.input ?? {}, toolBlock.id);
205
- }
206
- }
207
- break;
208
- }
209
- case "user": {
210
- const message = typeof parsed.message === "object" && parsed.message !== null
211
- ? parsed.message
212
- : null;
213
- const content = Array.isArray(message?.content) ? message.content : [];
214
- for (const block of content) {
215
- if (typeof block === "object" &&
216
- block !== null &&
217
- "type" in block &&
218
- block.type === "tool_result" &&
219
- "tool_use_id" in block &&
220
- typeof block.tool_use_id === "string") {
221
- void presenter.onToolResult?.(block.tool_use_id, extractToolResultContent(block.content));
222
- }
223
- }
224
- break;
225
- }
226
- case "result": {
227
- const inputTokens = typeof parsed.usage === "object" &&
228
- parsed.usage !== null &&
229
- typeof parsed.usage.input_tokens === "number"
230
- ? parsed.usage.input_tokens
231
- : 0;
232
- const outputTokens = typeof parsed.usage === "object" &&
233
- parsed.usage !== null &&
234
- typeof parsed.usage.output_tokens === "number"
235
- ? parsed.usage.output_tokens
236
- : 0;
237
- const cacheReadTokens = typeof parsed.usage === "object" &&
238
- parsed.usage !== null &&
239
- typeof parsed.usage.cache_read_input_tokens === "number"
240
- ? parsed.usage.cache_read_input_tokens
241
- : 0;
242
- const cacheCreationTokens = typeof parsed.usage === "object" &&
243
- parsed.usage !== null &&
244
- typeof parsed.usage.cache_creation_input_tokens === "number"
245
- ? parsed.usage.cache_creation_input_tokens
246
- : 0;
247
- state.usage = {
248
- model: typeof parsed.model === "string"
249
- ? parsed.model
250
- : typeof context.config.selectedModel === "string"
251
- ? context.config.selectedModel
252
- : "claude",
253
- numTurns: typeof parsed.num_turns === "number" ? parsed.num_turns : Math.max(state.iterations, 1),
254
- durationMs: typeof parsed.duration_ms === "number" ? parsed.duration_ms : 0,
255
- inputTokens,
256
- outputTokens,
257
- cacheReadTokens,
258
- cacheCreationTokens,
259
- costUsd: typeof parsed.total_cost_usd === "number" ? parsed.total_cost_usd : 0,
260
- };
261
- void presenter.onUsageUpdate?.({
262
- model: state.usage.model,
263
- inputTokens: state.usage.inputTokens,
264
- outputTokens: state.usage.outputTokens,
265
- cacheReadTokens: state.usage.cacheReadTokens,
266
- cacheCreationTokens: state.usage.cacheCreationTokens,
267
- });
268
- if (typeof parsed.result === "string" && parsed.result.trim().length > 0) {
269
- state.summary = parsed.result.trim();
270
- }
271
- if (typeof parsed.num_turns === "number") {
272
- state.iterations = parsed.num_turns;
273
- }
274
- const subtype = typeof parsed.subtype === "string" ? parsed.subtype : "";
275
- if ((subtype === "error_during_execution" || subtype === "error_max_turns") &&
276
- !state.error) {
277
- const errObj = typeof parsed.error === "object" && parsed.error !== null
278
- ? parsed.error
279
- : null;
280
- const errMsg = (typeof parsed.error === "string" && parsed.error.trim()) ||
281
- (errObj && typeof errObj.message === "string" && errObj.message.trim()) ||
282
- (typeof parsed.message === "string" && parsed.message.trim()) ||
283
- (typeof parsed.result === "string" && parsed.result.trim()) ||
284
- subtype;
285
- state.error = errMsg;
286
- const errFields = {
287
- error: parsed.error,
288
- message: parsed.message,
289
- result: typeof parsed.result === "string" ? parsed.result.slice(0, 200) : parsed.result,
290
- session_id: parsed.session_id,
291
- model: parsed.model,
292
- num_turns: parsed.num_turns,
293
- is_error: parsed.is_error,
294
- };
295
- console.error("[claude_cli] result subtype=", subtype, "error fields:", JSON.stringify(errFields));
296
- console.error("[claude_cli] Full result event:", JSON.stringify(parsed).slice(0, 2000));
297
- }
298
- break;
299
- }
300
- default:
301
- break;
302
- }
303
- }
304
- function parseCodexStructuredLine(line, context, state) {
305
- const presenter = context.presenter;
306
- let parsed = null;
307
- try {
308
- parsed = JSON.parse(line);
309
- }
310
- catch {
311
- state.summary += `${line}\n`;
312
- void presenter.onAssistantText(`${line}\n`);
313
- return;
314
- }
315
- const type = typeof parsed.type === "string" ? parsed.type : "";
316
- if (!type)
317
- return;
318
- if (typeof parsed.thread_id === "string") {
319
- state.runtimeSessionId = parsed.thread_id;
320
- }
321
- const extractCodexErrorMessage = (value) => {
322
- if (typeof value !== "string") {
323
- return "";
324
- }
325
- const trimmed = value.trim();
326
- if (!trimmed) {
327
- return "";
328
- }
329
- try {
330
- const parsedValue = JSON.parse(trimmed);
331
- if (typeof parsedValue.detail === "string" && parsedValue.detail.trim().length > 0) {
332
- return parsedValue.detail.trim();
333
- }
334
- if (typeof parsedValue.message === "string" && parsedValue.message.trim().length > 0) {
335
- return parsedValue.message.trim();
336
- }
337
- }
338
- catch {
339
- // Fall through to the raw string below.
340
- }
341
- return trimmed;
342
- };
343
- switch (type) {
344
- case "thread.started":
345
- break;
346
- case "turn.started":
347
- state.iterations += 1;
348
- break;
349
- case "session_configured":
350
- if (typeof parsed.session_id === "string") {
351
- state.runtimeSessionId = parsed.session_id;
352
- }
353
- break;
354
- case "task_started":
355
- state.iterations += 1;
356
- break;
357
- case "item.started": {
358
- const item = typeof parsed.item === "object" && parsed.item !== null
359
- ? parsed.item
360
- : null;
361
- if (!item || item.type !== "command_execution" || typeof item.id !== "string") {
362
- break;
363
- }
364
- const command = typeof item.command === "string" ? item.command : "";
365
- void presenter.onToolUse("Bash", { command, cwd: context.cwd }, item.id);
366
- break;
367
- }
368
- case "item.completed": {
369
- const item = typeof parsed.item === "object" && parsed.item !== null
370
- ? parsed.item
371
- : null;
372
- if (!item || typeof item.type !== "string") {
373
- break;
374
- }
375
- if (item.type === "reasoning" && typeof item.text === "string") {
376
- void presenter.onThinking(item.text);
377
- break;
378
- }
379
- if (item.type === "agent_message" && typeof item.text === "string") {
380
- state.summary += `${item.text}\n`;
381
- void presenter.onAssistantText(item.text);
382
- break;
383
- }
384
- if (item.type === "command_execution" && typeof item.id === "string") {
385
- const output = typeof item.aggregated_output === "string" ? item.aggregated_output : "";
386
- const exitCode = typeof item.exit_code === "number" ? item.exit_code : null;
387
- const resultText = output.trim().length > 0
388
- ? output
389
- : exitCode === null
390
- ? ""
391
- : `Exit code: ${exitCode}`;
392
- void presenter.onToolResult?.(item.id, resultText);
393
- break;
394
- }
395
- break;
396
- }
397
- case "agent_message_delta":
398
- case "agent_message_content_delta": {
399
- const delta = typeof parsed.delta === "string" ? parsed.delta : "";
400
- if (!delta)
401
- return;
402
- state.summary += delta;
403
- void presenter.onAssistantText(delta);
404
- break;
405
- }
406
- case "agent_reasoning_delta":
407
- case "reasoning_content_delta":
408
- case "agent_reasoning_raw_content_delta": {
409
- const delta = typeof parsed.delta === "string" ? parsed.delta : "";
410
- if (!delta)
411
- return;
412
- void presenter.onThinking(delta);
413
- break;
414
- }
415
- case "exec_command_begin": {
416
- const toolId = typeof parsed.call_id === "string" ? parsed.call_id : `exec-${Date.now()}`;
417
- const command = Array.isArray(parsed.command) ? parsed.command.join(" ") : "";
418
- const cwd = typeof parsed.cwd === "string" ? parsed.cwd : context.cwd;
419
- void presenter.onToolUse("Bash", { command, cwd }, toolId);
420
- break;
421
- }
422
- case "exec_command_end": {
423
- const toolId = typeof parsed.call_id === "string" ? parsed.call_id : `exec-${Date.now()}`;
424
- const output = typeof parsed.formatted_output === "string"
425
- ? parsed.formatted_output
426
- : typeof parsed.aggregated_output === "string"
427
- ? parsed.aggregated_output
428
- : "";
429
- void presenter.onToolResult?.(toolId, output);
430
- break;
431
- }
432
- case "mcp_tool_call_begin": {
433
- const toolId = typeof parsed.call_id === "string" ? parsed.call_id : `mcp-${Date.now()}`;
434
- const invocation = typeof parsed.invocation === "object" && parsed.invocation !== null
435
- ? parsed.invocation
436
- : {};
437
- const tool = typeof invocation.tool_name === "string"
438
- ? invocation.tool_name
439
- : typeof invocation.tool === "string"
440
- ? invocation.tool
441
- : "MCP Tool";
442
- void presenter.onToolUse(tool, invocation, toolId);
443
- break;
444
- }
445
- case "mcp_tool_call_end": {
446
- const toolId = typeof parsed.call_id === "string" ? parsed.call_id : `mcp-${Date.now()}`;
447
- const result = parsed.result;
448
- void presenter.onToolResult?.(toolId, JSON.stringify(result ?? {}, null, 2));
449
- break;
450
- }
451
- case "token_count": {
452
- const info = typeof parsed.info === "object" && parsed.info !== null
453
- ? parsed.info
454
- : {};
455
- const inputTokens = typeof info.input_tokens === "number" ? info.input_tokens : 0;
456
- const outputTokens = typeof info.output_tokens === "number" ? info.output_tokens : 0;
457
- state.usage = {
458
- model: typeof info.model === "string" ? info.model : "codex",
459
- numTurns: Math.max(state.iterations, 1),
460
- durationMs: 0,
461
- inputTokens,
462
- outputTokens,
463
- cacheReadTokens: typeof info.cached_input_tokens === "number" ? info.cached_input_tokens : 0,
464
- cacheCreationTokens: 0,
465
- costUsd: typeof info.total_cost_usd === "number" ? info.total_cost_usd : 0,
466
- };
467
- void presenter.onUsageUpdate?.({
468
- model: state.usage.model,
469
- inputTokens: state.usage.inputTokens,
470
- outputTokens: state.usage.outputTokens,
471
- cacheReadTokens: state.usage.cacheReadTokens,
472
- cacheCreationTokens: state.usage.cacheCreationTokens,
473
- });
474
- break;
475
- }
476
- case "task_complete": {
477
- const lastMessage = typeof parsed.last_agent_message === "string" ? parsed.last_agent_message : "";
478
- if (lastMessage.length > 0) {
479
- state.summary = lastMessage;
480
- }
481
- break;
482
- }
483
- case "turn.completed": {
484
- const usage = typeof parsed.usage === "object" && parsed.usage !== null
485
- ? parsed.usage
486
- : {};
487
- const inputTokens = typeof usage.input_tokens === "number" ? usage.input_tokens : 0;
488
- const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
489
- const cacheReadTokens = typeof usage.cached_input_tokens === "number" ? usage.cached_input_tokens : 0;
490
- state.usage = {
491
- model: typeof context.config.selectedModel === "string" && context.config.selectedModel.trim()
492
- ? context.config.selectedModel
493
- : "codex",
494
- numTurns: Math.max(state.iterations, 1),
495
- durationMs: 0,
496
- inputTokens,
497
- outputTokens,
498
- cacheReadTokens,
499
- cacheCreationTokens: 0,
500
- costUsd: 0,
501
- };
502
- void presenter.onUsageUpdate?.({
503
- model: state.usage.model,
504
- inputTokens: state.usage.inputTokens,
505
- outputTokens: state.usage.outputTokens,
506
- cacheReadTokens: state.usage.cacheReadTokens,
507
- cacheCreationTokens: state.usage.cacheCreationTokens,
508
- });
509
- break;
510
- }
511
- case "error": {
512
- const message = extractCodexErrorMessage(parsed.message);
513
- if (message) {
514
- state.error = message;
515
- }
516
- break;
517
- }
518
- case "turn.failed": {
519
- const error = typeof parsed.error === "object" && parsed.error !== null
520
- ? parsed.error
521
- : {};
522
- const message = extractCodexErrorMessage(error.message);
523
- if (message) {
524
- state.error = message;
525
- }
526
- break;
527
- }
528
- default:
529
- break;
530
- }
531
- }
532
- function buildGeminiToolResultText(parsed) {
533
- const output = typeof parsed.output === "string" ? parsed.output : "";
534
- if (output.trim().length > 0) {
535
- return output;
536
- }
537
- const error = typeof parsed.error === "object" && parsed.error !== null
538
- ? parsed.error
539
- : null;
540
- const message = typeof error?.message === "string" ? error.message.trim() : "";
541
- const errorType = typeof error?.type === "string" ? error.type.trim() : "";
542
- if (message && errorType) {
543
- return `${errorType}: ${message}`;
544
- }
545
- if (message) {
546
- return message;
547
- }
548
- const status = typeof parsed.status === "string" ? parsed.status.trim() : "";
549
- return status || "Tool completed";
550
- }
551
- function parseGeminiStructuredLine(line, context, state) {
552
- const presenter = context.presenter;
553
- let parsed = null;
554
- try {
555
- parsed = JSON.parse(line);
556
- }
557
- catch {
558
- state.summary += `${line}\n`;
559
- void presenter.onAssistantText(`${line}\n`);
560
- return;
561
- }
562
- const type = typeof parsed.type === "string" ? parsed.type : "";
563
- if (!type) {
564
- return;
565
- }
566
- if (typeof parsed.session_id === "string") {
567
- state.runtimeSessionId = parsed.session_id;
568
- }
569
- if (typeof parsed.model === "string") {
570
- state.activeModel = parsed.model;
571
- }
572
- switch (type) {
573
- case "init": {
574
- const model = state.activeModel || context.config.selectedModel || "gemini";
575
- void presenter.onLog(`[gemini_cli] Session initialized with ${model}`);
576
- break;
577
- }
578
- case "message": {
579
- const role = typeof parsed.role === "string" ? parsed.role : "";
580
- if (role !== "assistant") {
581
- break;
582
- }
583
- const content = typeof parsed.content === "string" ? parsed.content : "";
584
- if (!content) {
585
- break;
586
- }
587
- state.iterations = Math.max(state.iterations, 1);
588
- state.summary += content;
589
- void presenter.onAssistantText(content);
590
- break;
591
- }
592
- case "tool_use": {
593
- const toolName = typeof parsed.tool_name === "string" ? parsed.tool_name : "Gemini Tool";
594
- const toolId = typeof parsed.tool_id === "string" ? parsed.tool_id : `gemini-tool-${Date.now()}`;
595
- state.iterations = Math.max(state.iterations, 1);
596
- void presenter.onToolUse(toolName, parsed.parameters ?? {}, toolId);
597
- break;
598
- }
599
- case "tool_result": {
600
- const toolId = typeof parsed.tool_id === "string" ? parsed.tool_id : `gemini-tool-${Date.now()}`;
601
- state.iterations = Math.max(state.iterations, 1);
602
- void presenter.onToolResult?.(toolId, buildGeminiToolResultText(parsed));
603
- break;
604
- }
605
- case "error": {
606
- const message = typeof parsed.message === "string" ? parsed.message.trim() : "";
607
- const severity = typeof parsed.severity === "string" ? parsed.severity : "error";
608
- if (message) {
609
- void presenter.onLog(`[gemini_cli/${severity}] ${message}`);
610
- if (severity === "error") {
611
- state.error = message;
612
- }
613
- }
614
- break;
615
- }
616
- case "result": {
617
- const stats = typeof parsed.stats === "object" && parsed.stats !== null
618
- ? parsed.stats
619
- : {};
620
- state.iterations = Math.max(state.iterations, 1);
621
- state.usage = {
622
- model: state.activeModel ||
623
- (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim()
624
- ? context.config.selectedModel
625
- : "gemini"),
626
- numTurns: Math.max(state.iterations, 1),
627
- durationMs: typeof stats.duration_ms === "number" ? stats.duration_ms : 0,
628
- inputTokens: typeof stats.input_tokens === "number"
629
- ? stats.input_tokens
630
- : typeof stats.input === "number"
631
- ? stats.input
632
- : 0,
633
- outputTokens: typeof stats.output_tokens === "number" ? stats.output_tokens : 0,
634
- cacheReadTokens: typeof stats.cached === "number" ? stats.cached : 0,
635
- cacheCreationTokens: 0,
636
- costUsd: 0,
637
- };
638
- void presenter.onUsageUpdate?.({
639
- model: state.usage.model,
640
- inputTokens: state.usage.inputTokens,
641
- outputTokens: state.usage.outputTokens,
642
- cacheReadTokens: state.usage.cacheReadTokens,
643
- cacheCreationTokens: state.usage.cacheCreationTokens,
644
- });
645
- if (typeof parsed.status === "string" && parsed.status !== "success" && !state.error) {
646
- state.error = parsed.status;
647
- }
648
- break;
649
- }
650
- default:
651
- break;
652
- }
653
- }
654
- function getClaudePermissionMode(mode) {
655
- switch (mode) {
656
- case "plan":
657
- case "ask":
658
- case "review":
659
- return "plan";
660
- default:
661
- return "bypassPermissions";
662
- }
663
- }
664
- export function createClaudeCliBackend(command = "claude", defaultArgs = []) {
665
- return {
666
- kind: "claude_cli",
667
- supportTier: "structured",
668
- async run(context) {
669
- const args = [
670
- "--print",
671
- "--verbose",
672
- "--output-format",
673
- "stream-json",
674
- "--permission-mode",
675
- getClaudePermissionMode(context.config.mode),
676
- ];
677
- if (context.config.systemPrompt?.trim()) {
678
- args.push("--system-prompt", context.config.systemPrompt.trim());
679
- }
680
- if (context.config.systemPromptAppend?.trim()) {
681
- args.push("--append-system-prompt", context.config.systemPromptAppend.trim());
682
- }
683
- if (context.config.selectedModel?.trim()) {
684
- args.push("--model", context.config.selectedModel.trim());
685
- }
686
- const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
687
- if (resumeId) {
688
- args.push("--resume", resumeId);
689
- console.info("[claude_cli] Resuming session", { resumeId });
690
- }
691
- args.push(...defaultArgs, context.promptText);
692
- return createGenericCliBackend({
693
- kind: "claude_cli",
694
- supportTier: "structured",
695
- command,
696
- args,
697
- parseStructuredLine: parseClaudeStructuredLine,
698
- }).run(context);
699
- },
700
- };
701
- }
702
- export function createGeminiCliBackend(command = "gemini", defaultArgs = []) {
703
- return createGenericCliBackend({
704
- kind: "gemini_cli",
705
- supportTier: "structured",
706
- command,
707
- args: [],
708
- buildArgs: (context) => {
709
- const args = ["-p", "", "--output-format", "stream-json"];
710
- const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
711
- const approvalMode = context.config.mode === "plan" ||
712
- context.config.mode === "ask" ||
713
- context.config.mode === "review"
714
- ? "plan"
715
- : "yolo";
716
- args.push("--approval-mode", approvalMode);
717
- if (resumeId) {
718
- args.push("--resume", resumeId);
719
- }
720
- if (context.config.selectedModel?.trim()) {
721
- args.push("--model", context.config.selectedModel.trim());
722
- }
723
- return [...args, ...defaultArgs];
724
- },
725
- promptViaStdin: true,
726
- augmentPrompt: (context) => {
727
- const basePrompt = buildPromptWithSystem(context.config, context.promptText);
728
- if (context.config.mode === "plan") {
729
- return buildPlanModePrefix(basePrompt);
730
- }
731
- return basePrompt;
732
- },
733
- parseStructuredLine: parseGeminiStructuredLine,
734
- });
735
- }
736
- export function createGenericCliPassthroughBackend(command, defaultArgs = []) {
737
- return createGenericCliBackend({
738
- kind: "generic_cli",
739
- supportTier: "text",
740
- command,
741
- args: defaultArgs,
742
- promptViaStdin: true,
743
- });
744
- }
745
- export function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
746
- return createGenericCliBackend({
747
- kind: "codex_app_server",
748
- supportTier: "structured",
749
- command,
750
- args: [],
751
- buildArgs: (context) => {
752
- const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
753
- const baseArgs = resumeId
754
- ? ["exec", "resume", "--json", "--skip-git-repo-check", resumeId, "-"]
755
- : ["exec", "--json", "--skip-git-repo-check", "-"];
756
- return [...baseArgs, ...defaultArgs];
757
- },
758
- promptViaStdin: true,
759
- augmentPrompt: (context) => {
760
- const basePrompt = buildPromptWithSystem(context.config, context.promptText);
761
- if (context.config.mode === "plan") {
762
- return buildPlanModePrefix(basePrompt);
763
- }
764
- return basePrompt;
765
- },
766
- parseStructuredLine: parseCodexStructuredLine,
767
- });
768
- }
1
+ export * from "@aiden/agent-core";
769
2
  //# sourceMappingURL=runtime-backends.js.map