agent-worker 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -297,6 +297,14 @@ function parseModel(model) {
297
297
  };
298
298
  }
299
299
 
300
+ //#endregion
301
+ //#region src/backends/types.ts
302
+ /**
303
+ * Default idle timeout for CLI backends (10 minutes).
304
+ * Timeout resets on any stdout activity, so this is an inactivity threshold.
305
+ */
306
+ const DEFAULT_IDLE_TIMEOUT = 6e5;
307
+
300
308
  //#endregion
301
309
  //#region src/backends/idle-timeout.ts
302
310
  /**
@@ -337,8 +345,12 @@ async function execWithIdleTimeout(options) {
337
345
  subprocess.stdout?.on("data", (chunk) => {
338
346
  const text = chunk.toString();
339
347
  stdout += text;
340
- if (onStdout) onStdout(text);
341
348
  resetTimer();
349
+ if (onStdout) try {
350
+ onStdout(text);
351
+ } catch (err) {
352
+ console.error("onStdout callback error:", err);
353
+ }
342
354
  });
343
355
  subprocess.stderr?.on("data", (chunk) => {
344
356
  stderr += chunk.toString();
@@ -385,8 +397,12 @@ function execWithIdleTimeoutAbortable(options) {
385
397
  subprocess.stdout?.on("data", (chunk) => {
386
398
  const text = chunk.toString();
387
399
  stdout += text;
388
- if (onStdout) onStdout(text);
389
400
  resetTimer();
401
+ if (onStdout) try {
402
+ onStdout(text);
403
+ } catch (err) {
404
+ console.error("onStdout callback error:", err);
405
+ }
390
406
  });
391
407
  subprocess.stderr?.on("data", (chunk) => {
392
408
  stderr += chunk.toString();
@@ -456,6 +472,10 @@ function formatEvent(event, backendName) {
456
472
  if (event.sessionId) details.push(`session: ${event.sessionId}`);
457
473
  return `${backendName} initialized${details.length > 0 ? ` (${details.join(", ")})` : ""}`;
458
474
  }
475
+ case "tool_call_started": {
476
+ const callIdSuffix = event.callId ? ` [${event.callId.slice(0, 8)}]` : "";
477
+ return `STARTING ${event.name}${callIdSuffix}`;
478
+ }
459
479
  case "tool_call": {
460
480
  const truncated = event.args.length > 100 ? event.args.slice(0, 100) + "..." : event.args;
461
481
  return `CALL ${event.name}(${truncated})`;
@@ -469,6 +489,13 @@ function formatEvent(event, backendName) {
469
489
  if (details.length > 0) parts.push(`(${details.join(", ")})`);
470
490
  return parts.join(" ");
471
491
  }
492
+ case "user_message": return `User: ${event.text.length > 80 ? event.text.slice(0, 80) + "..." : event.text}`;
493
+ case "assistant_message": return `Assistant: ${event.text.length > 80 ? event.text.slice(0, 80) + "..." : event.text}`;
494
+ case "skip": return null;
495
+ case "unknown": {
496
+ const preview = JSON.stringify(event.raw).slice(0, 100);
497
+ return `[DEBUG] ${backendName} unknown event type="${event.type}": ${preview}...`;
498
+ }
472
499
  }
473
500
  }
474
501
  /**
@@ -480,30 +507,36 @@ function formatEvent(event, backendName) {
480
507
  * { type: "result", duration_ms: N, total_cost_usd: N }
481
508
  */
482
509
  const claudeAdapter = (raw) => {
483
- const type = raw.type;
484
- if (type === "system" && raw.subtype === "init") return {
510
+ const event = raw;
511
+ if (event.type === "system" && event.subtype === "init") return {
485
512
  kind: "init",
486
- model: raw.model || void 0,
487
- sessionId: raw.session_id
513
+ model: event.model,
514
+ sessionId: event.session_id
488
515
  };
489
- if (type === "assistant") {
490
- const message = raw.message;
491
- if (!message?.content) return null;
492
- const toolCalls = message.content.filter((c) => c.type === "tool_use");
516
+ if (event.type === "user") {
517
+ const textContent = event.message.content.find((c) => c.type === "text");
518
+ if (textContent && "text" in textContent) return {
519
+ kind: "user_message",
520
+ text: textContent.text
521
+ };
522
+ return { kind: "skip" };
523
+ }
524
+ if (event.type === "assistant") {
525
+ const toolCalls = event.message.content.filter((c) => c.type === "tool_use");
493
526
  if (toolCalls.length > 0) {
494
527
  const tc = toolCalls[0];
495
528
  return {
496
529
  kind: "tool_call",
497
- name: tc.name || "unknown",
530
+ name: tc.name,
498
531
  args: formatToolInput(tc.input)
499
532
  };
500
533
  }
501
- return null;
534
+ return { kind: "skip" };
502
535
  }
503
- if (type === "result") return {
536
+ if (event.type === "result") return {
504
537
  kind: "completed",
505
- durationMs: raw.duration_ms,
506
- costUsd: raw.total_cost_usd
538
+ durationMs: event.duration_ms,
539
+ costUsd: event.total_cost_usd
507
540
  };
508
541
  return null;
509
542
  };
@@ -531,6 +564,51 @@ function extractClaudeResult(stdout) {
531
564
  return { content: stdout.trim() };
532
565
  }
533
566
  /**
567
+ * Adapter for Cursor stream-json format.
568
+ *
569
+ * Events:
570
+ * { type: "system", subtype: "init", model: "..." }
571
+ * { type: "tool_call", subtype: "started", call_id: "...", tool_call: { shellToolCall: {...} } }
572
+ * { type: "tool_call", subtype: "completed", call_id: "..." }
573
+ * { type: "result", duration_ms: N }
574
+ */
575
+ const cursorAdapter = (raw) => {
576
+ const event = raw;
577
+ if (event.type === "system" && event.subtype === "init") return {
578
+ kind: "init",
579
+ model: event.model,
580
+ sessionId: event.session_id
581
+ };
582
+ if (event.type === "user") return {
583
+ kind: "user_message",
584
+ text: event.message.content.map((c) => c.text).join("\n")
585
+ };
586
+ if (event.type === "assistant") return {
587
+ kind: "assistant_message",
588
+ text: event.message.content.map((c) => c.text).join("\n")
589
+ };
590
+ if (event.type === "tool_call") {
591
+ if (event.subtype === "started" && event.tool_call) {
592
+ if (event.tool_call.shellToolCall) return {
593
+ kind: "tool_call_started",
594
+ name: "bash",
595
+ callId: event.call_id
596
+ };
597
+ return {
598
+ kind: "tool_call_started",
599
+ name: "tool",
600
+ callId: event.call_id
601
+ };
602
+ }
603
+ return { kind: "skip" };
604
+ }
605
+ if (event.type === "result") return {
606
+ kind: "completed",
607
+ durationMs: event.duration_ms
608
+ };
609
+ return null;
610
+ };
611
+ /**
534
612
  * Adapter for Codex --json format.
535
613
  *
536
614
  * Events:
@@ -540,34 +618,26 @@ function extractClaudeResult(stdout) {
540
618
  * { type: "turn.completed", usage: { input_tokens, output_tokens } }
541
619
  */
542
620
  const codexAdapter = (raw) => {
543
- const type = raw.type;
544
- if (type === "thread.started") {
545
- const threadId = raw.thread_id;
546
- return {
547
- kind: "init",
548
- sessionId: threadId ? `${threadId.slice(0, 8)}...` : void 0
549
- };
550
- }
551
- if (type === "item.completed") {
552
- const item = raw.item;
553
- if (!item) return null;
554
- if (item.type === "function_call") return {
621
+ const event = raw;
622
+ if (event.type === "thread.started") return {
623
+ kind: "init",
624
+ sessionId: `${event.thread_id.slice(0, 8)}...`
625
+ };
626
+ if (event.type === "item.completed") {
627
+ if (event.item.type === "function_call") return {
555
628
  kind: "tool_call",
556
- name: item.name || "unknown",
557
- args: item.arguments ?? ""
558
- };
559
- return null;
560
- }
561
- if (type === "turn.completed") {
562
- const usage = raw.usage;
563
- return {
564
- kind: "completed",
565
- usage: usage ? {
566
- input: usage.input_tokens ?? 0,
567
- output: usage.output_tokens ?? 0
568
- } : void 0
629
+ name: event.item.name,
630
+ args: event.item.arguments
569
631
  };
632
+ return { kind: "skip" };
570
633
  }
634
+ if (event.type === "turn.completed") return {
635
+ kind: "completed",
636
+ usage: {
637
+ input: event.usage.input_tokens,
638
+ output: event.usage.output_tokens
639
+ }
640
+ };
571
641
  return null;
572
642
  };
573
643
  /**
@@ -589,13 +659,14 @@ function extractCodexResult(stdout) {
589
659
  * Create a line-buffered stream parser.
590
660
  *
591
661
  * Accumulates stdout chunks, parses each line through the given adapter,
592
- * and emits formatted progress messages via debugLog.
662
+ * and emits formatted progress messages via appropriate callback.
593
663
  *
594
- * @param debugLog - Callback for progress messages
664
+ * @param debugLog - Callback for debug messages (kind="debug", only in --debug mode)
595
665
  * @param backendName - Display name (e.g., "Cursor", "Claude", "Codex")
596
666
  * @param adapter - Format-specific adapter to convert raw JSON → StreamEvent
667
+ * @param messageLog - Optional callback for agent output messages (tool calls, assistant messages) (kind="stream", visible in normal mode). If not provided, uses debugLog.
597
668
  */
598
- function createStreamParser(debugLog, backendName, adapter) {
669
+ function createStreamParser(debugLog, backendName, adapter, messageLog) {
599
670
  let lineBuf = "";
600
671
  return (chunk) => {
601
672
  lineBuf += chunk;
@@ -605,11 +676,15 @@ function createStreamParser(debugLog, backendName, adapter) {
605
676
  if (!line.trim()) continue;
606
677
  try {
607
678
  const raw = JSON.parse(line);
608
- if (raw.type === "assistant" || raw.type === "system") debugLog(`[DEBUG] ${backendName} event: ${JSON.stringify(raw).substring(0, 200)}`);
609
- const event = adapter(raw);
679
+ let event = adapter(raw);
680
+ if (!event && raw.type) event = {
681
+ kind: "unknown",
682
+ type: raw.type,
683
+ raw
684
+ };
610
685
  if (event) {
611
686
  const progress = formatEvent(event, backendName);
612
- if (progress) debugLog(progress);
687
+ if (progress) ((event.kind === "tool_call" || event.kind === "tool_call_started" || event.kind === "user_message" || event.kind === "assistant_message") && messageLog ? messageLog : debugLog)(progress);
613
688
  }
614
689
  } catch {}
615
690
  }
@@ -646,7 +721,7 @@ var ClaudeCodeBackend = class {
646
721
  currentAbort;
647
722
  constructor(options = {}) {
648
723
  this.options = {
649
- timeout: 3e5,
724
+ timeout: DEFAULT_IDLE_TIMEOUT,
650
725
  ...options
651
726
  };
652
727
  }
@@ -666,14 +741,14 @@ var ClaudeCodeBackend = class {
666
741
  const cwd = this.options.workspace || this.options.cwd;
667
742
  const debugLog = this.options.debugLog;
668
743
  const outputFormat = this.options.outputFormat ?? "stream-json";
669
- const timeout = this.options.timeout ?? 3e5;
744
+ const timeout = this.options.timeout ?? DEFAULT_IDLE_TIMEOUT;
670
745
  try {
671
746
  const { promise, abort } = execWithIdleTimeoutAbortable({
672
747
  command: "claude",
673
748
  args,
674
749
  cwd,
675
750
  timeout,
676
- onStdout: outputFormat === "stream-json" && debugLog ? createStreamParser(debugLog, "Claude", claudeAdapter) : void 0
751
+ onStdout: outputFormat === "stream-json" && debugLog ? createStreamParser(debugLog, "Claude", claudeAdapter, this.options.messageLog) : void 0
677
752
  });
678
753
  this.currentAbort = abort;
679
754
  const { stdout } = await promise;
@@ -771,7 +846,7 @@ var CodexBackend = class {
771
846
  options;
772
847
  constructor(options = {}) {
773
848
  this.options = {
774
- timeout: 3e5,
849
+ timeout: DEFAULT_IDLE_TIMEOUT,
775
850
  ...options
776
851
  };
777
852
  }
@@ -790,14 +865,14 @@ var CodexBackend = class {
790
865
  const args = this.buildArgs(message);
791
866
  const cwd = this.options.workspace || this.options.cwd;
792
867
  const debugLog = this.options.debugLog;
793
- const timeout = this.options.timeout ?? 3e5;
868
+ const timeout = this.options.timeout ?? DEFAULT_IDLE_TIMEOUT;
794
869
  try {
795
870
  const { stdout } = await execWithIdleTimeout({
796
871
  command: "codex",
797
872
  args,
798
873
  cwd,
799
874
  timeout,
800
- onStdout: debugLog ? createStreamParser(debugLog, "Codex", codexAdapter) : void 0
875
+ onStdout: debugLog ? createStreamParser(debugLog, "Codex", codexAdapter, this.options.messageLog) : void 0
801
876
  });
802
877
  return extractCodexResult(stdout);
803
878
  } catch (error) {
@@ -860,7 +935,7 @@ var CursorBackend = class {
860
935
  resolvedCommand = null;
861
936
  constructor(options = {}) {
862
937
  this.options = {
863
- timeout: 3e5,
938
+ timeout: DEFAULT_IDLE_TIMEOUT,
864
939
  ...options
865
940
  };
866
941
  }
@@ -878,14 +953,15 @@ var CursorBackend = class {
878
953
  const { command, args } = await this.buildCommand(message);
879
954
  const cwd = this.options.workspace || this.options.cwd;
880
955
  const debugLog = this.options.debugLog;
881
- const timeout = this.options.timeout ?? 3e5;
956
+ const messageLog = this.options.messageLog;
957
+ const timeout = this.options.timeout ?? DEFAULT_IDLE_TIMEOUT;
882
958
  try {
883
959
  const { stdout } = await execWithIdleTimeout({
884
960
  command,
885
961
  args,
886
962
  cwd,
887
963
  timeout,
888
- onStdout: debugLog ? createStreamParser(debugLog, "Cursor", claudeAdapter) : void 0
964
+ onStdout: debugLog ? createStreamParser(debugLog, "Cursor", cursorAdapter, messageLog) : void 0
889
965
  });
890
966
  return extractClaudeResult(stdout);
891
967
  } catch (error) {
@@ -1115,4 +1191,4 @@ async function listBackends() {
1115
1191
  }
1116
1192
 
1117
1193
  //#endregion
1118
- export { getModelForBackend as C, createModel as D, SUPPORTED_PROVIDERS as E, createModelAsync as O, SDK_MODEL_ALIASES as S, FRONTIER_MODELS as T, execWithIdleTimeout as _, createMockBackend as a, CODEX_MODEL_MAP as b, CodexBackend as c, codexAdapter as d, createStreamParser as f, IdleTimeoutError as g, formatEvent as h, MockAIBackend as i, getDefaultModel as k, ClaudeCodeBackend as l, extractCodexResult as m, createBackend as n, SdkBackend as o, extractClaudeResult as p, listBackends as r, CursorBackend as s, checkBackends as t, claudeAdapter as u, BACKEND_DEFAULT_MODELS as v, parseModel as w, CURSOR_MODEL_MAP as x, CLAUDE_MODEL_MAP as y };
1194
+ export { getDefaultModel as A, SDK_MODEL_ALIASES as C, SUPPORTED_PROVIDERS as D, FRONTIER_MODELS as E, createModel as O, CURSOR_MODEL_MAP as S, parseModel as T, execWithIdleTimeout as _, createMockBackend as a, CLAUDE_MODEL_MAP as b, CodexBackend as c, codexAdapter as d, createStreamParser as f, IdleTimeoutError as g, formatEvent as h, MockAIBackend as i, createModelAsync as k, ClaudeCodeBackend as l, extractCodexResult as m, createBackend as n, SdkBackend as o, extractClaudeResult as p, listBackends as r, CursorBackend as s, checkBackends as t, claudeAdapter as u, DEFAULT_IDLE_TIMEOUT as v, getModelForBackend as w, CODEX_MODEL_MAP as x, BACKEND_DEFAULT_MODELS as y };
@@ -0,0 +1,3 @@
1
+ import { C as SDK_MODEL_ALIASES, S as CURSOR_MODEL_MAP, _ as execWithIdleTimeout, a as createMockBackend, b as CLAUDE_MODEL_MAP, c as CodexBackend, d as codexAdapter, f as createStreamParser, g as IdleTimeoutError, h as formatEvent, i as MockAIBackend, l as ClaudeCodeBackend, m as extractCodexResult, n as createBackend, o as SdkBackend, p as extractClaudeResult, r as listBackends, s as CursorBackend, t as checkBackends, u as claudeAdapter, v as DEFAULT_IDLE_TIMEOUT, w as getModelForBackend, x as CODEX_MODEL_MAP, y as BACKEND_DEFAULT_MODELS } from "./backends-BOAkfYyL.mjs";
2
+
3
+ export { listBackends };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { T as FRONTIER_MODELS, k as getDefaultModel, n as createBackend } from "../backends-Hclwb_Zp.mjs";
3
- import { a as createSkillsTool, c as createFeedbackTool, l as AgentSession, o as SkillsProvider, s as FEEDBACK_PROMPT, t as SkillImporter } from "../skills-CrCMADND.mjs";
2
+ import { A as getDefaultModel, E as FRONTIER_MODELS, n as createBackend } from "../backends-BOAkfYyL.mjs";
3
+ import { a as createSkillsTool, c as createFeedbackTool, l as AgentSession, o as SkillsProvider, s as FEEDBACK_PROMPT, t as SkillImporter } from "../skills-xNmQZf8e.mjs";
4
4
  import { jsonSchema, tool } from "ai";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
6
6
  import { dirname, isAbsolute, join, relative } from "node:path";
@@ -604,6 +604,7 @@ function calculatePriority(msg) {
604
604
  const KEYS = {
605
605
  channel: "channel.jsonl",
606
606
  inboxState: "_state/inbox.json",
607
+ agentStatus: "_state/agent-status.json",
607
608
  documentPrefix: "documents/",
608
609
  resourcePrefix: "resources/"
609
610
  };
@@ -672,7 +673,7 @@ var ContextProviderImpl = class {
672
673
  if (options?.agent) {
673
674
  const agent = options.agent;
674
675
  entries = entries.filter((e) => {
675
- if (e.kind === "log" || e.kind === "debug") return false;
676
+ if (e.kind === "log" || e.kind === "debug" || e.kind === "stream") return false;
676
677
  if (e.to) return e.to === agent || e.from === agent;
677
678
  return true;
678
679
  });
@@ -718,7 +719,7 @@ var ContextProviderImpl = class {
718
719
  let seenIdx = -1;
719
720
  if (lastSeenId) seenIdx = entries.findIndex((e) => e.id === lastSeenId);
720
721
  return entries.filter((e) => {
721
- if (e.kind === "log" || e.kind === "debug") return false;
722
+ if (e.kind === "log" || e.kind === "debug" || e.kind === "stream") return false;
722
723
  if (e.from === agent) return false;
723
724
  return e.mentions.includes(agent) || e.to === agent;
724
725
  }).map((entry) => {
@@ -797,6 +798,42 @@ var ContextProviderImpl = class {
797
798
  }
798
799
  return null;
799
800
  }
801
+ async loadAgentStatus() {
802
+ const raw = await this.storage.read(KEYS.agentStatus);
803
+ if (!raw) return {};
804
+ try {
805
+ return JSON.parse(raw);
806
+ } catch {
807
+ return {};
808
+ }
809
+ }
810
+ async saveAgentStatus(statuses) {
811
+ await this.storage.write(KEYS.agentStatus, JSON.stringify(statuses, null, 2));
812
+ }
813
+ async setAgentStatus(agent, status) {
814
+ const statuses = await this.loadAgentStatus();
815
+ const existing = statuses[agent] || {
816
+ state: "idle",
817
+ lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
818
+ };
819
+ statuses[agent] = {
820
+ ...existing,
821
+ ...status,
822
+ lastUpdate: (/* @__PURE__ */ new Date()).toISOString()
823
+ };
824
+ if (status.state === "running" && existing.state !== "running") statuses[agent].startedAt = (/* @__PURE__ */ new Date()).toISOString();
825
+ if (status.state === "idle") {
826
+ statuses[agent].startedAt = void 0;
827
+ statuses[agent].task = void 0;
828
+ }
829
+ await this.saveAgentStatus(statuses);
830
+ }
831
+ async getAgentStatus(agent) {
832
+ return (await this.loadAgentStatus())[agent] || null;
833
+ }
834
+ async listAgentStatus() {
835
+ return this.loadAgentStatus();
836
+ }
800
837
  async markRunStart() {
801
838
  this.runStartIndex = (await this.syncChannel()).length;
802
839
  }
@@ -2120,7 +2157,7 @@ Examples:
2120
2157
 
2121
2158
  Note: Workflow name is inferred from YAML 'name' field or filename
2122
2159
  `).action(async (file, options) => {
2123
- const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CzVHUE9I.mjs");
2160
+ const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CoZnnJ3O.mjs");
2124
2161
  const tag = options.tag || DEFAULT_TAG;
2125
2162
  const parsedWorkflow = await parseWorkflowFile(file, { tag });
2126
2163
  const workflowName = parsedWorkflow.name;
@@ -2131,7 +2168,7 @@ Note: Workflow name is inferred from YAML 'name' field or filename
2131
2168
  isCleaningUp = true;
2132
2169
  console.log("\nInterrupted, cleaning up...");
2133
2170
  if (controllers) {
2134
- const { shutdownControllers } = await import("../workflow-CzVHUE9I.mjs");
2171
+ const { shutdownControllers } = await import("../workflow-CoZnnJ3O.mjs");
2135
2172
  const { createSilentLogger } = await import("../logger-C3ekEOzi.mjs");
2136
2173
  await shutdownControllers(controllers, createSilentLogger());
2137
2174
  }
@@ -2201,7 +2238,7 @@ Examples:
2201
2238
 
2202
2239
  Note: Workflow name is inferred from YAML 'name' field or filename
2203
2240
  `).action(async (file, options) => {
2204
- const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CzVHUE9I.mjs");
2241
+ const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CoZnnJ3O.mjs");
2205
2242
  const tag = options.tag || DEFAULT_TAG;
2206
2243
  const parsedWorkflow = await parseWorkflowFile(file, { tag });
2207
2244
  const workflowName = parsedWorkflow.name;
@@ -2396,7 +2433,7 @@ function registerInfoCommands(program) {
2396
2433
  console.log(`\nDefault: ${defaultModel} (when no model specified)`);
2397
2434
  });
2398
2435
  program.command("backends").description("Check available backends (SDK, CLI tools)").action(async () => {
2399
- const { listBackends } = await import("../backends-BN3LvE37.mjs");
2436
+ const { listBackends } = await import("../backends-e6gCxRZ9.mjs");
2400
2437
  const backends = await listBackends();
2401
2438
  console.log("Backend Status:\n");
2402
2439
  for (const backend of backends) {
@@ -2426,7 +2463,7 @@ Examples:
2426
2463
  $ agent-worker doc read @review:pr-123 # Read specific workflow:tag document
2427
2464
  `).action(async (targetInput) => {
2428
2465
  const dir = await resolveDir(targetInput);
2429
- const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
2466
+ const { createFileContextProvider } = await import("../context-dgI2YCGG.mjs");
2430
2467
  const content = await createFileContextProvider(dir, []).readDocument();
2431
2468
  console.log(content || "(empty document)");
2432
2469
  });
@@ -2444,7 +2481,7 @@ Examples:
2444
2481
  process.exit(1);
2445
2482
  }
2446
2483
  const dir = await resolveDir(targetInput);
2447
- const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
2484
+ const { createFileContextProvider } = await import("../context-dgI2YCGG.mjs");
2448
2485
  await createFileContextProvider(dir, []).writeDocument(content);
2449
2486
  console.log("Document written");
2450
2487
  });
@@ -2462,7 +2499,7 @@ Examples:
2462
2499
  process.exit(1);
2463
2500
  }
2464
2501
  const dir = await resolveDir(targetInput);
2465
- const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
2502
+ const { createFileContextProvider } = await import("../context-dgI2YCGG.mjs");
2466
2503
  await createFileContextProvider(dir, []).appendDocument(content);
2467
2504
  console.log("Content appended");
2468
2505
  });
@@ -2544,7 +2581,7 @@ Note: Requires agent to be created with --feedback flag
2544
2581
 
2545
2582
  //#endregion
2546
2583
  //#region package.json
2547
- var version = "0.7.0";
2584
+ var version = "0.9.0";
2548
2585
 
2549
2586
  //#endregion
2550
2587
  //#region src/cli/index.ts
@@ -1,4 +1,4 @@
1
1
  import { _ as shouldUseResource, a as FileStorage, c as CONTEXT_DEFAULTS, d as RESOURCE_PREFIX, f as RESOURCE_SCHEME, g as generateResourceId, h as extractMentions, i as resolveContextDir, l as MENTION_PATTERN, m as createResourceRef, n as createFileContextProvider, o as MemoryStorage, p as calculatePriority, r as getDefaultContextDir, s as ContextProviderImpl, t as FileContextProvider, u as MESSAGE_LENGTH_THRESHOLD } from "./cli/index.mjs";
2
- import { a as createMemoryContextProvider, i as MemoryContextProvider, n as formatProposal, r as formatProposalList, t as createContextMCPServer } from "./mcp-server-D5Pnt0lB.mjs";
2
+ import { a as createMemoryContextProvider, i as MemoryContextProvider, n as formatProposal, r as formatProposalList, t as createContextMCPServer } from "./mcp-server-BQCQxv2v.mjs";
3
3
 
4
4
  export { createFileContextProvider };
package/dist/index.d.mts CHANGED
@@ -94,7 +94,7 @@ interface SessionConfig {
94
94
  approval?: Record<string, ApprovalCheck>;
95
95
  /** Maximum tokens for response (default: 4096) */
96
96
  maxTokens?: number;
97
- /** Maximum tool call steps per turn (default: 10) */
97
+ /** Maximum tool call steps per turn (default: 200) */
98
98
  maxSteps?: number;
99
99
  }
100
100
  /**
@@ -473,8 +473,10 @@ interface ClaudeCodeOptions {
473
473
  timeout?: number;
474
474
  /** MCP config file path (for workflow context) */
475
475
  mcpConfigPath?: string;
476
- /** Debug log function (for workflow diagnostics) */
476
+ /** Debug log function (for tool calls and debug info) */
477
477
  debugLog?: (message: string) => void;
478
+ /** Message log function (for agent messages - user/assistant) */
479
+ messageLog?: (message: string) => void;
478
480
  }
479
481
  declare class ClaudeCodeBackend implements Backend {
480
482
  readonly type: "claude";
@@ -520,8 +522,10 @@ interface CodexOptions {
520
522
  resume?: string;
521
523
  /** Idle timeout in milliseconds — kills process if no output for this duration */
522
524
  timeout?: number;
523
- /** Debug log function (for workflow diagnostics) */
525
+ /** Debug log function (for tool calls and debug info) */
524
526
  debugLog?: (message: string) => void;
527
+ /** Message log function (for agent messages - user/assistant) */
528
+ messageLog?: (message: string) => void;
525
529
  }
526
530
  declare class CodexBackend implements Backend {
527
531
  readonly type: "codex";
@@ -556,8 +560,10 @@ interface CursorOptions {
556
560
  workspace?: string;
557
561
  /** Idle timeout in milliseconds — kills process if no output for this duration */
558
562
  timeout?: number;
559
- /** Debug log function (for workflow diagnostics) */
563
+ /** Debug log function (for tool calls and debug info) */
560
564
  debugLog?: (message: string) => void;
565
+ /** Message log function (for agent messages - user/assistant) */
566
+ messageLog?: (message: string) => void;
561
567
  }
562
568
  declare class CursorBackend implements Backend {
563
569
  readonly type: "cursor";
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { D as createModel, E as SUPPORTED_PROVIDERS, O as createModelAsync, T as FRONTIER_MODELS, a as createMockBackend, c as CodexBackend, i as MockAIBackend, l as ClaudeCodeBackend, n as createBackend, o as SdkBackend, r as listBackends, s as CursorBackend, t as checkBackends } from "./backends-Hclwb_Zp.mjs";
2
- import { a as createSkillsTool, c as createFeedbackTool, i as parseImportSpec, l as AgentSession, n as buildGitUrl, o as SkillsProvider, r as getSpecDisplayName, s as FEEDBACK_PROMPT, t as SkillImporter } from "./skills-CrCMADND.mjs";
1
+ import { D as SUPPORTED_PROVIDERS, E as FRONTIER_MODELS, O as createModel, a as createMockBackend, c as CodexBackend, i as MockAIBackend, k as createModelAsync, l as ClaudeCodeBackend, n as createBackend, o as SdkBackend, r as listBackends, s as CursorBackend, t as checkBackends } from "./backends-BOAkfYyL.mjs";
2
+ import { a as createSkillsTool, c as createFeedbackTool, i as parseImportSpec, l as AgentSession, n as buildGitUrl, o as SkillsProvider, r as getSpecDisplayName, s as FEEDBACK_PROMPT, t as SkillImporter } from "./skills-xNmQZf8e.mjs";
3
3
  import { jsonSchema, tool } from "ai";
4
4
  import { createBashTool } from "bash-tool";
5
5
 
@@ -121,7 +121,7 @@ function formatProposalList(proposals) {
121
121
  * Tool Taxonomy:
122
122
  * - Channel: channel_send, channel_read (public append-only log)
123
123
  * - Team: team_members, team_doc_*, team_proposal_*, team_vote (shared workspace)
124
- * - My: my_inbox, my_inbox_ack (personal agent tools)
124
+ * - My: my_inbox, my_inbox_ack, my_status_set (personal agent tools)
125
125
  * - Resource: resource_create, resource_read (general-purpose reference mechanism)
126
126
  * - Feedback: feedback_submit (agent observations about tools/workflows, opt-in)
127
127
  */
@@ -152,7 +152,7 @@ function formatInbox(messages) {
152
152
  * - Team: team_members, team_doc_read, team_doc_write, team_doc_append,
153
153
  * team_doc_list, team_doc_create, team_proposal_create, team_vote,
154
154
  * team_proposal_status, team_proposal_cancel
155
- * - My: my_inbox, my_inbox_ack
155
+ * - My: my_inbox, my_inbox_ack, my_status_set
156
156
  * - Resource: resource_create, resource_read
157
157
  */
158
158
  function createContextMCPServer(options) {
@@ -276,20 +276,44 @@ function createContextMCPServer(options) {
276
276
  })
277
277
  }] };
278
278
  });
279
- server.tool("team_members", "List all agents in this workflow. Use to discover who you can @mention.", {}, async (_args, extra) => {
279
+ server.tool("my_status_set", "Update your status and current task. Call when starting or completing work.", {
280
+ task: z.string().optional().describe("Current task description (what you're working on)"),
281
+ state: z.enum(["idle", "running"]).optional().describe("Agent state (running = working, idle = available)"),
282
+ metadata: z.record(z.unknown()).optional().describe("Additional metadata (e.g., PR number, file path)")
283
+ }, async (args, extra) => {
284
+ const agent = getAgentId(extra) || "anonymous";
285
+ logTool("my_status_set", agent, args);
286
+ const status = {};
287
+ if (args.task !== void 0) status.task = args.task;
288
+ if (args.state !== void 0) status.state = args.state;
289
+ if (args.metadata !== void 0) status.metadata = args.metadata;
290
+ await provider.setAgentStatus(agent, status);
291
+ return { content: [{
292
+ type: "text",
293
+ text: JSON.stringify({
294
+ status: "updated",
295
+ agent,
296
+ ...status
297
+ })
298
+ }] };
299
+ });
300
+ server.tool("team_members", "List all agents in this workflow. Use to discover who you can @mention. Optionally includes agent status (state, current task).", { includeStatus: z.boolean().optional().describe("Include agent status information") }, async (args, extra) => {
280
301
  const currentAgent = getAgentId(extra) || "anonymous";
302
+ const includeStatus = args.includeStatus ?? false;
281
303
  const agents = validAgents.map((name) => ({
282
304
  name,
283
305
  mention: `@${name}`,
284
306
  isYou: name === currentAgent
285
307
  }));
308
+ const result = {
309
+ agents,
310
+ count: agents.length,
311
+ hint: "Use @agent in channel_send to mention other agents"
312
+ };
313
+ if (includeStatus) result.status = await provider.listAgentStatus();
286
314
  return { content: [{
287
315
  type: "text",
288
- text: JSON.stringify({
289
- agents,
290
- count: agents.length,
291
- hint: "Use @agent in channel_send to mention other agents"
292
- })
316
+ text: JSON.stringify(result)
293
317
  }] };
294
318
  });
295
319
  server.tool("team_doc_read", "Read a shared team document.", { file: z.string().optional().describe("Document file path (default: notes.md)") }, async ({ file }, extra) => {
@@ -1,4 +1,4 @@
1
- import { O as createModelAsync } from "./backends-Hclwb_Zp.mjs";
1
+ import { k as createModelAsync } from "./backends-BOAkfYyL.mjs";
2
2
  import { ToolLoopAgent, jsonSchema, stepCountIs, tool } from "ai";
3
3
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
4
  import { join, normalize } from "node:path";
@@ -70,7 +70,7 @@ var AgentSession = class {
70
70
  this.tools = config.tools ? { ...config.tools } : {};
71
71
  this.approval = config.approval ? { ...config.approval } : {};
72
72
  this.maxTokens = config.maxTokens ?? 4096;
73
- this.maxSteps = config.maxSteps ?? 10;
73
+ this.maxSteps = config.maxSteps ?? 200;
74
74
  this.backend = config.backend ?? null;
75
75
  }
76
76
  /**
@@ -238,6 +238,7 @@ var AgentSession = class {
238
238
  this.totalUsage.input += usage.input;
239
239
  this.totalUsage.output += usage.output;
240
240
  this.totalUsage.total += usage.total;
241
+ if (this.maxSteps > 0 && stepNumber >= this.maxSteps && allToolCalls.length > 0) console.warn(`⚠️ Agent reached maxSteps limit (${this.maxSteps}) but wanted to continue. Consider increasing maxSteps or removing the limit.`);
241
242
  const currentPending = this.pendingApprovals.filter((p) => p.status === "pending");
242
243
  return {
243
244
  content: result.text,
@@ -1,6 +1,6 @@
1
- import { O as createModelAsync, a as createMockBackend, n as createBackend, w as parseModel } from "./backends-Hclwb_Zp.mjs";
1
+ import { T as parseModel, a as createMockBackend, k as createModelAsync, n as createBackend } from "./backends-BOAkfYyL.mjs";
2
2
  import { c as CONTEXT_DEFAULTS, i as resolveContextDir, n as createFileContextProvider, t as FileContextProvider } from "./cli/index.mjs";
3
- import { a as createMemoryContextProvider, t as createContextMCPServer } from "./mcp-server-D5Pnt0lB.mjs";
3
+ import { a as createMemoryContextProvider, t as createContextMCPServer } from "./mcp-server-BQCQxv2v.mjs";
4
4
  import { createChannelLogger, createSilentLogger } from "./logger-C3ekEOzi.mjs";
5
5
  import { generateText, jsonSchema, stepCountIs, tool } from "ai";
6
6
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
@@ -493,12 +493,13 @@ function buildAgentPrompt(ctx) {
493
493
  sections.push("- **channel_read**: Read recent channel messages (DMs and logs are auto-filtered).");
494
494
  sections.push("");
495
495
  sections.push("### Team Tools");
496
- sections.push("- **team_members**: List all agents you can @mention.");
496
+ sections.push("- **team_members**: List all agents you can @mention. Pass includeStatus=true to see their current state and tasks.");
497
497
  sections.push("- **team_doc_read/write/append/list/create**: Shared team documents.");
498
498
  sections.push("");
499
499
  sections.push("### Personal Tools");
500
500
  sections.push("- **my_inbox**: Check your unread messages.");
501
- sections.push("- **my_inbox_ack**: Acknowledge messages after processing (pass the latest timestamp).");
501
+ sections.push("- **my_inbox_ack**: Acknowledge messages after processing (pass the latest message ID).");
502
+ sections.push("- **my_status_set**: Update your status. Call when starting work (state='running', task='...') or when done (state='idle').");
502
503
  sections.push("");
503
504
  sections.push("### Proposal & Voting Tools");
504
505
  sections.push("- **team_proposal_create**: Create a proposal for team voting (types: election, decision, approval, assignment).");
@@ -809,7 +810,7 @@ async function runSdkAgent(ctx, debugLog) {
809
810
  system: ctx.agent.resolvedSystemPrompt,
810
811
  prompt,
811
812
  maxOutputTokens: ctx.agent.max_tokens ?? 8192,
812
- stopWhen: stepCountIs(ctx.agent.max_steps ?? 30),
813
+ stopWhen: stepCountIs(ctx.agent.max_steps ?? 200),
813
814
  onStepFinish: (step) => {
814
815
  _stepNum++;
815
816
  if (step.toolCalls?.length) {
@@ -827,6 +828,12 @@ async function runSdkAgent(ctx, debugLog) {
827
828
  }
828
829
  });
829
830
  const totalToolCalls = result.steps.reduce((n, s) => n + s.toolCalls.length, 0);
831
+ const lastStep = result.steps[result.steps.length - 1];
832
+ if (ctx.agent.max_steps && result.steps.length >= ctx.agent.max_steps && (lastStep?.toolCalls?.length ?? 0) > 0) {
833
+ const warning = `⚠️ Agent reached max_steps limit (${ctx.agent.max_steps}) but wanted to continue. Consider increasing max_steps or removing the limit.`;
834
+ log(warning);
835
+ await ctx.provider.appendChannel(ctx.name, warning, { kind: "log" }).catch(() => {});
836
+ }
830
837
  await mcp.close();
831
838
  return {
832
839
  success: true,
@@ -895,6 +902,7 @@ function createAgentController(config) {
895
902
  const inbox = await contextProvider.getInbox(name);
896
903
  if (inbox.length === 0) {
897
904
  state = "idle";
905
+ await contextProvider.setAgentStatus(name, { state: "idle" });
898
906
  continue;
899
907
  }
900
908
  const senders = inbox.map((m) => m.entry.from);
@@ -910,6 +918,7 @@ function createAgentController(config) {
910
918
  while (attempt < retryConfig.maxAttempts && shouldContinue(state)) {
911
919
  attempt++;
912
920
  state = "running";
921
+ await contextProvider.setAgentStatus(name, { state: "running" });
913
922
  infoLog(`Running (attempt ${attempt}/${retryConfig.maxAttempts})`);
914
923
  lastResult = await runAgent(backend, {
915
924
  name,
@@ -931,6 +940,7 @@ function createAgentController(config) {
931
940
  infoLog(`DONE ${lastResult.steps ? `${lastResult.steps} steps, ${lastResult.toolCalls} tool calls, ${lastResult.duration}ms` : `${lastResult.duration}ms`}`);
932
941
  if (lastResult.content) await contextProvider.appendChannel(name, lastResult.content);
933
942
  await contextProvider.ackInbox(name, latestId);
943
+ await contextProvider.setAgentStatus(name, { state: "idle" });
934
944
  break;
935
945
  }
936
946
  errorLog(`ERROR ${lastResult.error}`);
@@ -946,6 +956,7 @@ function createAgentController(config) {
946
956
  }
947
957
  if (lastResult && onRunComplete) onRunComplete(lastResult);
948
958
  state = "idle";
959
+ await contextProvider.setAgentStatus(name, { state: "idle" });
949
960
  }
950
961
  }
951
962
  return {
@@ -958,15 +969,18 @@ function createAgentController(config) {
958
969
  async start() {
959
970
  if (state !== "stopped") throw new Error(`Controller ${name} is already running`);
960
971
  state = "idle";
972
+ await contextProvider.setAgentStatus(name, { state: "idle" });
961
973
  infoLog(`Starting`);
962
974
  runLoop().catch((error) => {
963
975
  errorLog(`ERROR ${error instanceof Error ? error.message : String(error)}`);
964
976
  state = "stopped";
977
+ contextProvider.setAgentStatus(name, { state: "stopped" }).catch(() => {});
965
978
  });
966
979
  },
967
980
  async stop() {
968
981
  log(`Stopping`);
969
982
  state = "stopped";
983
+ await contextProvider.setAgentStatus(name, { state: "stopped" });
970
984
  if (backend.abort) backend.abort();
971
985
  if (pollTimeout) {
972
986
  clearTimeout(pollTimeout);
@@ -1011,10 +1025,11 @@ async function runAgent(backend, ctx, log, infoLog) {
1011
1025
  }
1012
1026
  const prompt = buildAgentPrompt(ctx);
1013
1027
  info(`Prompt (${prompt.length} chars) → ${backend.type} backend`);
1014
- await backend.send(prompt, { system: ctx.agent.resolvedSystemPrompt });
1028
+ const response = await backend.send(prompt, { system: ctx.agent.resolvedSystemPrompt });
1015
1029
  return {
1016
1030
  success: true,
1017
- duration: Date.now() - startTime
1031
+ duration: Date.now() - startTime,
1032
+ content: response.content
1018
1033
  };
1019
1034
  } catch (error) {
1020
1035
  return {
@@ -1053,6 +1068,7 @@ function getBackendByType(backendType, options) {
1053
1068
  const backendOptions = {};
1054
1069
  if (options?.timeout) backendOptions.timeout = options.timeout;
1055
1070
  if (options?.debugLog) backendOptions.debugLog = options.debugLog;
1071
+ if (options?.messageLog) backendOptions.messageLog = options.messageLog;
1056
1072
  return createBackend({
1057
1073
  type: backendType,
1058
1074
  model: options?.model,
@@ -1561,14 +1577,21 @@ async function runWorkflowWithControllers(config) {
1561
1577
  const backendDebugLog = (msg) => {
1562
1578
  agentLogger.debug(msg);
1563
1579
  };
1580
+ const backendMessageLog = (msg) => {
1581
+ runtime.contextProvider.appendChannel(agentName, msg, { kind: "stream" }).catch(() => {});
1582
+ };
1564
1583
  let backend;
1565
1584
  if (createBackend) backend = createBackend(agentName, agentDef);
1566
1585
  else if (agentDef.backend) backend = getBackendByType(agentDef.backend, {
1567
1586
  model: agentDef.model,
1568
1587
  debugLog: backendDebugLog,
1588
+ messageLog: backendMessageLog,
1569
1589
  timeout: agentDef.timeout
1570
1590
  });
1571
- else if (agentDef.model) backend = getBackendForModel(agentDef.model, { debugLog: backendDebugLog });
1591
+ else if (agentDef.model) backend = getBackendForModel(agentDef.model, {
1592
+ debugLog: backendDebugLog,
1593
+ messageLog: backendMessageLog
1594
+ });
1572
1595
  else throw new Error(`Agent "${agentName}" requires either a backend or model field`);
1573
1596
  logger.debug(`Using backend: ${backend.type} for ${agentName}`);
1574
1597
  const workspaceDir = join(runtime.contextDir, "workspaces", agentName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-worker",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "SDK and CLI for creating and testing agent workers with Vercel AI SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -1,3 +0,0 @@
1
- import { C as getModelForBackend, S as SDK_MODEL_ALIASES, _ as execWithIdleTimeout, a as createMockBackend, b as CODEX_MODEL_MAP, c as CodexBackend, d as codexAdapter, f as createStreamParser, g as IdleTimeoutError, h as formatEvent, i as MockAIBackend, l as ClaudeCodeBackend, m as extractCodexResult, n as createBackend, o as SdkBackend, p as extractClaudeResult, r as listBackends, s as CursorBackend, t as checkBackends, u as claudeAdapter, v as BACKEND_DEFAULT_MODELS, x as CURSOR_MODEL_MAP, y as CLAUDE_MODEL_MAP } from "./backends-Hclwb_Zp.mjs";
2
-
3
- export { listBackends };