@agentfield/sdk 0.1.130-rc.4 → 0.1.130

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs, { promises, readFileSync } from 'fs';
2
- import * as path2 from 'path';
3
- import path2__default, { resolve, dirname } from 'path';
2
+ import * as path3 from 'path';
3
+ import path3__default, { resolve, dirname } from 'path';
4
4
  import { createRequire } from 'module';
5
5
  import { spawn } from 'child_process';
6
6
  import express from 'express';
@@ -197,7 +197,7 @@ function estimateTokens(text2) {
197
197
  }
198
198
  function writeSchemaFile(schemaJson, cwd) {
199
199
  const filePath = getSchemaPath(cwd);
200
- fs.mkdirSync(path2__default.dirname(filePath), { recursive: true });
200
+ fs.mkdirSync(path3__default.dirname(filePath), { recursive: true });
201
201
  const fd = fs.openSync(filePath, "w", 384);
202
202
  try {
203
203
  fs.writeFileSync(fd, schemaJson, "utf8");
@@ -213,10 +213,10 @@ function validateAgainstSchema(data, schema) {
213
213
  return data;
214
214
  }
215
215
  function getOutputPath(cwd) {
216
- return path2__default.join(cwd, OUTPUT_FILENAME);
216
+ return path3__default.join(cwd, OUTPUT_FILENAME);
217
217
  }
218
218
  function getSchemaPath(cwd) {
219
- return path2__default.join(cwd, SCHEMA_FILENAME);
219
+ return path3__default.join(cwd, SCHEMA_FILENAME);
220
220
  }
221
221
  function schemaToJsonSchema(schema) {
222
222
  if (isRecord2(schema)) {
@@ -322,7 +322,7 @@ function parseAndValidate(filePath, schema) {
322
322
  function cleanupTempFiles(cwd) {
323
323
  for (const filename of [OUTPUT_FILENAME, SCHEMA_FILENAME]) {
324
324
  try {
325
- fs.unlinkSync(path2__default.join(cwd, filename));
325
+ fs.unlinkSync(path3__default.join(cwd, filename));
326
326
  } catch {
327
327
  }
328
328
  }
@@ -361,6 +361,393 @@ var init_types = __esm({
361
361
  "src/harness/types.ts"() {
362
362
  }
363
363
  });
364
+ function resolveIdleMs(idleSeconds) {
365
+ let seconds = idleSeconds;
366
+ if (seconds === void 0) {
367
+ const raw = process.env.AGENTFIELD_HARNESS_IDLE_SECONDS;
368
+ const parsed = raw !== void 0 ? Number(raw) : NaN;
369
+ seconds = Number.isFinite(parsed) ? parsed : DEFAULT_IDLE_SECONDS;
370
+ }
371
+ return seconds > 0 ? seconds * 1e3 : void 0;
372
+ }
373
+ function runCli(cmd, options) {
374
+ return new Promise((resolve3, reject) => {
375
+ const [bin, ...args] = cmd;
376
+ const env = { ...process.env, ...options?.env };
377
+ applyOpenRouterAttributionEnv(env);
378
+ const hasInput = options?.inputText !== void 0;
379
+ const proc = spawn(bin, args, {
380
+ env,
381
+ cwd: options?.cwd,
382
+ stdio: [hasInput ? "pipe" : "ignore", "pipe", "pipe"]
383
+ });
384
+ if (hasInput) {
385
+ proc.stdin?.end(options.inputText);
386
+ }
387
+ let stdout = "";
388
+ let stderr = "";
389
+ let settled = false;
390
+ let lastActivity = Date.now();
391
+ proc.stdout.on("data", (data) => {
392
+ stdout += data.toString();
393
+ lastActivity = Date.now();
394
+ });
395
+ proc.stderr.on("data", (data) => {
396
+ stderr += data.toString();
397
+ lastActivity = Date.now();
398
+ });
399
+ const timer = options?.timeout ? setTimeout(() => {
400
+ if (settled) {
401
+ return;
402
+ }
403
+ settled = true;
404
+ cleanup();
405
+ proc.kill("SIGKILL");
406
+ reject(new Error(`CLI timed out after ${options.timeout}ms`));
407
+ }, options.timeout) : void 0;
408
+ const idleMs = resolveIdleMs(options?.idleSeconds);
409
+ const idleTimer = idleMs ? setInterval(() => {
410
+ if (settled) {
411
+ return;
412
+ }
413
+ if (Date.now() - lastActivity >= idleMs) {
414
+ settled = true;
415
+ cleanup();
416
+ proc.kill("SIGKILL");
417
+ reject(
418
+ new Error(
419
+ `CLI made no progress for ${Math.round(idleMs / 1e3)}s`
420
+ )
421
+ );
422
+ }
423
+ }, Math.min(idleMs, 1e3)) : void 0;
424
+ function cleanup() {
425
+ if (timer) {
426
+ clearTimeout(timer);
427
+ }
428
+ if (idleTimer) {
429
+ clearInterval(idleTimer);
430
+ }
431
+ }
432
+ proc.on("close", (code) => {
433
+ if (settled) {
434
+ return;
435
+ }
436
+ settled = true;
437
+ cleanup();
438
+ resolve3({ stdout, stderr, exitCode: code ?? 0 });
439
+ });
440
+ proc.on("error", (err) => {
441
+ if (settled) {
442
+ return;
443
+ }
444
+ settled = true;
445
+ cleanup();
446
+ reject(err);
447
+ });
448
+ });
449
+ }
450
+ function parseJsonl(text2) {
451
+ const events = [];
452
+ for (const line of text2.split("\n")) {
453
+ const trimmed = line.trim();
454
+ if (!trimmed) {
455
+ continue;
456
+ }
457
+ try {
458
+ events.push(JSON.parse(trimmed));
459
+ } catch {
460
+ continue;
461
+ }
462
+ }
463
+ return events;
464
+ }
465
+ function extractFinalText(events) {
466
+ let result;
467
+ for (const event of events) {
468
+ const type = event.type;
469
+ if (type === "item.completed") {
470
+ const item = event.item;
471
+ if (typeof item === "object" && item !== null) {
472
+ const itemType = item.type;
473
+ const itemText = item.text;
474
+ if (itemType === "agent_message" && typeof itemText === "string") {
475
+ result = itemText;
476
+ }
477
+ }
478
+ } else if (type === "result") {
479
+ const candidate = event.result ?? event.text;
480
+ if (typeof candidate === "string") {
481
+ result = candidate;
482
+ }
483
+ } else if (type === "turn.completed" && typeof event.text === "string") {
484
+ result = event.text;
485
+ } else if ((type === "message" || type === "assistant") && typeof event.content === "string") {
486
+ result = event.content;
487
+ }
488
+ }
489
+ return result;
490
+ }
491
+ var DEFAULT_IDLE_SECONDS;
492
+ var init_cli = __esm({
493
+ "src/harness/cli.ts"() {
494
+ init_openrouterAttribution();
495
+ DEFAULT_IDLE_SECONDS = 120;
496
+ }
497
+ });
498
+
499
+ // src/harness/providers/aforge.ts
500
+ var aforge_exports = {};
501
+ __export(aforge_exports, {
502
+ AFORGE_DEFAULT_MODEL: () => AFORGE_DEFAULT_MODEL,
503
+ AforgeProvider: () => AforgeProvider
504
+ });
505
+ function resolveMaxConcurrent() {
506
+ const parsed = Number.parseInt(process.env.AFORGE_MAX_CONCURRENT ?? "", 10);
507
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MAX_CONCURRENT;
508
+ }
509
+ function stripOpenRouterPrefix(model) {
510
+ return model.startsWith("openrouter/") ? model.slice("openrouter/".length) : model;
511
+ }
512
+ function parseEnvelope(stdout) {
513
+ try {
514
+ const value = JSON.parse(stdout.trim());
515
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && ("deliverable" in value || "text" in value)) {
516
+ return value;
517
+ }
518
+ } catch {
519
+ }
520
+ const lines = stdout.split("\n").map((line) => line.trim()).filter(Boolean);
521
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
522
+ try {
523
+ const value = JSON.parse(lines[index]);
524
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && ("deliverable" in value || "text" in value)) {
525
+ return value;
526
+ }
527
+ } catch {
528
+ }
529
+ }
530
+ return void 0;
531
+ }
532
+ function numeric(value) {
533
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
534
+ }
535
+ function timeoutSeconds() {
536
+ const parsed = Number.parseInt(process.env.AGENTFIELD_HARNESS_TIMEOUT_SECONDS ?? "", 10);
537
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TIMEOUT_SECONDS;
538
+ }
539
+ function innerTimeout(outer) {
540
+ return outer > LANDING_WINDOW_SECONDS ? outer - LANDING_WINDOW_SECONDS : 1;
541
+ }
542
+ function taskInput(prompt, systemPrompt) {
543
+ return typeof systemPrompt === "string" && systemPrompt.trim() ? `${systemPrompt.trim()}
544
+
545
+ Task:
546
+ ${prompt}` : prompt;
547
+ }
548
+ function crashMessage(exitCode, blockedOn, deliverable, stderr) {
549
+ const cleanStderr = stderr.trim().replace(ANSI_PATTERN, "");
550
+ const exitContext = `aforge exit code ${exitCode}`;
551
+ let message = exitCode < 0 ? `Process killed by signal ${-exitCode}. ${exitContext}` : exitContext;
552
+ if (cleanStderr) {
553
+ message += `. stderr: ${cleanStderr.slice(0, 1e3)}`;
554
+ } else if (blockedOn) {
555
+ message += `. blocked_on: ${blockedOn.slice(0, 1e3)}`;
556
+ } else if (deliverable) {
557
+ message += `. partial: ${deliverable.slice(0, 1e3)}`;
558
+ }
559
+ return message;
560
+ }
561
+ function stringOptions(value) {
562
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
563
+ return {};
564
+ }
565
+ const result = {};
566
+ for (const [key, item] of Object.entries(value)) {
567
+ if (typeof item === "string") {
568
+ result[key] = item;
569
+ }
570
+ }
571
+ return result;
572
+ }
573
+ var REASONING_VARIANTS, DEFAULT_TIMEOUT_SECONDS, LANDING_WINDOW_SECONDS, DEFAULT_MAX_CONCURRENT, ANSI_PATTERN, AFORGE_DEFAULT_MODEL, Semaphore, aforgeSemaphore, AforgeProvider;
574
+ var init_aforge = __esm({
575
+ "src/harness/providers/aforge.ts"() {
576
+ init_types();
577
+ init_cli();
578
+ init_modelVariant();
579
+ REASONING_VARIANTS = /* @__PURE__ */ new Set(["off", "low", "medium", "high"]);
580
+ DEFAULT_TIMEOUT_SECONDS = 1800;
581
+ LANDING_WINDOW_SECONDS = 5;
582
+ DEFAULT_MAX_CONCURRENT = 8;
583
+ ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
584
+ AFORGE_DEFAULT_MODEL = "~deepseek/deepseek-v4-flash-latest";
585
+ Semaphore = class {
586
+ constructor(limit) {
587
+ this.limit = limit;
588
+ }
589
+ limit;
590
+ active = 0;
591
+ waiters = [];
592
+ async use(operation) {
593
+ await this.acquire();
594
+ try {
595
+ return await operation();
596
+ } finally {
597
+ this.release();
598
+ }
599
+ }
600
+ acquire() {
601
+ if (this.active < this.limit) {
602
+ this.active += 1;
603
+ return Promise.resolve();
604
+ }
605
+ return new Promise((resolve3) => {
606
+ this.waiters.push(() => {
607
+ this.active += 1;
608
+ resolve3();
609
+ });
610
+ });
611
+ }
612
+ release() {
613
+ this.active -= 1;
614
+ this.waiters.shift()?.();
615
+ }
616
+ };
617
+ aforgeSemaphore = new Semaphore(resolveMaxConcurrent());
618
+ AforgeProvider = class {
619
+ bin;
620
+ constructor(bin = "aforge") {
621
+ this.bin = bin === "aforge" ? process.env.AFORGE_BIN?.trim() || bin : bin;
622
+ }
623
+ async execute(prompt, options) {
624
+ return aforgeSemaphore.use(() => this.executeImpl(prompt, options));
625
+ }
626
+ async executeImpl(prompt, options) {
627
+ const projectDir = typeof options.projectDir === "string" ? options.projectDir : typeof options.project_dir === "string" ? options.project_dir : void 0;
628
+ const cwd = typeof options.cwd === "string" ? options.cwd : void 0;
629
+ const root = projectDir ?? cwd ?? ".";
630
+ const outerTimeout = timeoutSeconds();
631
+ const command = (process.env.AGENTFIELD_AFORGE_COMMAND ?? "exec").trim().toLowerCase();
632
+ if (command !== "do" && command !== "exec") {
633
+ return createRawResult({
634
+ isError: true,
635
+ errorMessage: `AGENTFIELD_AFORGE_COMMAND must be 'do' or 'exec', got ${JSON.stringify(command)}`,
636
+ failureType: "crash",
637
+ metrics: createMetrics()
638
+ });
639
+ }
640
+ const systemPrompt = options.systemPrompt ?? options.system_prompt;
641
+ const cmd = command === "exec" ? [
642
+ this.bin,
643
+ "exec",
644
+ "--json",
645
+ "-w",
646
+ root,
647
+ "--timeout",
648
+ String(innerTimeout(outerTimeout))
649
+ ] : [
650
+ this.bin,
651
+ "do",
652
+ "--json",
653
+ "--yes-spend",
654
+ "-w",
655
+ root,
656
+ "--timeout",
657
+ String(innerTimeout(outerTimeout))
658
+ ];
659
+ if (command === "exec" && typeof options.maxTurns === "number" && Number.isFinite(options.maxTurns) && options.maxTurns > 0) {
660
+ cmd.push("--turns", String(Math.trunc(options.maxTurns)));
661
+ }
662
+ if (command === "exec") {
663
+ cmd.push("--context-fill", "60", "--completion-reserve", "65536");
664
+ }
665
+ if (command === "exec" && typeof systemPrompt === "string" && systemPrompt.trim()) {
666
+ cmd.push("--system", systemPrompt.trim());
667
+ }
668
+ const { model, variant } = resolveModelAndVariant(options);
669
+ const env = command === "exec" ? { AFORGE_MODELS: "" } : {};
670
+ if (model) {
671
+ const slug = stripOpenRouterPrefix(model);
672
+ env.AFORGE_MODEL = slug;
673
+ if (command === "exec") {
674
+ cmd.push("--model", slug, "--plan-model", slug);
675
+ }
676
+ }
677
+ if (variant) {
678
+ const normalized = variant.trim().toLowerCase();
679
+ if (REASONING_VARIANTS.has(normalized)) {
680
+ env.AFORGE_EXEC_REASONING = normalized;
681
+ }
682
+ }
683
+ Object.assign(env, stringOptions(options.env));
684
+ const effectiveModel = model || env.AFORGE_MODEL || AFORGE_DEFAULT_MODEL;
685
+ const startApi = Date.now();
686
+ try {
687
+ const { stdout, stderr, exitCode } = await runCli(cmd, {
688
+ env,
689
+ cwd: void 0,
690
+ timeout: outerTimeout * 1e3,
691
+ idleSeconds: 0,
692
+ inputText: command === "exec" ? prompt : taskInput(prompt, systemPrompt)
693
+ });
694
+ const envelope = parseEnvelope(stdout);
695
+ const outputValue = command === "exec" ? envelope?.text : envelope?.deliverable;
696
+ const resultText = typeof outputValue === "string" && outputValue.trim() ? outputValue.trim() : void 0;
697
+ const blockedOn = typeof envelope?.blocked_on === "string" ? envelope.blocked_on.trim() : "";
698
+ const stop = typeof envelope?.stop === "string" ? envelope.stop.trim() : "";
699
+ const usage = typeof envelope?.usage === "object" && envelope.usage !== null && !Array.isArray(envelope.usage) ? envelope.usage : {};
700
+ const isError = command === "exec" ? exitCode < 0 || resultText === void 0 || ![0, 2, 3].includes(exitCode) : exitCode !== 0 || resultText === void 0 || blockedOn !== "";
701
+ const inputTokens = Math.trunc(numeric(usage.prompt_tokens) ?? 0);
702
+ const outputTokens = Math.trunc(numeric(usage.completion_tokens) ?? 0);
703
+ const cacheReadTokens = Math.trunc(numeric(usage.cached_tokens) ?? 0);
704
+ const calls = Math.trunc(numeric(command === "exec" ? envelope?.turns : usage.calls) ?? 0);
705
+ const nativeSpend = numeric(envelope?.spend);
706
+ const legacyCost = numeric(usage.cost);
707
+ const providerCost = nativeSpend !== void 0 && nativeSpend > 0 ? nativeSpend : legacyCost;
708
+ return createRawResult({
709
+ result: resultText,
710
+ messages: envelope ? [envelope] : [],
711
+ metrics: createMetrics({
712
+ durationApiMs: Date.now() - startApi,
713
+ numTurns: calls,
714
+ totalCostUsd: providerCost !== void 0 && providerCost > 0 ? providerCost : void 0,
715
+ usage,
716
+ sessionId: "",
717
+ inputTokens,
718
+ outputTokens,
719
+ cacheReadTokens,
720
+ cacheCreationTokens: 0,
721
+ totalTokens: inputTokens + outputTokens,
722
+ model: effectiveModel
723
+ }),
724
+ isError,
725
+ errorMessage: isError ? crashMessage(exitCode, blockedOn || stop, resultText, stderr) : void 0,
726
+ failureType: isError ? command === "do" && exitCode === 2 || command === "exec" && exitCode === 4 ? "timeout" : "crash" : "none",
727
+ returnCode: exitCode
728
+ });
729
+ } catch (error) {
730
+ const message = error instanceof Error ? error.message : String(error);
731
+ if (message.includes("ENOENT")) {
732
+ return createRawResult({
733
+ isError: true,
734
+ errorMessage: `AForge binary not found at '${this.bin}'. Install it with \`af aforge ensure\`, or set AFORGE_BIN to its path.`,
735
+ failureType: "crash",
736
+ metrics: createMetrics({ durationApiMs: Date.now() - startApi })
737
+ });
738
+ }
739
+ const timedOut = /timed out|deadline exceeded|no progress/i.test(message);
740
+ return createRawResult({
741
+ isError: true,
742
+ errorMessage: message,
743
+ failureType: timedOut ? "timeout" : "crash",
744
+ metrics: createMetrics({ durationApiMs: Date.now() - startApi })
745
+ });
746
+ }
747
+ }
748
+ };
749
+ }
750
+ });
364
751
 
365
752
  // src/harness/providers/claude.ts
366
753
  var claude_exports = {};
@@ -499,136 +886,6 @@ var init_claude = __esm({
499
886
  };
500
887
  }
501
888
  });
502
- function resolveIdleMs(idleSeconds) {
503
- let seconds = idleSeconds;
504
- if (seconds === void 0) {
505
- const raw = process.env.AGENTFIELD_HARNESS_IDLE_SECONDS;
506
- const parsed = raw !== void 0 ? Number(raw) : NaN;
507
- seconds = Number.isFinite(parsed) ? parsed : DEFAULT_IDLE_SECONDS;
508
- }
509
- return seconds > 0 ? seconds * 1e3 : void 0;
510
- }
511
- function runCli(cmd, options) {
512
- return new Promise((resolve3, reject) => {
513
- const [bin, ...args] = cmd;
514
- const env = { ...process.env, ...options?.env };
515
- applyOpenRouterAttributionEnv(env);
516
- const proc = spawn(bin, args, {
517
- env,
518
- cwd: options?.cwd,
519
- stdio: ["ignore", "pipe", "pipe"]
520
- });
521
- let stdout = "";
522
- let stderr = "";
523
- let settled = false;
524
- let lastActivity = Date.now();
525
- proc.stdout.on("data", (data) => {
526
- stdout += data.toString();
527
- lastActivity = Date.now();
528
- });
529
- proc.stderr.on("data", (data) => {
530
- stderr += data.toString();
531
- lastActivity = Date.now();
532
- });
533
- const timer = options?.timeout ? setTimeout(() => {
534
- if (settled) {
535
- return;
536
- }
537
- settled = true;
538
- cleanup();
539
- proc.kill("SIGKILL");
540
- reject(new Error(`CLI timed out after ${options.timeout}ms`));
541
- }, options.timeout) : void 0;
542
- const idleMs = resolveIdleMs(options?.idleSeconds);
543
- const idleTimer = idleMs ? setInterval(() => {
544
- if (settled) {
545
- return;
546
- }
547
- if (Date.now() - lastActivity >= idleMs) {
548
- settled = true;
549
- cleanup();
550
- proc.kill("SIGKILL");
551
- reject(
552
- new Error(
553
- `CLI made no progress for ${Math.round(idleMs / 1e3)}s`
554
- )
555
- );
556
- }
557
- }, Math.min(idleMs, 1e3)) : void 0;
558
- function cleanup() {
559
- if (timer) {
560
- clearTimeout(timer);
561
- }
562
- if (idleTimer) {
563
- clearInterval(idleTimer);
564
- }
565
- }
566
- proc.on("close", (code) => {
567
- if (settled) {
568
- return;
569
- }
570
- settled = true;
571
- cleanup();
572
- resolve3({ stdout, stderr, exitCode: code ?? 0 });
573
- });
574
- proc.on("error", (err) => {
575
- if (settled) {
576
- return;
577
- }
578
- settled = true;
579
- cleanup();
580
- reject(err);
581
- });
582
- });
583
- }
584
- function parseJsonl(text2) {
585
- const events = [];
586
- for (const line of text2.split("\n")) {
587
- const trimmed = line.trim();
588
- if (!trimmed) {
589
- continue;
590
- }
591
- try {
592
- events.push(JSON.parse(trimmed));
593
- } catch {
594
- continue;
595
- }
596
- }
597
- return events;
598
- }
599
- function extractFinalText(events) {
600
- let result;
601
- for (const event of events) {
602
- const type = event.type;
603
- if (type === "item.completed") {
604
- const item = event.item;
605
- if (typeof item === "object" && item !== null) {
606
- const itemType = item.type;
607
- const itemText = item.text;
608
- if (itemType === "agent_message" && typeof itemText === "string") {
609
- result = itemText;
610
- }
611
- }
612
- } else if (type === "result") {
613
- const candidate = event.result ?? event.text;
614
- if (typeof candidate === "string") {
615
- result = candidate;
616
- }
617
- } else if (type === "turn.completed" && typeof event.text === "string") {
618
- result = event.text;
619
- } else if ((type === "message" || type === "assistant") && typeof event.content === "string") {
620
- result = event.content;
621
- }
622
- }
623
- return result;
624
- }
625
- var DEFAULT_IDLE_SECONDS;
626
- var init_cli = __esm({
627
- "src/harness/cli.ts"() {
628
- init_openrouterAttribution();
629
- DEFAULT_IDLE_SECONDS = 120;
630
- }
631
- });
632
889
 
633
890
  // src/harness/providers/codex.ts
634
891
  var codex_exports = {};
@@ -875,34 +1132,49 @@ ${prompt}`;
875
1132
  });
876
1133
 
877
1134
  // src/harness/providers/factory.ts
1135
+ function resolveProviderName(explicit) {
1136
+ const explicitName = explicit?.trim();
1137
+ if (explicitName) {
1138
+ return explicitName;
1139
+ }
1140
+ const envName = process.env[HARNESS_PROVIDER_ENV_VAR]?.trim();
1141
+ return envName || DEFAULT_HARNESS_PROVIDER;
1142
+ }
878
1143
  async function buildProvider(config) {
879
- if (!SUPPORTED_PROVIDERS.has(config.provider)) {
1144
+ const provider = resolveProviderName(config.provider);
1145
+ if (!SUPPORTED_PROVIDERS.has(provider)) {
880
1146
  throw new Error(
881
- `Unknown harness provider: "${config.provider}". Supported: ${[...SUPPORTED_PROVIDERS].sort().join(", ")}`
1147
+ `Unknown harness provider: "${provider}". Supported: ${[...SUPPORTED_PROVIDERS].sort().join(", ")}`
882
1148
  );
883
1149
  }
884
- if (config.provider === "claude-code") {
1150
+ if (provider === "aforge") {
1151
+ const { AforgeProvider: AforgeProvider2 } = await Promise.resolve().then(() => (init_aforge(), aforge_exports));
1152
+ return new AforgeProvider2(config.aforgeBin ?? "aforge");
1153
+ }
1154
+ if (provider === "claude-code") {
885
1155
  const { ClaudeCodeProvider: ClaudeCodeProvider2 } = await Promise.resolve().then(() => (init_claude(), claude_exports));
886
1156
  return new ClaudeCodeProvider2();
887
1157
  }
888
- if (config.provider === "codex") {
1158
+ if (provider === "codex") {
889
1159
  const { CodexProvider: CodexProvider2 } = await Promise.resolve().then(() => (init_codex(), codex_exports));
890
1160
  return new CodexProvider2(config.codexBin ?? "codex");
891
1161
  }
892
- if (config.provider === "gemini") {
1162
+ if (provider === "gemini") {
893
1163
  const { GeminiProvider: GeminiProvider2 } = await Promise.resolve().then(() => (init_gemini(), gemini_exports));
894
1164
  return new GeminiProvider2(config.geminiBin ?? "gemini");
895
1165
  }
896
- if (config.provider === "opencode") {
1166
+ if (provider === "opencode") {
897
1167
  const { OpenCodeProvider: OpenCodeProvider2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
898
1168
  return new OpenCodeProvider2(config.opencodeBin ?? "opencode");
899
1169
  }
900
- throw new Error(`Provider "${config.provider}" is not yet implemented.`);
1170
+ throw new Error(`Provider "${provider}" is not yet implemented.`);
901
1171
  }
902
- var SUPPORTED_PROVIDERS;
1172
+ var SUPPORTED_PROVIDERS, DEFAULT_HARNESS_PROVIDER, HARNESS_PROVIDER_ENV_VAR;
903
1173
  var init_factory = __esm({
904
1174
  "src/harness/providers/factory.ts"() {
905
- SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini", "opencode"]);
1175
+ SUPPORTED_PROVIDERS = /* @__PURE__ */ new Set(["aforge", "claude-code", "codex", "gemini", "opencode"]);
1176
+ DEFAULT_HARNESS_PROVIDER = "aforge";
1177
+ HARNESS_PROVIDER_ENV_VAR = "AGENTFIELD_HARNESS_PROVIDER";
906
1178
  }
907
1179
  });
908
1180
 
@@ -945,22 +1217,28 @@ var init_runner = __esm({
945
1217
  async run(prompt, options = {}) {
946
1218
  const { schema, ...rest } = options;
947
1219
  const resolved = this.resolveOptions(this.config, rest);
948
- if (!resolved.provider) {
949
- throw new Error("No harness provider specified. Set 'provider' in HarnessConfig or pass it to .harness() call.");
950
- }
951
- const cwd = resolved.cwd ?? ".";
1220
+ resolved.provider = resolveProviderName(resolved.provider);
952
1221
  const provider = await this.buildProvider(resolved.provider, resolved);
953
- const effectivePrompt = schema === void 0 ? prompt : `${prompt}${buildPromptSuffix(schema, cwd)}`;
1222
+ const cwd = resolved.cwd ?? ".";
1223
+ const outputRoot = resolved.projectDir ?? cwd;
1224
+ let outputDir;
1225
+ if (schema !== void 0) {
1226
+ fs.mkdirSync(outputRoot, { recursive: true });
1227
+ outputDir = fs.mkdtempSync(path3__default.join(outputRoot, ".agentfield-out-"));
1228
+ }
1229
+ const effectivePrompt = schema === void 0 ? prompt : `${prompt}${buildPromptSuffix(schema, outputDir)}`;
954
1230
  const startTime = Date.now();
955
1231
  try {
956
1232
  const raw = await this.executeWithRetry(provider, effectivePrompt, resolved);
957
1233
  if (schema !== void 0) {
958
- return this.handleSchemaOutput(raw, schema, cwd, startTime);
1234
+ return this.handleSchemaOutput(raw, schema, outputDir, startTime);
959
1235
  }
960
1236
  return createHarnessResult({
961
1237
  result: raw.result,
962
1238
  isError: raw.isError,
963
1239
  errorMessage: raw.errorMessage,
1240
+ failureType: raw.failureType,
1241
+ returnCode: raw.returnCode,
964
1242
  costUsd: raw.metrics.totalCostUsd,
965
1243
  numTurns: raw.metrics.numTurns,
966
1244
  durationMs: Date.now() - startTime,
@@ -970,7 +1248,8 @@ var init_runner = __esm({
970
1248
  });
971
1249
  } finally {
972
1250
  if (schema !== void 0) {
973
- cleanupTempFiles(cwd);
1251
+ cleanupTempFiles(outputDir);
1252
+ fs.rmSync(outputDir, { recursive: true, force: true });
974
1253
  }
975
1254
  }
976
1255
  }
@@ -992,6 +1271,8 @@ var init_runner = __esm({
992
1271
  "systemPrompt",
993
1272
  "env",
994
1273
  "cwd",
1274
+ "projectDir",
1275
+ "aforgeBin",
995
1276
  "codexBin",
996
1277
  "geminiBin",
997
1278
  "opencodeBin"
@@ -1056,6 +1337,8 @@ var init_runner = __esm({
1056
1337
  result: raw.result,
1057
1338
  parsed,
1058
1339
  isError: false,
1340
+ failureType: raw.failureType,
1341
+ returnCode: raw.returnCode,
1059
1342
  costUsd: raw.metrics.totalCostUsd,
1060
1343
  numTurns: raw.metrics.numTurns,
1061
1344
  durationMs: Date.now() - startTime,
@@ -1068,6 +1351,8 @@ var init_runner = __esm({
1068
1351
  result: raw.result,
1069
1352
  isError: true,
1070
1353
  errorMessage: "Schema validation failed after parse and cosmetic repair attempts.",
1354
+ failureType: "schema",
1355
+ returnCode: raw.returnCode,
1071
1356
  costUsd: raw.metrics.totalCostUsd,
1072
1357
  numTurns: raw.metrics.numTurns,
1073
1358
  durationMs: Date.now() - startTime,
@@ -5849,22 +6134,22 @@ var Agent = class {
5849
6134
  },
5850
6135
  message: { error: "rate_limit_exceeded", message: "Too many authentication attempts. Try again later." },
5851
6136
  skip: (req) => {
5852
- const path3 = req.path;
5853
- if (!path3.startsWith("/reasoners/") && !path3.startsWith("/skills/") && !path3.startsWith("/execute") && !path3.startsWith("/api/v1/reasoners/") && !path3.startsWith("/api/v1/skills/")) {
6137
+ const path4 = req.path;
6138
+ if (!path4.startsWith("/reasoners/") && !path4.startsWith("/skills/") && !path4.startsWith("/execute") && !path4.startsWith("/api/v1/reasoners/") && !path4.startsWith("/api/v1/skills/")) {
5854
6139
  return true;
5855
6140
  }
5856
- const parts = path3.replace(/^\/+/, "").split("/");
6141
+ const parts = path4.replace(/^\/+/, "").split("/");
5857
6142
  const funcName = parts[parts.length - 1] ?? "";
5858
6143
  return realtimeFunctions.has(funcName);
5859
6144
  }
5860
6145
  });
5861
6146
  this.app.use(authRateLimiter);
5862
6147
  this.app.use(async (req, res, next) => {
5863
- const path3 = req.path;
5864
- if (!path3.startsWith("/reasoners/") && !path3.startsWith("/skills/") && !path3.startsWith("/execute") && !path3.startsWith("/api/v1/reasoners/") && !path3.startsWith("/api/v1/skills/")) {
6148
+ const path4 = req.path;
6149
+ if (!path4.startsWith("/reasoners/") && !path4.startsWith("/skills/") && !path4.startsWith("/execute") && !path4.startsWith("/api/v1/reasoners/") && !path4.startsWith("/api/v1/skills/")) {
5865
6150
  return next();
5866
6151
  }
5867
- const parts = path3.replace(/^\/+/, "").split("/");
6152
+ const parts = path4.replace(/^\/+/, "").split("/");
5868
6153
  const funcName = parts[parts.length - 1] ?? "";
5869
6154
  if (realtimeFunctions.has(funcName)) {
5870
6155
  return next();
@@ -6064,9 +6349,9 @@ var Agent = class {
6064
6349
  return handler(req, res);
6065
6350
  }
6066
6351
  async handleServerlessEvent(event) {
6067
- const path3 = event?.path ?? event?.rawPath ?? "";
6352
+ const path4 = event?.path ?? event?.rawPath ?? "";
6068
6353
  const action = event?.action ?? "";
6069
- if (path3 === "/discover" || action === "discover") {
6354
+ if (path4 === "/discover" || action === "discover") {
6070
6355
  return {
6071
6356
  statusCode: 200,
6072
6357
  headers: { "content-type": "application/json" },
@@ -6075,7 +6360,7 @@ var Agent = class {
6075
6360
  }
6076
6361
  const body = this.normalizeEventBody(event);
6077
6362
  const invocation = this.extractInvocationDetails({
6078
- path: path3,
6363
+ path: path4,
6079
6364
  query: event?.queryStringParameters,
6080
6365
  body,
6081
6366
  reasoner: event?.reasoner,
@@ -6154,9 +6439,9 @@ var Agent = class {
6154
6439
  const input = this.normalizeInputPayload(params.body);
6155
6440
  return { name: name ?? void 0, targetType: typeValue, input };
6156
6441
  }
6157
- parsePathTarget(path3) {
6158
- if (!path3) return {};
6159
- const normalized = path3.split("?")[0];
6442
+ parsePathTarget(path4) {
6443
+ if (!path4) return {};
6444
+ const normalized = path4.split("?")[0];
6160
6445
  const reasonerMatch = normalized.match(/\/reasoners\/([^/]+)/);
6161
6446
  if (reasonerMatch?.[1]) {
6162
6447
  return { name: reasonerMatch[1], targetType: "reasoner" };
@@ -7326,7 +7611,7 @@ var MultimodalResponse = class {
7326
7611
  */
7327
7612
  async saveImage(image, imagePath) {
7328
7613
  const bytes = await this.getImageBytes(image);
7329
- await promises.mkdir(path2.dirname(imagePath), { recursive: true });
7614
+ await promises.mkdir(path3.dirname(imagePath), { recursive: true });
7330
7615
  await promises.writeFile(imagePath, bytes);
7331
7616
  }
7332
7617
  /**
@@ -7334,7 +7619,7 @@ var MultimodalResponse = class {
7334
7619
  */
7335
7620
  async saveAudio(audio, audioPath) {
7336
7621
  const bytes = await this.getAudioBytes(audio);
7337
- await promises.mkdir(path2.dirname(audioPath), { recursive: true });
7622
+ await promises.mkdir(path3.dirname(audioPath), { recursive: true });
7338
7623
  await promises.writeFile(audioPath, bytes);
7339
7624
  }
7340
7625
  /**
@@ -7342,7 +7627,7 @@ var MultimodalResponse = class {
7342
7627
  */
7343
7628
  async saveFile(file, filePath) {
7344
7629
  const bytes = await this.getFileBytes(file);
7345
- await promises.mkdir(path2.dirname(filePath), { recursive: true });
7630
+ await promises.mkdir(path3.dirname(filePath), { recursive: true });
7346
7631
  await promises.writeFile(filePath, bytes);
7347
7632
  }
7348
7633
  /**
@@ -7353,7 +7638,7 @@ var MultimodalResponse = class {
7353
7638
  const savedFiles = {};
7354
7639
  await promises.mkdir(outputDir, { recursive: true });
7355
7640
  if (this._audio) {
7356
- const audioPath = path2.join(outputDir, `${prefix}_audio.${this._audio.format}`);
7641
+ const audioPath = path3.join(outputDir, `${prefix}_audio.${this._audio.format}`);
7357
7642
  await this.saveAudio(this._audio, audioPath);
7358
7643
  savedFiles["audio"] = audioPath;
7359
7644
  }
@@ -7361,22 +7646,22 @@ var MultimodalResponse = class {
7361
7646
  const image = this._images[i];
7362
7647
  let ext = "png";
7363
7648
  if (image.url) {
7364
- const urlExt = path2.extname(image.url).slice(1);
7649
+ const urlExt = path3.extname(image.url).slice(1);
7365
7650
  if (urlExt) ext = urlExt;
7366
7651
  }
7367
- const imagePath = path2.join(outputDir, `${prefix}_image_${i}.${ext}`);
7652
+ const imagePath = path3.join(outputDir, `${prefix}_image_${i}.${ext}`);
7368
7653
  await this.saveImage(image, imagePath);
7369
7654
  savedFiles[`image_${i}`] = imagePath;
7370
7655
  }
7371
7656
  for (let i = 0; i < this._files.length; i++) {
7372
7657
  const file = this._files[i];
7373
7658
  const filename = file.filename || `${prefix}_file_${i}`;
7374
- const filePath = path2.join(outputDir, filename);
7659
+ const filePath = path3.join(outputDir, filename);
7375
7660
  await this.saveFile(file, filePath);
7376
7661
  savedFiles[`file_${i}`] = filePath;
7377
7662
  }
7378
7663
  if (this._text) {
7379
- const textPath = path2.join(outputDir, `${prefix}_text.txt`);
7664
+ const textPath = path3.join(outputDir, `${prefix}_text.txt`);
7380
7665
  await promises.writeFile(textPath, this._text, "utf-8");
7381
7666
  savedFiles["text"] = textPath;
7382
7667
  }