agent-worker 0.5.0 → 0.6.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.
@@ -359,6 +359,70 @@ async function execWithIdleTimeout(options) {
359
359
  }
360
360
  }
361
361
  /**
362
+ * Execute a command with idle timeout and return abort controller
363
+ * This version returns both the promise and an abort function for external control
364
+ */
365
+ function execWithIdleTimeoutAbortable(options) {
366
+ const { command, args, cwd, onStdout } = options;
367
+ const timeout = Math.max(options.timeout, MIN_TIMEOUT_MS);
368
+ let idleTimedOut = false;
369
+ let timer;
370
+ let stdout = "";
371
+ let stderr = "";
372
+ let isAborted = false;
373
+ const subprocess = execa(command, args, {
374
+ cwd,
375
+ stdin: "ignore",
376
+ buffer: false
377
+ });
378
+ const resetTimer = () => {
379
+ clearTimeout(timer);
380
+ timer = setTimeout(() => {
381
+ idleTimedOut = true;
382
+ subprocess.kill();
383
+ }, timeout);
384
+ };
385
+ subprocess.stdout?.on("data", (chunk) => {
386
+ const text = chunk.toString();
387
+ stdout += text;
388
+ if (onStdout) onStdout(text);
389
+ resetTimer();
390
+ });
391
+ subprocess.stderr?.on("data", (chunk) => {
392
+ stderr += chunk.toString();
393
+ resetTimer();
394
+ });
395
+ resetTimer();
396
+ const abort = () => {
397
+ if (!isAborted) {
398
+ isAborted = true;
399
+ clearTimeout(timer);
400
+ subprocess.kill("SIGTERM");
401
+ setTimeout(() => {
402
+ if (!subprocess.killed) subprocess.kill("SIGKILL");
403
+ }, 1e3);
404
+ }
405
+ };
406
+ return {
407
+ promise: (async () => {
408
+ try {
409
+ await subprocess;
410
+ clearTimeout(timer);
411
+ return {
412
+ stdout: stdout.trimEnd(),
413
+ stderr: stderr.trimEnd()
414
+ };
415
+ } catch (error) {
416
+ clearTimeout(timer);
417
+ if (isAborted) throw new Error("Process aborted by user");
418
+ if (idleTimedOut) throw new IdleTimeoutError(timeout, stdout, stderr);
419
+ throw error;
420
+ }
421
+ })(),
422
+ abort
423
+ };
424
+ }
425
+ /**
362
426
  * Error thrown when a process is killed due to idle timeout
363
427
  */
364
428
  var IdleTimeoutError = class extends Error {
@@ -577,6 +641,7 @@ function formatToolInput(input) {
577
641
  var ClaudeCodeBackend = class {
578
642
  type = "claude";
579
643
  options;
644
+ currentAbort;
580
645
  constructor(options = {}) {
581
646
  this.options = {
582
647
  timeout: 3e5,
@@ -601,13 +666,16 @@ var ClaudeCodeBackend = class {
601
666
  const outputFormat = this.options.outputFormat ?? "stream-json";
602
667
  const timeout = this.options.timeout ?? 3e5;
603
668
  try {
604
- const { stdout } = await execWithIdleTimeout({
669
+ const { promise, abort } = execWithIdleTimeoutAbortable({
605
670
  command: "claude",
606
671
  args,
607
672
  cwd,
608
673
  timeout,
609
674
  onStdout: outputFormat === "stream-json" && debugLog ? createStreamParser(debugLog, "Claude", claudeAdapter) : void 0
610
675
  });
676
+ this.currentAbort = abort;
677
+ const { stdout } = await promise;
678
+ this.currentAbort = void 0;
611
679
  if (outputFormat === "stream-json") return extractClaudeResult(stdout);
612
680
  if (outputFormat === "json") try {
613
681
  const parsed = JSON.parse(stdout);
@@ -621,6 +689,7 @@ var ClaudeCodeBackend = class {
621
689
  }
622
690
  return { content: stdout.trim() };
623
691
  } catch (error) {
692
+ this.currentAbort = void 0;
624
693
  if (error instanceof IdleTimeoutError) throw new Error(`claude timed out after ${timeout}ms of inactivity`);
625
694
  if (error && typeof error === "object" && "exitCode" in error) {
626
695
  const execError = error;
@@ -660,6 +729,7 @@ var ClaudeCodeBackend = class {
660
729
  if (this.options.allowedTools?.length) args.push("--allowed-tools", this.options.allowedTools.join(","));
661
730
  const outputFormat = this.options.outputFormat ?? "stream-json";
662
731
  args.push("--output-format", outputFormat);
732
+ if (outputFormat === "stream-json") args.push("--verbose");
663
733
  if (this.options.continue) args.push("--continue");
664
734
  if (this.options.resume) args.push("--resume", this.options.resume);
665
735
  if (this.options.mcpConfigPath) args.push("--mcp-config", this.options.mcpConfigPath);
@@ -671,6 +741,15 @@ var ClaudeCodeBackend = class {
671
741
  setMcpConfigPath(path) {
672
742
  this.options.mcpConfigPath = path;
673
743
  }
744
+ /**
745
+ * Abort any running claude process
746
+ */
747
+ abort() {
748
+ if (this.currentAbort) {
749
+ this.currentAbort();
750
+ this.currentAbort = void 0;
751
+ }
752
+ }
674
753
  };
675
754
 
676
755
  //#endregion
@@ -1,3 +1,3 @@
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-CEYiMUgC.mjs";
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-BJyk6zvs.mjs";
2
2
 
3
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-CEYiMUgC.mjs";
3
- import { a as createSkillsTool, c as createFeedbackTool, l as AgentSession, o as SkillsProvider, s as FEEDBACK_PROMPT, t as SkillImporter } from "../skills-iya7NbH7.mjs";
2
+ import { T as FRONTIER_MODELS, k as getDefaultModel, n as createBackend } from "../backends-BJyk6zvs.mjs";
3
+ import { a as createSkillsTool, c as createFeedbackTool, l as AgentSession, o as SkillsProvider, s as FEEDBACK_PROMPT, t as SkillImporter } from "../skills-CuAfAkHU.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";
@@ -541,6 +541,8 @@ async function handleRequest(getState, req, resetIdleTimer, gracefulShutdown, re
541
541
  const RESOURCE_PREFIX = "res_";
542
542
  /** Resource URI scheme */
543
543
  const RESOURCE_SCHEME = "resource:";
544
+ /** Message length threshold for channel messages - content longer than this should use resources or documents */
545
+ const MESSAGE_LENGTH_THRESHOLD = 1200;
544
546
  /**
545
547
  * Generate a unique resource ID
546
548
  */
@@ -554,6 +556,12 @@ function generateResourceId() {
554
556
  function createResourceRef(id) {
555
557
  return `${RESOURCE_SCHEME}${id}`;
556
558
  }
559
+ /**
560
+ * Check if content should be stored as a resource instead of inline
561
+ */
562
+ function shouldUseResource(content) {
563
+ return content.length > MESSAGE_LENGTH_THRESHOLD;
564
+ }
557
565
  /** Default context configuration values */
558
566
  const CONTEXT_DEFAULTS = {
559
567
  dir: "~/.agent-worker/workflows/${{ workflow.name }}/${{ workflow.tag }}/",
@@ -679,6 +687,23 @@ var ContextProviderImpl = class {
679
687
  cursor: entries.length
680
688
  };
681
689
  }
690
+ /**
691
+ * Smart send: automatically converts long messages to resources
692
+ *
693
+ * If content exceeds MESSAGE_LENGTH_THRESHOLD:
694
+ * 1. Creates a resource with the full content
695
+ * 2. Sends a short message referencing the resource
696
+ * 3. Logs the full content in debug channel for visibility
697
+ */
698
+ async smartSend(from, content, options) {
699
+ if (!shouldUseResource(content)) return this.appendChannel(from, content, options);
700
+ const resourceType = content.startsWith("```") || content.includes("\n```") ? "markdown" : "text";
701
+ const resource = await this.createResource(content, from, resourceType);
702
+ await this.appendChannel("system", `Created resource ${resource.id} (${content.length} chars) for @${from}:\n${content}`, { kind: "debug" });
703
+ const mentions = extractMentions(content, this.validAgents);
704
+ const shortMessage = `${mentions.length > 0 ? mentions.map((m) => `@${m}`).join(" ") + " " : ""}[Long content stored as resource]\n\nRead the full content: resource_read("${resource.id}")\n\nReference: ${resource.ref}`;
705
+ return this.appendChannel(from, shortMessage, options);
706
+ }
682
707
  async getInbox(agent) {
683
708
  const state = await this.loadInboxState();
684
709
  const lastAckId = state.readCursors[agent];
@@ -2094,10 +2119,25 @@ Examples:
2094
2119
 
2095
2120
  Note: Workflow name is inferred from YAML 'name' field or filename
2096
2121
  `).action(async (file, options) => {
2097
- const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-K1Zd655A.mjs");
2122
+ const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-C26F4PpH.mjs");
2098
2123
  const tag = options.tag || DEFAULT_TAG;
2099
2124
  const parsedWorkflow = await parseWorkflowFile(file, { tag });
2100
2125
  const workflowName = parsedWorkflow.name;
2126
+ let controllers;
2127
+ let isCleaningUp = false;
2128
+ const cleanup = async () => {
2129
+ if (isCleaningUp) return;
2130
+ isCleaningUp = true;
2131
+ console.log("\nInterrupted, cleaning up...");
2132
+ if (controllers) {
2133
+ const { shutdownControllers } = await import("../workflow-C26F4PpH.mjs");
2134
+ const { createSilentLogger } = await import("../logger-L9AtbIPS.mjs");
2135
+ await shutdownControllers(controllers, createSilentLogger());
2136
+ }
2137
+ process.exit(130);
2138
+ };
2139
+ process.on("SIGINT", cleanup);
2140
+ process.on("SIGTERM", cleanup);
2101
2141
  try {
2102
2142
  const log = options.json ? console.error : console.log;
2103
2143
  const result = await runWorkflowWithControllers({
@@ -2110,6 +2150,9 @@ Note: Workflow name is inferred from YAML 'name' field or filename
2110
2150
  mode: "run",
2111
2151
  feedback: options.feedback
2112
2152
  });
2153
+ controllers = result.controllers;
2154
+ process.off("SIGINT", cleanup);
2155
+ process.off("SIGTERM", cleanup);
2113
2156
  if (!result.success) {
2114
2157
  console.error("Workflow failed:", result.error);
2115
2158
  process.exit(1);
@@ -2132,6 +2175,8 @@ Note: Workflow name is inferred from YAML 'name' field or filename
2132
2175
  for (const entry of result.feedback) console.log(` [${entry.type}] ${entry.target}: ${entry.description}`);
2133
2176
  }
2134
2177
  } catch (error) {
2178
+ process.off("SIGINT", cleanup);
2179
+ process.off("SIGTERM", cleanup);
2135
2180
  console.error("Error:", error instanceof Error ? error.message : String(error));
2136
2181
  process.exit(1);
2137
2182
  }
@@ -2144,7 +2189,7 @@ Examples:
2144
2189
 
2145
2190
  Note: Workflow name is inferred from YAML 'name' field or filename
2146
2191
  `).action(async (file, options) => {
2147
- const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-K1Zd655A.mjs");
2192
+ const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-C26F4PpH.mjs");
2148
2193
  const tag = options.tag || DEFAULT_TAG;
2149
2194
  const parsedWorkflow = await parseWorkflowFile(file, { tag });
2150
2195
  const workflowName = parsedWorkflow.name;
@@ -2339,7 +2384,7 @@ function registerInfoCommands(program) {
2339
2384
  console.log(`\nDefault: ${defaultModel} (when no model specified)`);
2340
2385
  });
2341
2386
  program.command("backends").description("Check available backends (SDK, CLI tools)").action(async () => {
2342
- const { listBackends } = await import("../backends-B8rYTNqn.mjs");
2387
+ const { listBackends } = await import("../backends-fLwD_6G_.mjs");
2343
2388
  const backends = await listBackends();
2344
2389
  console.log("Backend Status:\n");
2345
2390
  for (const backend of backends) {
@@ -2369,7 +2414,7 @@ Examples:
2369
2414
  $ agent-worker doc read @review:pr-123 # Read specific workflow:tag document
2370
2415
  `).action(async (targetInput) => {
2371
2416
  const dir = await resolveDir(targetInput);
2372
- const { createFileContextProvider } = await import("../context-C7nBmU5D.mjs");
2417
+ const { createFileContextProvider } = await import("../context-DW7xrslO.mjs");
2373
2418
  const content = await createFileContextProvider(dir, []).readDocument();
2374
2419
  console.log(content || "(empty document)");
2375
2420
  });
@@ -2387,7 +2432,7 @@ Examples:
2387
2432
  process.exit(1);
2388
2433
  }
2389
2434
  const dir = await resolveDir(targetInput);
2390
- const { createFileContextProvider } = await import("../context-C7nBmU5D.mjs");
2435
+ const { createFileContextProvider } = await import("../context-DW7xrslO.mjs");
2391
2436
  await createFileContextProvider(dir, []).writeDocument(content);
2392
2437
  console.log("Document written");
2393
2438
  });
@@ -2405,7 +2450,7 @@ Examples:
2405
2450
  process.exit(1);
2406
2451
  }
2407
2452
  const dir = await resolveDir(targetInput);
2408
- const { createFileContextProvider } = await import("../context-C7nBmU5D.mjs");
2453
+ const { createFileContextProvider } = await import("../context-DW7xrslO.mjs");
2409
2454
  await createFileContextProvider(dir, []).appendDocument(content);
2410
2455
  console.log("Content appended");
2411
2456
  });
@@ -2485,6 +2530,10 @@ Note: Requires agent to be created with --feedback flag
2485
2530
  });
2486
2531
  }
2487
2532
 
2533
+ //#endregion
2534
+ //#region package.json
2535
+ var version = "0.6.0";
2536
+
2488
2537
  //#endregion
2489
2538
  //#region src/cli/index.ts
2490
2539
  globalThis.AI_SDK_LOG_WARNINGS = false;
@@ -2497,7 +2546,7 @@ process.stderr.write = function(chunk, ...rest) {
2497
2546
  return true;
2498
2547
  };
2499
2548
  const program = new Command();
2500
- program.name("agent-worker").description("CLI for creating and managing AI agents").version("0.0.1");
2549
+ program.name("agent-worker").description("CLI for creating and managing AI agents").version(version);
2501
2550
  registerAgentCommands(program);
2502
2551
  registerSendCommands(program);
2503
2552
  registerMockCommands(program);
@@ -2509,4 +2558,4 @@ registerDocCommands(program);
2509
2558
  program.parse();
2510
2559
 
2511
2560
  //#endregion
2512
- export { FileStorage as a, CONTEXT_DEFAULTS as c, RESOURCE_SCHEME as d, calculatePriority as f, generateResourceId as h, resolveContextDir as i, MENTION_PATTERN as l, extractMentions as m, createFileContextProvider as n, MemoryStorage as o, createResourceRef as p, getDefaultContextDir as r, ContextProviderImpl as s, FileContextProvider as t, RESOURCE_PREFIX as u };
2561
+ export { shouldUseResource as _, FileStorage as a, CONTEXT_DEFAULTS as c, RESOURCE_PREFIX as d, RESOURCE_SCHEME as f, generateResourceId as g, extractMentions as h, resolveContextDir as i, MENTION_PATTERN as l, createResourceRef as m, createFileContextProvider as n, MemoryStorage as o, calculatePriority as p, getDefaultContextDir as r, ContextProviderImpl as s, FileContextProvider as t, MESSAGE_LENGTH_THRESHOLD as u };
@@ -0,0 +1,4 @@
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-ONSDOpt5.mjs";
3
+
4
+ export { createFileContextProvider };
package/dist/index.d.mts CHANGED
@@ -175,6 +175,8 @@ interface Backend {
175
175
  setWorkspace?(workspaceDir: string, mcpConfig: {
176
176
  mcpServers: Record<string, unknown>;
177
177
  }): void;
178
+ /** Abort any running operations and cleanup resources */
179
+ abort?(): void;
178
180
  }
179
181
  //#endregion
180
182
  //#region src/agent/session.d.ts
@@ -477,6 +479,7 @@ interface ClaudeCodeOptions {
477
479
  declare class ClaudeCodeBackend implements Backend {
478
480
  readonly type: "claude";
479
481
  private options;
482
+ private currentAbort?;
480
483
  constructor(options?: ClaudeCodeOptions);
481
484
  /**
482
485
  * Set up workspace directory with MCP config
@@ -499,6 +502,10 @@ declare class ClaudeCodeBackend implements Backend {
499
502
  * Set MCP config path (for workflow integration)
500
503
  */
501
504
  setMcpConfigPath(path: string): void;
505
+ /**
506
+ * Abort any running claude process
507
+ */
508
+ abort(): void;
502
509
  }
503
510
  //#endregion
504
511
  //#region src/backends/codex.d.ts
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-CEYiMUgC.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-iya7NbH7.mjs";
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-BJyk6zvs.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-CuAfAkHU.mjs";
3
3
  import { jsonSchema, tool } from "ai";
4
4
  import { createBashTool } from "bash-tool";
5
5
 
@@ -0,0 +1,63 @@
1
+ //#region src/workflow/logger.ts
2
+ /**
3
+ * Create a silent logger (no output)
4
+ */
5
+ function createSilentLogger() {
6
+ const noop = () => {};
7
+ return {
8
+ debug: noop,
9
+ info: noop,
10
+ warn: noop,
11
+ error: noop,
12
+ isDebug: () => false,
13
+ child: () => createSilentLogger()
14
+ };
15
+ }
16
+ /**
17
+ * Create a logger that writes to the channel.
18
+ *
19
+ * - info/warn/error → channel entry with kind="log" (always shown to user)
20
+ * - debug → channel entry with kind="debug" (only shown with --debug)
21
+ *
22
+ * The display layer handles formatting and filtering.
23
+ */
24
+ function createChannelLogger(config) {
25
+ const { provider, from = "system" } = config;
26
+ const formatContent = (level, message, args) => {
27
+ const argsStr = args.length > 0 ? " " + args.map(formatArg).join(" ") : "";
28
+ if (level === "warn") return `[WARN] ${message}${argsStr}`;
29
+ if (level === "error") return `[ERROR] ${message}${argsStr}`;
30
+ return `${message}${argsStr}`;
31
+ };
32
+ const write = (level, message, args) => {
33
+ const content = formatContent(level, message, args);
34
+ const kind = level === "debug" ? "debug" : "log";
35
+ provider.appendChannel(from, content, { kind }).catch(() => {});
36
+ };
37
+ return {
38
+ debug: (message, ...args) => write("debug", message, args),
39
+ info: (message, ...args) => write("info", message, args),
40
+ warn: (message, ...args) => write("warn", message, args),
41
+ error: (message, ...args) => write("error", message, args),
42
+ isDebug: () => true,
43
+ child: (childPrefix) => {
44
+ return createChannelLogger({
45
+ provider,
46
+ from: from ? `${from}:${childPrefix}` : childPrefix
47
+ });
48
+ }
49
+ };
50
+ }
51
+ /** Format an argument for logging */
52
+ function formatArg(arg) {
53
+ if (arg === null || arg === void 0) return String(arg);
54
+ if (typeof arg === "object") try {
55
+ return JSON.stringify(arg);
56
+ } catch {
57
+ return String(arg);
58
+ }
59
+ return String(arg);
60
+ }
61
+
62
+ //#endregion
63
+ export { createChannelLogger, createSilentLogger };
@@ -169,9 +169,8 @@ function createContextMCPServer(options) {
169
169
  version
170
170
  });
171
171
  const agentConnections = /* @__PURE__ */ new Map();
172
- const CHANNEL_MSG_LIMIT = 2e3;
173
- server.tool("channel_send", `Send a message to the shared channel. Use @agent to mention/notify. Use "to" for private DMs. Max ${CHANNEL_MSG_LIMIT} chars — for longer content, use resource_create first then reference the resource ID in your message.`, {
174
- message: z.string().describe("Message content, can include @mentions like @reviewer or @coder"),
172
+ server.tool("channel_send", `Send a message to the shared channel. Use @agent to mention/notify. Use "to" for private DMs. Long messages (> 2000 chars) are automatically converted to resources.`, {
173
+ message: z.string().describe("Message content, can include @mentions like @reviewer or @coder. Long messages are auto-converted to resources."),
175
174
  to: z.string().optional().describe("Send as DM to a specific agent (private, only you and recipient see it)")
176
175
  }, async ({ message, to }, extra) => {
177
176
  const from = getAgentId(extra) || "anonymous";
@@ -179,15 +178,8 @@ function createContextMCPServer(options) {
179
178
  message,
180
179
  to
181
180
  });
182
- if (message.length > CHANNEL_MSG_LIMIT) return {
183
- isError: true,
184
- content: [{
185
- type: "text",
186
- text: `Message too long (${message.length} chars, max ${CHANNEL_MSG_LIMIT}). Use resource_create to store the full content, then send a short message referencing the resource ID.`
187
- }]
188
- };
189
181
  const sendOpts = to ? { to } : void 0;
190
- const msg = await provider.appendChannel(from, message, sendOpts);
182
+ const msg = await provider.smartSend(from, message, sendOpts);
191
183
  for (const target of msg.mentions) if (onMention) onMention(from, target, msg);
192
184
  if (to && !msg.mentions.includes(to) && onMention) onMention(from, to, msg);
193
185
  return { content: [{
@@ -1,4 +1,4 @@
1
- import { O as createModelAsync } from "./backends-CEYiMUgC.mjs";
1
+ import { O as createModelAsync } from "./backends-BJyk6zvs.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";
@@ -1,6 +1,7 @@
1
- import { O as createModelAsync, a as createMockBackend, n as createBackend, w as parseModel } from "./backends-CEYiMUgC.mjs";
1
+ import { O as createModelAsync, a as createMockBackend, n as createBackend, w as parseModel } from "./backends-BJyk6zvs.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-DtIApaBD.mjs";
3
+ import { a as createMemoryContextProvider, t as createContextMCPServer } from "./mcp-server-ONSDOpt5.mjs";
4
+ import { createChannelLogger, createSilentLogger } from "./logger-L9AtbIPS.mjs";
4
5
  import { generateText, jsonSchema, stepCountIs, tool } from "ai";
5
6
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
6
7
  import { basename, dirname, join, resolve } from "node:path";
@@ -459,16 +460,6 @@ function formatInbox(inbox) {
459
460
  }).join("\n");
460
461
  }
461
462
  /**
462
- * Format channel messages for display
463
- */
464
- function formatChannel(entries) {
465
- if (entries.length === 0) return "(no messages)";
466
- return entries.map((e) => {
467
- const dm = e.to ? ` [DM→@${e.to}]` : "";
468
- return `[${e.timestamp.slice(11, 19)}] @${e.from}${dm}: ${e.content}`;
469
- }).join("\n");
470
- }
471
- /**
472
463
  * Build the complete agent prompt from run context
473
464
  */
474
465
  function buildAgentPrompt(ctx) {
@@ -479,8 +470,8 @@ function buildAgentPrompt(ctx) {
479
470
  sections.push(`## Inbox (${ctx.inbox.length} message${ctx.inbox.length === 1 ? "" : "s"} for you)`);
480
471
  sections.push(formatInbox(ctx.inbox));
481
472
  sections.push("");
482
- sections.push(`## Recent Activity (last ${ctx.recentChannel.length} messages)`);
483
- sections.push(formatChannel(ctx.recentChannel));
473
+ sections.push("## Recent Activity");
474
+ sections.push("Use channel_read tool to view recent channel messages and conversation context if needed.");
484
475
  if (ctx.documentContent) {
485
476
  sections.push("");
486
477
  sections.push("## Shared Document");
@@ -964,6 +955,7 @@ function createAgentController(config) {
964
955
  async stop() {
965
956
  log(`Stopping`);
966
957
  state = "stopped";
958
+ if (backend.abort) backend.abort();
967
959
  if (pollTimeout) {
968
960
  clearTimeout(pollTimeout);
969
961
  pollTimeout = null;
@@ -1368,68 +1360,6 @@ function startChannelWatcher(config) {
1368
1360
  } };
1369
1361
  }
1370
1362
 
1371
- //#endregion
1372
- //#region src/workflow/logger.ts
1373
- /**
1374
- * Create a silent logger (no output)
1375
- */
1376
- function createSilentLogger() {
1377
- const noop = () => {};
1378
- return {
1379
- debug: noop,
1380
- info: noop,
1381
- warn: noop,
1382
- error: noop,
1383
- isDebug: () => false,
1384
- child: () => createSilentLogger()
1385
- };
1386
- }
1387
- /**
1388
- * Create a logger that writes to the channel.
1389
- *
1390
- * - info/warn/error → channel entry with kind="log" (always shown to user)
1391
- * - debug → channel entry with kind="debug" (only shown with --debug)
1392
- *
1393
- * The display layer handles formatting and filtering.
1394
- */
1395
- function createChannelLogger(config) {
1396
- const { provider, from = "system" } = config;
1397
- const formatContent = (level, message, args) => {
1398
- const argsStr = args.length > 0 ? " " + args.map(formatArg).join(" ") : "";
1399
- if (level === "warn") return `[WARN] ${message}${argsStr}`;
1400
- if (level === "error") return `[ERROR] ${message}${argsStr}`;
1401
- return `${message}${argsStr}`;
1402
- };
1403
- const write = (level, message, args) => {
1404
- const content = formatContent(level, message, args);
1405
- const kind = level === "debug" ? "debug" : "log";
1406
- provider.appendChannel(from, content, { kind }).catch(() => {});
1407
- };
1408
- return {
1409
- debug: (message, ...args) => write("debug", message, args),
1410
- info: (message, ...args) => write("info", message, args),
1411
- warn: (message, ...args) => write("warn", message, args),
1412
- error: (message, ...args) => write("error", message, args),
1413
- isDebug: () => true,
1414
- child: (childPrefix) => {
1415
- return createChannelLogger({
1416
- provider,
1417
- from: from ? `${from}:${childPrefix}` : childPrefix
1418
- });
1419
- }
1420
- };
1421
- }
1422
- /** Format an argument for logging */
1423
- function formatArg(arg) {
1424
- if (arg === null || arg === void 0) return String(arg);
1425
- if (typeof arg === "object") try {
1426
- return JSON.stringify(arg);
1427
- } catch {
1428
- return String(arg);
1429
- }
1430
- return String(arg);
1431
- }
1432
-
1433
1363
  //#endregion
1434
1364
  //#region src/workflow/runner.ts
1435
1365
  /**
@@ -1560,7 +1490,7 @@ async function initWorkflow(config) {
1560
1490
  return;
1561
1491
  }
1562
1492
  logger.debug(`Kickoff: ${interpolatedKickoff.slice(0, 100)}...`);
1563
- await contextProvider.appendChannel("system", interpolatedKickoff);
1493
+ await contextProvider.smartSend("system", interpolatedKickoff);
1564
1494
  },
1565
1495
  async shutdown() {
1566
1496
  logger.debug("Shutting down...");
@@ -1789,4 +1719,4 @@ function sleep(ms) {
1789
1719
  }
1790
1720
 
1791
1721
  //#endregion
1792
- export { parseWorkflowFile, runWorkflowWithControllers };
1722
+ export { parseWorkflowFile, runWorkflowWithControllers, shutdownControllers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-worker",
3
- "version": "0.5.0",
3
+ "version": "0.6.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,4 +0,0 @@
1
- import { a as FileStorage, c as CONTEXT_DEFAULTS, d as RESOURCE_SCHEME, f as calculatePriority, h as generateResourceId, i as resolveContextDir, l as MENTION_PATTERN, m as extractMentions, n as createFileContextProvider, o as MemoryStorage, p as createResourceRef, r as getDefaultContextDir, s as ContextProviderImpl, t as FileContextProvider, u as RESOURCE_PREFIX } from "./cli/index.mjs";
2
- import { a as createMemoryContextProvider, i as MemoryContextProvider, n as formatProposal, r as formatProposalList, t as createContextMCPServer } from "./mcp-server-DtIApaBD.mjs";
3
-
4
- export { createFileContextProvider };