agent-worker 0.5.0 → 0.7.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.
- package/dist/{backends-B8rYTNqn.mjs → backends-BN3LvE37.mjs} +1 -1
- package/dist/{backends-CEYiMUgC.mjs → backends-Hclwb_Zp.mjs} +83 -2
- package/dist/cli/index.mjs +79 -18
- package/dist/context-Bq7pSNVM.mjs +4 -0
- package/dist/display-pretty-BL9H2ocr.mjs +169 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +2 -2
- package/dist/logger-C3ekEOzi.mjs +63 -0
- package/dist/{mcp-server-DtIApaBD.mjs → mcp-server-D5Pnt0lB.mjs} +13 -13
- package/dist/{skills-iya7NbH7.mjs → skills-CrCMADND.mjs} +1 -1
- package/dist/{workflow-K1Zd655A.mjs → workflow-CzVHUE9I.mjs} +38 -125
- package/package.json +3 -1
- package/dist/context-C7nBmU5D.mjs +0 -4
|
@@ -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-
|
|
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
2
|
|
|
3
3
|
export { listBackends };
|
|
@@ -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 {
|
|
@@ -540,7 +604,9 @@ function createStreamParser(debugLog, backendName, adapter) {
|
|
|
540
604
|
for (const line of lines) {
|
|
541
605
|
if (!line.trim()) continue;
|
|
542
606
|
try {
|
|
543
|
-
const
|
|
607
|
+
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);
|
|
544
610
|
if (event) {
|
|
545
611
|
const progress = formatEvent(event, backendName);
|
|
546
612
|
if (progress) debugLog(progress);
|
|
@@ -577,6 +643,7 @@ function formatToolInput(input) {
|
|
|
577
643
|
var ClaudeCodeBackend = class {
|
|
578
644
|
type = "claude";
|
|
579
645
|
options;
|
|
646
|
+
currentAbort;
|
|
580
647
|
constructor(options = {}) {
|
|
581
648
|
this.options = {
|
|
582
649
|
timeout: 3e5,
|
|
@@ -601,13 +668,16 @@ var ClaudeCodeBackend = class {
|
|
|
601
668
|
const outputFormat = this.options.outputFormat ?? "stream-json";
|
|
602
669
|
const timeout = this.options.timeout ?? 3e5;
|
|
603
670
|
try {
|
|
604
|
-
const {
|
|
671
|
+
const { promise, abort } = execWithIdleTimeoutAbortable({
|
|
605
672
|
command: "claude",
|
|
606
673
|
args,
|
|
607
674
|
cwd,
|
|
608
675
|
timeout,
|
|
609
676
|
onStdout: outputFormat === "stream-json" && debugLog ? createStreamParser(debugLog, "Claude", claudeAdapter) : void 0
|
|
610
677
|
});
|
|
678
|
+
this.currentAbort = abort;
|
|
679
|
+
const { stdout } = await promise;
|
|
680
|
+
this.currentAbort = void 0;
|
|
611
681
|
if (outputFormat === "stream-json") return extractClaudeResult(stdout);
|
|
612
682
|
if (outputFormat === "json") try {
|
|
613
683
|
const parsed = JSON.parse(stdout);
|
|
@@ -621,6 +691,7 @@ var ClaudeCodeBackend = class {
|
|
|
621
691
|
}
|
|
622
692
|
return { content: stdout.trim() };
|
|
623
693
|
} catch (error) {
|
|
694
|
+
this.currentAbort = void 0;
|
|
624
695
|
if (error instanceof IdleTimeoutError) throw new Error(`claude timed out after ${timeout}ms of inactivity`);
|
|
625
696
|
if (error && typeof error === "object" && "exitCode" in error) {
|
|
626
697
|
const execError = error;
|
|
@@ -660,6 +731,7 @@ var ClaudeCodeBackend = class {
|
|
|
660
731
|
if (this.options.allowedTools?.length) args.push("--allowed-tools", this.options.allowedTools.join(","));
|
|
661
732
|
const outputFormat = this.options.outputFormat ?? "stream-json";
|
|
662
733
|
args.push("--output-format", outputFormat);
|
|
734
|
+
if (outputFormat === "stream-json") args.push("--verbose");
|
|
663
735
|
if (this.options.continue) args.push("--continue");
|
|
664
736
|
if (this.options.resume) args.push("--resume", this.options.resume);
|
|
665
737
|
if (this.options.mcpConfigPath) args.push("--mcp-config", this.options.mcpConfigPath);
|
|
@@ -671,6 +743,15 @@ var ClaudeCodeBackend = class {
|
|
|
671
743
|
setMcpConfigPath(path) {
|
|
672
744
|
this.options.mcpConfigPath = path;
|
|
673
745
|
}
|
|
746
|
+
/**
|
|
747
|
+
* Abort any running claude process
|
|
748
|
+
*/
|
|
749
|
+
abort() {
|
|
750
|
+
if (this.currentAbort) {
|
|
751
|
+
this.currentAbort();
|
|
752
|
+
this.currentAbort = void 0;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
674
755
|
};
|
|
675
756
|
|
|
676
757
|
//#endregion
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { T as FRONTIER_MODELS, k as getDefaultModel, n as createBackend } from "../backends-
|
|
3
|
-
import { a as createSkillsTool, c as createFeedbackTool, l as AgentSession, o as SkillsProvider, s as FEEDBACK_PROMPT, t as SkillImporter } from "../skills-
|
|
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";
|
|
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 }}/",
|
|
@@ -654,6 +662,7 @@ var ContextProviderImpl = class {
|
|
|
654
662
|
};
|
|
655
663
|
if (options?.to) msg.to = options.to;
|
|
656
664
|
if (options?.kind) msg.kind = options.kind;
|
|
665
|
+
if (options?.toolCall) msg.toolCall = options.toolCall;
|
|
657
666
|
const line = JSON.stringify(msg) + "\n";
|
|
658
667
|
await this.storage.append(KEYS.channel, line);
|
|
659
668
|
return msg;
|
|
@@ -679,6 +688,23 @@ var ContextProviderImpl = class {
|
|
|
679
688
|
cursor: entries.length
|
|
680
689
|
};
|
|
681
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* Smart send: automatically converts long messages to resources
|
|
693
|
+
*
|
|
694
|
+
* If content exceeds MESSAGE_LENGTH_THRESHOLD:
|
|
695
|
+
* 1. Creates a resource with the full content
|
|
696
|
+
* 2. Sends a short message referencing the resource
|
|
697
|
+
* 3. Logs the full content in debug channel for visibility
|
|
698
|
+
*/
|
|
699
|
+
async smartSend(from, content, options) {
|
|
700
|
+
if (!shouldUseResource(content)) return this.appendChannel(from, content, options);
|
|
701
|
+
const resourceType = content.startsWith("```") || content.includes("\n```") ? "markdown" : "text";
|
|
702
|
+
const resource = await this.createResource(content, from, resourceType);
|
|
703
|
+
await this.appendChannel("system", `Created resource ${resource.id} (${content.length} chars) for @${from}:\n${content}`, { kind: "debug" });
|
|
704
|
+
const mentions = extractMentions(content, this.validAgents);
|
|
705
|
+
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}`;
|
|
706
|
+
return this.appendChannel(from, shortMessage, options);
|
|
707
|
+
}
|
|
682
708
|
async getInbox(agent) {
|
|
683
709
|
const state = await this.loadInboxState();
|
|
684
710
|
const lastAckId = state.readCursors[agent];
|
|
@@ -2094,22 +2120,42 @@ Examples:
|
|
|
2094
2120
|
|
|
2095
2121
|
Note: Workflow name is inferred from YAML 'name' field or filename
|
|
2096
2122
|
`).action(async (file, options) => {
|
|
2097
|
-
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-
|
|
2123
|
+
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CzVHUE9I.mjs");
|
|
2098
2124
|
const tag = options.tag || DEFAULT_TAG;
|
|
2099
2125
|
const parsedWorkflow = await parseWorkflowFile(file, { tag });
|
|
2100
2126
|
const workflowName = parsedWorkflow.name;
|
|
2127
|
+
let controllers;
|
|
2128
|
+
let isCleaningUp = false;
|
|
2129
|
+
const cleanup = async () => {
|
|
2130
|
+
if (isCleaningUp) return;
|
|
2131
|
+
isCleaningUp = true;
|
|
2132
|
+
console.log("\nInterrupted, cleaning up...");
|
|
2133
|
+
if (controllers) {
|
|
2134
|
+
const { shutdownControllers } = await import("../workflow-CzVHUE9I.mjs");
|
|
2135
|
+
const { createSilentLogger } = await import("../logger-C3ekEOzi.mjs");
|
|
2136
|
+
await shutdownControllers(controllers, createSilentLogger());
|
|
2137
|
+
}
|
|
2138
|
+
process.exit(130);
|
|
2139
|
+
};
|
|
2140
|
+
process.on("SIGINT", cleanup);
|
|
2141
|
+
process.on("SIGTERM", cleanup);
|
|
2101
2142
|
try {
|
|
2102
2143
|
const log = options.json ? console.error : console.log;
|
|
2103
2144
|
const result = await runWorkflowWithControllers({
|
|
2104
2145
|
workflow: parsedWorkflow,
|
|
2105
2146
|
workflowName,
|
|
2106
2147
|
tag,
|
|
2148
|
+
workflowPath: file,
|
|
2107
2149
|
instance: `${workflowName}:${tag}`,
|
|
2108
2150
|
debug: options.debug,
|
|
2109
2151
|
log,
|
|
2110
2152
|
mode: "run",
|
|
2111
|
-
feedback: options.feedback
|
|
2153
|
+
feedback: options.feedback,
|
|
2154
|
+
prettyDisplay: !options.debug && !options.json
|
|
2112
2155
|
});
|
|
2156
|
+
controllers = result.controllers;
|
|
2157
|
+
process.off("SIGINT", cleanup);
|
|
2158
|
+
process.off("SIGTERM", cleanup);
|
|
2113
2159
|
if (!result.success) {
|
|
2114
2160
|
console.error("Workflow failed:", result.error);
|
|
2115
2161
|
process.exit(1);
|
|
@@ -2122,16 +2168,27 @@ Note: Workflow name is inferred from YAML 'name' field or filename
|
|
|
2122
2168
|
document: finalDoc,
|
|
2123
2169
|
feedback: result.feedback
|
|
2124
2170
|
}, null, 2));
|
|
2125
|
-
else if (
|
|
2126
|
-
|
|
2127
|
-
|
|
2171
|
+
else if (!options.debug) {
|
|
2172
|
+
const { showWorkflowSummary } = await import("../display-pretty-BL9H2ocr.mjs");
|
|
2173
|
+
showWorkflowSummary({
|
|
2174
|
+
duration: result.duration,
|
|
2175
|
+
document: finalDoc,
|
|
2176
|
+
feedback: result.feedback
|
|
2177
|
+
});
|
|
2178
|
+
} else {
|
|
2179
|
+
if (finalDoc) {
|
|
2180
|
+
console.log("\n--- Document ---");
|
|
2181
|
+
console.log(finalDoc);
|
|
2182
|
+
}
|
|
2183
|
+
if (result.feedback && result.feedback.length > 0) {
|
|
2184
|
+
console.log(`\n--- Feedback (${result.feedback.length}) ---`);
|
|
2185
|
+
for (const entry of result.feedback) console.log(` [${entry.type}] ${entry.target}: ${entry.description}`);
|
|
2186
|
+
}
|
|
2128
2187
|
}
|
|
2129
2188
|
}
|
|
2130
|
-
if (result.feedback && result.feedback.length > 0 && !options.json) {
|
|
2131
|
-
console.log(`\n--- Feedback (${result.feedback.length}) ---`);
|
|
2132
|
-
for (const entry of result.feedback) console.log(` [${entry.type}] ${entry.target}: ${entry.description}`);
|
|
2133
|
-
}
|
|
2134
2189
|
} catch (error) {
|
|
2190
|
+
process.off("SIGINT", cleanup);
|
|
2191
|
+
process.off("SIGTERM", cleanup);
|
|
2135
2192
|
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
2136
2193
|
process.exit(1);
|
|
2137
2194
|
}
|
|
@@ -2144,7 +2201,7 @@ Examples:
|
|
|
2144
2201
|
|
|
2145
2202
|
Note: Workflow name is inferred from YAML 'name' field or filename
|
|
2146
2203
|
`).action(async (file, options) => {
|
|
2147
|
-
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-
|
|
2204
|
+
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CzVHUE9I.mjs");
|
|
2148
2205
|
const tag = options.tag || DEFAULT_TAG;
|
|
2149
2206
|
const parsedWorkflow = await parseWorkflowFile(file, { tag });
|
|
2150
2207
|
const workflowName = parsedWorkflow.name;
|
|
@@ -2339,7 +2396,7 @@ function registerInfoCommands(program) {
|
|
|
2339
2396
|
console.log(`\nDefault: ${defaultModel} (when no model specified)`);
|
|
2340
2397
|
});
|
|
2341
2398
|
program.command("backends").description("Check available backends (SDK, CLI tools)").action(async () => {
|
|
2342
|
-
const { listBackends } = await import("../backends-
|
|
2399
|
+
const { listBackends } = await import("../backends-BN3LvE37.mjs");
|
|
2343
2400
|
const backends = await listBackends();
|
|
2344
2401
|
console.log("Backend Status:\n");
|
|
2345
2402
|
for (const backend of backends) {
|
|
@@ -2369,7 +2426,7 @@ Examples:
|
|
|
2369
2426
|
$ agent-worker doc read @review:pr-123 # Read specific workflow:tag document
|
|
2370
2427
|
`).action(async (targetInput) => {
|
|
2371
2428
|
const dir = await resolveDir(targetInput);
|
|
2372
|
-
const { createFileContextProvider } = await import("../context-
|
|
2429
|
+
const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
|
|
2373
2430
|
const content = await createFileContextProvider(dir, []).readDocument();
|
|
2374
2431
|
console.log(content || "(empty document)");
|
|
2375
2432
|
});
|
|
@@ -2387,7 +2444,7 @@ Examples:
|
|
|
2387
2444
|
process.exit(1);
|
|
2388
2445
|
}
|
|
2389
2446
|
const dir = await resolveDir(targetInput);
|
|
2390
|
-
const { createFileContextProvider } = await import("../context-
|
|
2447
|
+
const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
|
|
2391
2448
|
await createFileContextProvider(dir, []).writeDocument(content);
|
|
2392
2449
|
console.log("Document written");
|
|
2393
2450
|
});
|
|
@@ -2405,7 +2462,7 @@ Examples:
|
|
|
2405
2462
|
process.exit(1);
|
|
2406
2463
|
}
|
|
2407
2464
|
const dir = await resolveDir(targetInput);
|
|
2408
|
-
const { createFileContextProvider } = await import("../context-
|
|
2465
|
+
const { createFileContextProvider } = await import("../context-Bq7pSNVM.mjs");
|
|
2409
2466
|
await createFileContextProvider(dir, []).appendDocument(content);
|
|
2410
2467
|
console.log("Content appended");
|
|
2411
2468
|
});
|
|
@@ -2485,6 +2542,10 @@ Note: Requires agent to be created with --feedback flag
|
|
|
2485
2542
|
});
|
|
2486
2543
|
}
|
|
2487
2544
|
|
|
2545
|
+
//#endregion
|
|
2546
|
+
//#region package.json
|
|
2547
|
+
var version = "0.7.0";
|
|
2548
|
+
|
|
2488
2549
|
//#endregion
|
|
2489
2550
|
//#region src/cli/index.ts
|
|
2490
2551
|
globalThis.AI_SDK_LOG_WARNINGS = false;
|
|
@@ -2497,7 +2558,7 @@ process.stderr.write = function(chunk, ...rest) {
|
|
|
2497
2558
|
return true;
|
|
2498
2559
|
};
|
|
2499
2560
|
const program = new Command();
|
|
2500
|
-
program.name("agent-worker").description("CLI for creating and managing AI agents").version(
|
|
2561
|
+
program.name("agent-worker").description("CLI for creating and managing AI agents").version(version);
|
|
2501
2562
|
registerAgentCommands(program);
|
|
2502
2563
|
registerSendCommands(program);
|
|
2503
2564
|
registerMockCommands(program);
|
|
@@ -2509,4 +2570,4 @@ registerDocCommands(program);
|
|
|
2509
2570
|
program.parse();
|
|
2510
2571
|
|
|
2511
2572
|
//#endregion
|
|
2512
|
-
export { FileStorage as a, CONTEXT_DEFAULTS as c,
|
|
2573
|
+
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-D5Pnt0lB.mjs";
|
|
3
|
+
|
|
4
|
+
export { createFileContextProvider };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
|
|
4
|
+
//#region src/workflow/display-pretty.ts
|
|
5
|
+
/**
|
|
6
|
+
* Pretty display mode using @clack/prompts
|
|
7
|
+
*
|
|
8
|
+
* Clean, step-based CLI output:
|
|
9
|
+
* - Each message/event is a step
|
|
10
|
+
* - Uses clack's native symbols
|
|
11
|
+
* - Minimal decoration, maximum clarity
|
|
12
|
+
*/
|
|
13
|
+
const BANNER_LINES = [
|
|
14
|
+
" █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗ ██╗███████╗██████╗",
|
|
15
|
+
"██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ██║ ██║██╔═══██╗██╔══██╗██║ ██╔╝██╔════╝██╔══██╗",
|
|
16
|
+
"███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ █╗ ██║██║ ██║██████╔╝█████╔╝ █████╗ ██████╔╝",
|
|
17
|
+
"██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║███╗██║██║ ██║██╔══██╗██╔═██╗ ██╔══╝ ██╔══██╗",
|
|
18
|
+
"██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ╚███╔███╔╝╚██████╔╝██║ ██║██║ ██╗███████╗██║ ██║",
|
|
19
|
+
"╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝"
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Apply gradient colors to banner lines
|
|
23
|
+
* Creates a smooth cyan gradient effect (bright → dark) using ANSI 256 colors
|
|
24
|
+
* Inspired by vercel-labs/skills gradient approach
|
|
25
|
+
*/
|
|
26
|
+
function applyBannerGradient(lines) {
|
|
27
|
+
const CYAN_GRADIENT = [
|
|
28
|
+
"\x1B[38;5;51m",
|
|
29
|
+
"\x1B[38;5;45m",
|
|
30
|
+
"\x1B[38;5;39m",
|
|
31
|
+
"\x1B[38;5;33m",
|
|
32
|
+
"\x1B[38;5;27m",
|
|
33
|
+
"\x1B[38;5;21m"
|
|
34
|
+
];
|
|
35
|
+
const RESET = "\x1B[0m";
|
|
36
|
+
return lines.map((line, i) => `${CYAN_GRADIENT[i]}${line}${RESET}`).join("\n");
|
|
37
|
+
}
|
|
38
|
+
const AGENT_COLORS = [
|
|
39
|
+
pc.cyan,
|
|
40
|
+
pc.yellow,
|
|
41
|
+
pc.magenta,
|
|
42
|
+
pc.green,
|
|
43
|
+
pc.blue
|
|
44
|
+
];
|
|
45
|
+
function getAgentColor(name, agentNames) {
|
|
46
|
+
if (name === "system" || name === "user") return pc.dim;
|
|
47
|
+
const idx = agentNames.indexOf(name);
|
|
48
|
+
if (idx < 0) return AGENT_COLORS[name.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0) % AGENT_COLORS.length];
|
|
49
|
+
return AGENT_COLORS[idx % AGENT_COLORS.length];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Process a channel entry for pretty display
|
|
53
|
+
*/
|
|
54
|
+
function processEntry(entry, state, agentNames) {
|
|
55
|
+
const { kind, from, content, toolCall } = entry;
|
|
56
|
+
if (kind === "debug") return;
|
|
57
|
+
if (kind === "tool_call" && toolCall) {
|
|
58
|
+
const caller = from.includes(":") ? from.split(":").pop() : from;
|
|
59
|
+
if (caller) {
|
|
60
|
+
const color = getAgentColor(caller, agentNames);
|
|
61
|
+
const tool = pc.bold(pc.cyan(toolCall.name));
|
|
62
|
+
const args = toolCall.args ? pc.dim(`(${toolCall.args})`) : pc.dim("()");
|
|
63
|
+
p.log.message(`${color(caller)} called ${tool}${args}`, { symbol: pc.cyan("▶") });
|
|
64
|
+
} else p.log.message(`called ${pc.cyan(pc.bold(toolCall.name))}${pc.dim(`(${toolCall.args || ""})`)}`, { symbol: pc.cyan("▶") });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (kind === "log") {
|
|
68
|
+
if (content.includes("Running workflow:")) {
|
|
69
|
+
state.phase = "running";
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (content.includes("Agents:")) return;
|
|
73
|
+
if (content.includes("Starting agents")) {
|
|
74
|
+
if (state.spinner) {
|
|
75
|
+
const agentList = agentNames.join(", ");
|
|
76
|
+
state.spinner.stop(`Initialized: ${pc.dim(agentList)}`);
|
|
77
|
+
}
|
|
78
|
+
state.spinner = p.spinner();
|
|
79
|
+
state.spinner.start("Starting agents");
|
|
80
|
+
} else if (content.includes("Workflow complete")) {
|
|
81
|
+
if (state.spinner) {
|
|
82
|
+
state.spinner.stop();
|
|
83
|
+
state.spinner = null;
|
|
84
|
+
}
|
|
85
|
+
const match = content.match(/\(([0-9.]+)s\)/);
|
|
86
|
+
if (match) p.log.success(`Completed in ${pc.bold(match[1])}s`);
|
|
87
|
+
else p.log.success("Workflow complete");
|
|
88
|
+
state.phase = "complete";
|
|
89
|
+
} else if (content.startsWith("[ERROR]")) {
|
|
90
|
+
if (state.spinner) {
|
|
91
|
+
state.spinner.stop();
|
|
92
|
+
state.spinner = null;
|
|
93
|
+
}
|
|
94
|
+
p.log.error(content.replace("[ERROR] ", ""));
|
|
95
|
+
state.phase = "error";
|
|
96
|
+
} else if (content.startsWith("[WARN]")) p.log.warn(content.replace("[WARN] ", ""));
|
|
97
|
+
else if (content.match(/Inbox: \d+ message/)) p.log.step(pc.dim(content));
|
|
98
|
+
else if (content.match(/Running \(attempt/)) p.log.step(pc.dim(content));
|
|
99
|
+
else if (content.startsWith("DONE")) {
|
|
100
|
+
const details = content.replace("DONE ", "");
|
|
101
|
+
p.log.info(pc.green("✓") + " " + pc.dim(details));
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const color = getAgentColor(from, agentNames);
|
|
106
|
+
if (state.spinner && state.phase === "running" && !state.hasShownAgentsStarted) {
|
|
107
|
+
state.spinner.stop();
|
|
108
|
+
state.spinner = null;
|
|
109
|
+
p.log.info("Agents ready and processing");
|
|
110
|
+
state.hasShownAgentsStarted = true;
|
|
111
|
+
}
|
|
112
|
+
p.note(content.trim(), color(from));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Start pretty display watcher
|
|
116
|
+
*/
|
|
117
|
+
function startPrettyDisplay(config) {
|
|
118
|
+
const { contextProvider, agentNames, workflowName, tag, workflowPath, pollInterval = 500, initialCursor = 0 } = config;
|
|
119
|
+
const state = {
|
|
120
|
+
spinner: null,
|
|
121
|
+
phase: "init",
|
|
122
|
+
hasShownAgentsStarted: false
|
|
123
|
+
};
|
|
124
|
+
console.log("\n" + applyBannerGradient(BANNER_LINES));
|
|
125
|
+
console.log("");
|
|
126
|
+
const introText = ` ${workflowName}${tag === "main" ? "" : `:${tag}`}${workflowPath ? ` ${pc.dim(`(${workflowPath})`)}` : ""} `;
|
|
127
|
+
p.intro(pc.bgCyan(pc.black(introText)));
|
|
128
|
+
state.spinner = p.spinner();
|
|
129
|
+
const agentCount = agentNames.length;
|
|
130
|
+
const agentWord = agentCount === 1 ? "agent" : "agents";
|
|
131
|
+
state.spinner.start(`Initializing ${agentCount} ${agentWord}`);
|
|
132
|
+
let cursor = initialCursor;
|
|
133
|
+
let running = true;
|
|
134
|
+
const poll = async () => {
|
|
135
|
+
while (running) {
|
|
136
|
+
try {
|
|
137
|
+
const tail = await contextProvider.tailChannel(cursor);
|
|
138
|
+
for (const entry of tail.entries) processEntry(entry, state, agentNames);
|
|
139
|
+
cursor = tail.cursor;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("Display polling error:", error instanceof Error ? error.message : error);
|
|
142
|
+
}
|
|
143
|
+
await sleep(pollInterval);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
poll();
|
|
147
|
+
return { stop: () => {
|
|
148
|
+
running = false;
|
|
149
|
+
if (state.spinner) state.spinner.stop("Stopped");
|
|
150
|
+
} };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Show workflow completion summary
|
|
154
|
+
*/
|
|
155
|
+
function showWorkflowSummary(options) {
|
|
156
|
+
const { document, feedback } = options;
|
|
157
|
+
if (document && document.trim()) p.note(document, "Document");
|
|
158
|
+
if (feedback && feedback.length > 0) {
|
|
159
|
+
const feedbackLines = feedback.map((f) => `[${f.type}] ${f.target}: ${f.description}`);
|
|
160
|
+
p.note(feedbackLines.join("\n"), `Feedback (${feedback.length})`);
|
|
161
|
+
}
|
|
162
|
+
p.outro("Done");
|
|
163
|
+
}
|
|
164
|
+
function sleep(ms) {
|
|
165
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
export { showWorkflowSummary, startPrettyDisplay };
|
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-
|
|
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-
|
|
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";
|
|
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 };
|
|
@@ -159,19 +159,26 @@ function createContextMCPServer(options) {
|
|
|
159
159
|
const { provider, validAgents, name = "workflow-context", version = "1.0.0", onMention, proposalManager, feedback: feedbackEnabled, debugLog } = options;
|
|
160
160
|
const feedbackEntries = [];
|
|
161
161
|
const logTool = (tool, agent, params) => {
|
|
162
|
-
if (
|
|
162
|
+
if (!agent) return;
|
|
163
|
+
const paramsStr = Object.entries(params).filter(([_, v]) => v !== void 0).map(([k, v]) => {
|
|
163
164
|
const val = typeof v === "string" && v.length > 50 ? v.slice(0, 50) + "..." : v;
|
|
164
165
|
return `${k}=${JSON.stringify(val)}`;
|
|
165
|
-
}).join(", ")
|
|
166
|
+
}).join(", ");
|
|
167
|
+
provider.appendChannel(agent, `${tool}(${paramsStr})`, {
|
|
168
|
+
kind: "tool_call",
|
|
169
|
+
toolCall: {
|
|
170
|
+
name: tool,
|
|
171
|
+
args: paramsStr
|
|
172
|
+
}
|
|
173
|
+
}).catch(() => {});
|
|
166
174
|
};
|
|
167
175
|
const server = new McpServer({
|
|
168
176
|
name,
|
|
169
177
|
version
|
|
170
178
|
});
|
|
171
179
|
const agentConnections = /* @__PURE__ */ new Map();
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
message: z.string().describe("Message content, can include @mentions like @reviewer or @coder"),
|
|
180
|
+
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.`, {
|
|
181
|
+
message: z.string().describe("Message content, can include @mentions like @reviewer or @coder. Long messages are auto-converted to resources."),
|
|
175
182
|
to: z.string().optional().describe("Send as DM to a specific agent (private, only you and recipient see it)")
|
|
176
183
|
}, async ({ message, to }, extra) => {
|
|
177
184
|
const from = getAgentId(extra) || "anonymous";
|
|
@@ -179,15 +186,8 @@ function createContextMCPServer(options) {
|
|
|
179
186
|
message,
|
|
180
187
|
to
|
|
181
188
|
});
|
|
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
189
|
const sendOpts = to ? { to } : void 0;
|
|
190
|
-
const msg = await provider.
|
|
190
|
+
const msg = await provider.smartSend(from, message, sendOpts);
|
|
191
191
|
for (const target of msg.mentions) if (onMention) onMention(from, target, msg);
|
|
192
192
|
if (to && !msg.mentions.includes(to) && onMention) onMention(from, to, msg);
|
|
193
193
|
return { content: [{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { O as createModelAsync } from "./backends-
|
|
1
|
+
import { O as createModelAsync } from "./backends-Hclwb_Zp.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-
|
|
1
|
+
import { O as createModelAsync, a as createMockBackend, n as createBackend, w as parseModel } from "./backends-Hclwb_Zp.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-
|
|
3
|
+
import { a as createMemoryContextProvider, t as createContextMCPServer } from "./mcp-server-D5Pnt0lB.mjs";
|
|
4
|
+
import { createChannelLogger, createSilentLogger } from "./logger-C3ekEOzi.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";
|
|
@@ -14,9 +15,9 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
14
15
|
import { MockLanguageModelV3, mockValues } from "ai/test";
|
|
15
16
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
16
17
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
18
|
+
import stringWidth from "string-width";
|
|
17
19
|
import chalk from "chalk";
|
|
18
20
|
import wrapAnsi from "wrap-ansi";
|
|
19
|
-
import stringWidth from "string-width";
|
|
20
21
|
|
|
21
22
|
//#region src/workflow/parser.ts
|
|
22
23
|
/**
|
|
@@ -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(
|
|
483
|
-
sections.push(
|
|
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");
|
|
@@ -821,7 +812,18 @@ async function runSdkAgent(ctx, debugLog) {
|
|
|
821
812
|
stopWhen: stepCountIs(ctx.agent.max_steps ?? 30),
|
|
822
813
|
onStepFinish: (step) => {
|
|
823
814
|
_stepNum++;
|
|
824
|
-
if (step.toolCalls?.length)
|
|
815
|
+
if (step.toolCalls?.length) {
|
|
816
|
+
for (const tc of step.toolCalls) if (tc.toolName === "bash") {
|
|
817
|
+
const args = formatToolCall(tc);
|
|
818
|
+
ctx.provider.appendChannel(ctx.name, args, {
|
|
819
|
+
kind: "tool_call",
|
|
820
|
+
toolCall: {
|
|
821
|
+
name: tc.toolName,
|
|
822
|
+
args
|
|
823
|
+
}
|
|
824
|
+
}).catch(() => {});
|
|
825
|
+
}
|
|
826
|
+
}
|
|
825
827
|
}
|
|
826
828
|
});
|
|
827
829
|
const totalToolCalls = result.steps.reduce((n, s) => n + s.toolCalls.length, 0);
|
|
@@ -922,6 +924,7 @@ function createAgentController(config) {
|
|
|
922
924
|
workspaceDir,
|
|
923
925
|
projectDir,
|
|
924
926
|
retryAttempt: attempt,
|
|
927
|
+
provider: contextProvider,
|
|
925
928
|
feedback
|
|
926
929
|
}, log, infoLog);
|
|
927
930
|
if (lastResult.success) {
|
|
@@ -964,6 +967,7 @@ function createAgentController(config) {
|
|
|
964
967
|
async stop() {
|
|
965
968
|
log(`Stopping`);
|
|
966
969
|
state = "stopped";
|
|
970
|
+
if (backend.abort) backend.abort();
|
|
967
971
|
if (pollTimeout) {
|
|
968
972
|
clearTimeout(pollTimeout);
|
|
969
973
|
pollTimeout = null;
|
|
@@ -1270,46 +1274,6 @@ function formatStandardLog(entry, includeMillis = false) {
|
|
|
1270
1274
|
//#endregion
|
|
1271
1275
|
//#region src/workflow/display.ts
|
|
1272
1276
|
/**
|
|
1273
|
-
* Channel display formatting
|
|
1274
|
-
*
|
|
1275
|
-
* All output flows through the channel. This module formats and filters
|
|
1276
|
-
* channel entries for terminal display:
|
|
1277
|
-
* - kind=undefined (agent messages): always shown, colored
|
|
1278
|
-
* - kind="log" (operational logs): always shown, dimmed
|
|
1279
|
-
* - kind="debug" (debug details): only shown with --debug flag
|
|
1280
|
-
*
|
|
1281
|
-
* Two display modes:
|
|
1282
|
-
* - TTY (human): colored, aligned columns, smart wrapping
|
|
1283
|
-
* - Non-TTY (agent/pipe): plain text, no colors, simple separators
|
|
1284
|
-
*
|
|
1285
|
-
* Best practices implemented:
|
|
1286
|
-
* - Adaptive layout based on terminal width and agent names
|
|
1287
|
-
* - Smart text wrapping preserving ANSI colors
|
|
1288
|
-
* - Message grouping to reduce visual noise
|
|
1289
|
-
* - Background-agnostic color scheme
|
|
1290
|
-
*/
|
|
1291
|
-
/** Whether to use rich terminal formatting */
|
|
1292
|
-
const isTTY = !!process.stdout.isTTY && !process.env.NO_COLOR;
|
|
1293
|
-
/**
|
|
1294
|
-
* Background-agnostic color scheme
|
|
1295
|
-
* Uses only bold and standard colors that work on any theme
|
|
1296
|
-
*/
|
|
1297
|
-
const C = {
|
|
1298
|
-
dim: isTTY ? chalk.dim : (s) => s,
|
|
1299
|
-
bold: isTTY ? chalk.bold : (s) => s,
|
|
1300
|
-
yellow: isTTY ? chalk.yellow : (s) => s,
|
|
1301
|
-
red: isTTY ? chalk.red : (s) => s,
|
|
1302
|
-
agents: isTTY ? [
|
|
1303
|
-
chalk.cyan,
|
|
1304
|
-
chalk.yellow,
|
|
1305
|
-
chalk.magenta,
|
|
1306
|
-
chalk.green,
|
|
1307
|
-
chalk.blue,
|
|
1308
|
-
chalk.redBright
|
|
1309
|
-
] : Array(6).fill((s) => s),
|
|
1310
|
-
system: isTTY ? chalk.gray : (s) => s
|
|
1311
|
-
};
|
|
1312
|
-
/**
|
|
1313
1277
|
* Create display context for a workflow
|
|
1314
1278
|
*/
|
|
1315
1279
|
function createDisplayContext(agentNames, options) {
|
|
@@ -1368,68 +1332,6 @@ function startChannelWatcher(config) {
|
|
|
1368
1332
|
} };
|
|
1369
1333
|
}
|
|
1370
1334
|
|
|
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
1335
|
//#endregion
|
|
1434
1336
|
//#region src/workflow/runner.ts
|
|
1435
1337
|
/**
|
|
@@ -1560,7 +1462,7 @@ async function initWorkflow(config) {
|
|
|
1560
1462
|
return;
|
|
1561
1463
|
}
|
|
1562
1464
|
logger.debug(`Kickoff: ${interpolatedKickoff.slice(0, 100)}...`);
|
|
1563
|
-
await contextProvider.
|
|
1465
|
+
await contextProvider.smartSend("system", interpolatedKickoff);
|
|
1564
1466
|
},
|
|
1565
1467
|
async shutdown() {
|
|
1566
1468
|
logger.debug("Shutting down...");
|
|
@@ -1640,8 +1542,7 @@ async function runWorkflowWithControllers(config) {
|
|
|
1640
1542
|
} else logger.debug(`@mention: ${from} → @${target} (no controller found!)`);
|
|
1641
1543
|
},
|
|
1642
1544
|
debugLog: (msg) => {
|
|
1643
|
-
|
|
1644
|
-
else logger.debug(msg);
|
|
1545
|
+
logger.debug(msg);
|
|
1645
1546
|
},
|
|
1646
1547
|
feedback: feedbackEnabled
|
|
1647
1548
|
});
|
|
@@ -1656,9 +1557,9 @@ async function runWorkflowWithControllers(config) {
|
|
|
1656
1557
|
backend: agentDef.backend,
|
|
1657
1558
|
model: agentDef.model
|
|
1658
1559
|
});
|
|
1560
|
+
const agentLogger = logger.child(agentName);
|
|
1659
1561
|
const backendDebugLog = (msg) => {
|
|
1660
|
-
|
|
1661
|
-
else logger.debug(msg);
|
|
1562
|
+
agentLogger.debug(msg);
|
|
1662
1563
|
};
|
|
1663
1564
|
let backend;
|
|
1664
1565
|
if (createBackend) backend = createBackend(agentName, agentDef);
|
|
@@ -1694,7 +1595,19 @@ async function runWorkflowWithControllers(config) {
|
|
|
1694
1595
|
logger.debug("Sending kickoff message...");
|
|
1695
1596
|
await runtime.sendKickoff();
|
|
1696
1597
|
logger.debug("Kickoff sent");
|
|
1697
|
-
|
|
1598
|
+
let channelWatcher;
|
|
1599
|
+
if (config.prettyDisplay) {
|
|
1600
|
+
const { startPrettyDisplay } = await import("./display-pretty-BL9H2ocr.mjs");
|
|
1601
|
+
channelWatcher = startPrettyDisplay({
|
|
1602
|
+
contextProvider: runtime.contextProvider,
|
|
1603
|
+
agentNames: runtime.agentNames,
|
|
1604
|
+
workflowName,
|
|
1605
|
+
tag,
|
|
1606
|
+
workflowPath: config.workflowPath,
|
|
1607
|
+
initialCursor: channelStart,
|
|
1608
|
+
pollInterval: 250
|
|
1609
|
+
});
|
|
1610
|
+
} else channelWatcher = startChannelWatcher({
|
|
1698
1611
|
contextProvider: runtime.contextProvider,
|
|
1699
1612
|
agentNames: runtime.agentNames,
|
|
1700
1613
|
log,
|
|
@@ -1789,4 +1702,4 @@ function sleep(ms) {
|
|
|
1789
1702
|
}
|
|
1790
1703
|
|
|
1791
1704
|
//#endregion
|
|
1792
|
-
export { parseWorkflowFile, runWorkflowWithControllers };
|
|
1705
|
+
export { parseWorkflowFile, runWorkflowWithControllers, shutdownControllers };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"prepublishOnly": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@clack/prompts": "^1.0.0",
|
|
33
34
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
34
35
|
"ai": "^6.0.69",
|
|
35
36
|
"bash-tool": "^1.3.12",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"execa": "^9.6.1",
|
|
39
40
|
"just-bash": "^2.8.0",
|
|
40
41
|
"nanoid": "^5.1.6",
|
|
42
|
+
"picocolors": "^1.1.1",
|
|
41
43
|
"string-width": "^8.1.1",
|
|
42
44
|
"wrap-ansi": "^9.0.2",
|
|
43
45
|
"yaml": "^2.7.0",
|
|
@@ -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 };
|