joonecli 0.2.0 → 0.2.1
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/__tests__/config.test.js +1 -0
- package/dist/__tests__/config.test.js.map +1 -1
- package/dist/__tests__/installHostDeps.test.js +45 -0
- package/dist/__tests__/installHostDeps.test.js.map +1 -0
- package/dist/__tests__/whitelistedBackend.test.js +18 -0
- package/dist/__tests__/whitelistedBackend.test.js.map +1 -0
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.js +1 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +84 -100
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agentLoop.d.ts +10 -29
- package/dist/core/agentLoop.js +66 -237
- package/dist/core/agentLoop.js.map +1 -1
- package/dist/core/promptBuilder.js.map +1 -1
- package/dist/hitl/bridge.js +1 -27
- package/dist/hitl/bridge.js.map +1 -1
- package/dist/middleware/loopDetection.d.ts +7 -23
- package/dist/middleware/loopDetection.js +38 -42
- package/dist/middleware/loopDetection.js.map +1 -1
- package/dist/sandbox/whitelistedBackend.d.ts +5 -0
- package/dist/sandbox/whitelistedBackend.js +27 -0
- package/dist/sandbox/whitelistedBackend.js.map +1 -0
- package/dist/tools/askUser.d.ts +12 -3
- package/dist/tools/askUser.js +16 -28
- package/dist/tools/askUser.js.map +1 -1
- package/dist/tools/bashTool.d.ts +11 -0
- package/dist/tools/bashTool.js +51 -0
- package/dist/tools/bashTool.js.map +1 -0
- package/dist/tools/index.d.ts +15 -28
- package/dist/tools/index.js +9 -189
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/installHostDeps.d.ts +8 -2
- package/dist/tools/installHostDeps.js +38 -31
- package/dist/tools/installHostDeps.js.map +1 -1
- package/dist/ui/App.js +112 -56
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/MessageBubble.js +1 -1
- package/dist/ui/components/MessageBubble.js.map +1 -1
- package/package.json +7 -2
- package/dist/__tests__/m55.test.js +0 -160
- package/dist/__tests__/m55.test.js.map +0 -1
- package/dist/__tests__/middleware.test.js +0 -169
- package/dist/__tests__/middleware.test.js.map +0 -1
- package/dist/__tests__/optimizations.test.d.ts +0 -1
- package/dist/__tests__/optimizations.test.js +0 -136
- package/dist/__tests__/optimizations.test.js.map +0 -1
- package/dist/__tests__/security.test.d.ts +0 -1
- package/dist/__tests__/security.test.js +0 -86
- package/dist/__tests__/security.test.js.map +0 -1
- package/dist/__tests__/streaming.test.d.ts +0 -1
- package/dist/__tests__/streaming.test.js +0 -71
- package/dist/__tests__/streaming.test.js.map +0 -1
- package/dist/__tests__/toolRouter.test.d.ts +0 -1
- package/dist/__tests__/toolRouter.test.js +0 -37
- package/dist/__tests__/toolRouter.test.js.map +0 -1
- package/dist/__tests__/tools.test.d.ts +0 -1
- package/dist/__tests__/tools.test.js +0 -112
- package/dist/__tests__/tools.test.js.map +0 -1
- package/dist/core/subAgent.d.ts +0 -56
- package/dist/core/subAgent.js +0 -240
- package/dist/core/subAgent.js.map +0 -1
- package/dist/debug_google.d.ts +0 -1
- package/dist/debug_google.js +0 -23
- package/dist/debug_google.js.map +0 -1
- package/dist/middleware/commandSanitizer.d.ts +0 -18
- package/dist/middleware/commandSanitizer.js +0 -50
- package/dist/middleware/commandSanitizer.js.map +0 -1
- package/dist/middleware/permission.d.ts +0 -17
- package/dist/middleware/permission.js +0 -60
- package/dist/middleware/permission.js.map +0 -1
- package/dist/middleware/pipeline.d.ts +0 -31
- package/dist/middleware/pipeline.js +0 -62
- package/dist/middleware/pipeline.js.map +0 -1
- package/dist/middleware/preCompletion.d.ts +0 -29
- package/dist/middleware/preCompletion.js +0 -82
- package/dist/middleware/preCompletion.js.map +0 -1
- package/dist/middleware/types.d.ts +0 -40
- package/dist/middleware/types.js +0 -8
- package/dist/middleware/types.js.map +0 -1
- package/dist/skills/loader.d.ts +0 -55
- package/dist/skills/loader.js +0 -132
- package/dist/skills/loader.js.map +0 -1
- package/dist/skills/tools.d.ts +0 -5
- package/dist/skills/tools.js +0 -78
- package/dist/skills/tools.js.map +0 -1
- package/dist/test_cache.d.ts +0 -1
- package/dist/test_cache.js +0 -55
- package/dist/test_cache.js.map +0 -1
- package/dist/test_google.d.ts +0 -1
- package/dist/test_google.js +0 -36
- package/dist/test_google.js.map +0 -1
- package/dist/tools/browser.d.ts +0 -19
- package/dist/tools/browser.js +0 -114
- package/dist/tools/browser.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -31
- package/dist/tools/registry.js +0 -168
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/router.d.ts +0 -34
- package/dist/tools/router.js +0 -76
- package/dist/tools/router.js.map +0 -1
- package/dist/tools/security.d.ts +0 -28
- package/dist/tools/security.js +0 -183
- package/dist/tools/security.js.map +0 -1
- package/dist/tools/spawnAgent.d.ts +0 -19
- package/dist/tools/spawnAgent.js +0 -132
- package/dist/tools/spawnAgent.js.map +0 -1
- package/dist/tools/webSearch.d.ts +0 -6
- package/dist/tools/webSearch.js +0 -120
- package/dist/tools/webSearch.js.map +0 -1
- /package/dist/__tests__/{m55.test.d.ts → installHostDeps.test.d.ts} +0 -0
- /package/dist/__tests__/{middleware.test.d.ts → whitelistedBackend.test.d.ts} +0 -0
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import * as fs from "node:fs";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import * as os from "node:os";
|
|
5
|
-
import { ReadFileTool, WriteFileTool } from "../tools/index.js";
|
|
6
|
-
describe("ReadFileTool", () => {
|
|
7
|
-
let tmpDir;
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
tmpDir = fs.mkdtempSync(path.join(process.cwd(), ".joone-tools-test-"));
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
// ─── Test #27: Reads a normal file ───
|
|
15
|
-
it("reads a small file and returns its content", async () => {
|
|
16
|
-
const filePath = path.join(tmpDir, "hello.txt");
|
|
17
|
-
fs.writeFileSync(filePath, "Hello, world!", "utf-8");
|
|
18
|
-
const result = await ReadFileTool.execute({ path: filePath });
|
|
19
|
-
expect(result.content).toBe("Hello, world!");
|
|
20
|
-
});
|
|
21
|
-
// ─── Test #28: Returns error for non-existent file ───
|
|
22
|
-
it("returns an error message for a non-existent file", async () => {
|
|
23
|
-
const result = await ReadFileTool.execute({
|
|
24
|
-
path: path.join(tmpDir, "nope.txt"),
|
|
25
|
-
});
|
|
26
|
-
expect(result.content).toMatch(/not found/i);
|
|
27
|
-
});
|
|
28
|
-
// ─── Test #29: File size guardrail rejects files over 512KB ───
|
|
29
|
-
it("rejects files larger than 512KB with a descriptive error", async () => {
|
|
30
|
-
const filePath = path.join(tmpDir, "big.txt");
|
|
31
|
-
// Create a 600KB file
|
|
32
|
-
const bigContent = "x".repeat(600 * 1024);
|
|
33
|
-
fs.writeFileSync(filePath, bigContent, "utf-8");
|
|
34
|
-
const result = await ReadFileTool.execute({ path: filePath });
|
|
35
|
-
expect(result.content).toMatch(/too large/i);
|
|
36
|
-
expect(result.content).toMatch(/512/);
|
|
37
|
-
});
|
|
38
|
-
// ─── Test #30: Line range slicing works ───
|
|
39
|
-
it("returns only the requested line range", async () => {
|
|
40
|
-
const filePath = path.join(tmpDir, "lines.txt");
|
|
41
|
-
const lines = Array.from({ length: 20 }, (_, i) => `Line ${i + 1}`);
|
|
42
|
-
fs.writeFileSync(filePath, lines.join("\n"), "utf-8");
|
|
43
|
-
const result = await ReadFileTool.execute({
|
|
44
|
-
path: filePath,
|
|
45
|
-
startLine: 5,
|
|
46
|
-
endLine: 7,
|
|
47
|
-
});
|
|
48
|
-
expect(result.content).toContain("5: Line 5");
|
|
49
|
-
expect(result.content).toContain("6: Line 6");
|
|
50
|
-
expect(result.content).toContain("7: Line 7");
|
|
51
|
-
expect(result.content).not.toContain("4: Line 4");
|
|
52
|
-
expect(result.content).not.toContain("8: Line 8");
|
|
53
|
-
});
|
|
54
|
-
// ─── Test #31: Line count guardrail truncates long files ───
|
|
55
|
-
it("truncates files with more than 2000 lines", async () => {
|
|
56
|
-
const filePath = path.join(tmpDir, "long.txt");
|
|
57
|
-
// Create a file with 2500 short lines (under 512KB)
|
|
58
|
-
const lines = Array.from({ length: 2500 }, (_, i) => `L${i + 1}`);
|
|
59
|
-
fs.writeFileSync(filePath, lines.join("\n"), "utf-8");
|
|
60
|
-
const result = await ReadFileTool.execute({ path: filePath });
|
|
61
|
-
expect(result.content).toMatch(/truncated at 2000 lines/i);
|
|
62
|
-
expect(result.content).toContain("1: L1");
|
|
63
|
-
expect(result.content).toContain("2000: L2000");
|
|
64
|
-
expect(result.content).not.toContain("2001: L2001");
|
|
65
|
-
});
|
|
66
|
-
// ─── Test #X: Security Guardrail Blocks Outside Files ───
|
|
67
|
-
it("blocks reading files outside the project workspace", async () => {
|
|
68
|
-
// Create a file in the OS tmp directory (guaranteed outside project workspace)
|
|
69
|
-
const outsideDir = fs.mkdtempSync(path.join(os.tmpdir(), "joone-outside-"));
|
|
70
|
-
const filePath = path.join(outsideDir, "secret.txt");
|
|
71
|
-
fs.writeFileSync(filePath, "secret token", "utf-8");
|
|
72
|
-
try {
|
|
73
|
-
const result = await ReadFileTool.execute({ path: filePath });
|
|
74
|
-
expect(result.isError).toBe(true);
|
|
75
|
-
expect(result.content).toMatch(/Security Error: Access Denied/i);
|
|
76
|
-
expect(result.content).toMatch(/outside the current project workspace/i);
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
fs.rmSync(outsideDir, { recursive: true, force: true });
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
describe("WriteFileTool", () => {
|
|
84
|
-
let tmpDir;
|
|
85
|
-
beforeEach(() => {
|
|
86
|
-
tmpDir = fs.mkdtempSync(path.join(process.cwd(), ".joone-write-test-"));
|
|
87
|
-
});
|
|
88
|
-
afterEach(() => {
|
|
89
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
90
|
-
});
|
|
91
|
-
// ─── Test #32: Writes a file to disk ───
|
|
92
|
-
it("writes content to a file and confirms", async () => {
|
|
93
|
-
const filePath = path.join(tmpDir, "output.ts");
|
|
94
|
-
const result = await WriteFileTool.execute({
|
|
95
|
-
path: filePath,
|
|
96
|
-
content: "const x = 42;",
|
|
97
|
-
});
|
|
98
|
-
expect(result.content).toMatch(/file written/i);
|
|
99
|
-
expect(fs.readFileSync(filePath, "utf-8")).toBe("const x = 42;");
|
|
100
|
-
});
|
|
101
|
-
// ─── Test #33: Creates parent directories if needed ───
|
|
102
|
-
it("creates parent directories if they do not exist", async () => {
|
|
103
|
-
const filePath = path.join(tmpDir, "nested", "deep", "file.ts");
|
|
104
|
-
const result = await WriteFileTool.execute({
|
|
105
|
-
path: filePath,
|
|
106
|
-
content: "export {}",
|
|
107
|
-
});
|
|
108
|
-
expect(result.content).toMatch(/file written/i);
|
|
109
|
-
expect(fs.existsSync(filePath)).toBe(true);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
//# sourceMappingURL=tools.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../src/__tests__/tools.test.ts"],"names":[],"mappings":"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"}
|
package/dist/core/subAgent.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sub-Agent Manager
|
|
3
|
-
*
|
|
4
|
-
* Spawns and orchestrates isolated sub-agents for scoped tasks.
|
|
5
|
-
* Each sub-agent gets its own ExecutionHarness with a separate conversation
|
|
6
|
-
* history. Only the final SubAgentResult is returned to the main agent,
|
|
7
|
-
* discarding the sub-agent's internal conversation to save context.
|
|
8
|
-
*
|
|
9
|
-
* Supports both synchronous (blocking) and asynchronous (non-blocking) modes.
|
|
10
|
-
*
|
|
11
|
-
* Safety:
|
|
12
|
-
* - Depth limit of 1: sub-agents cannot spawn other sub-agents
|
|
13
|
-
* - maxTurns cap per agent prevents doom-loops
|
|
14
|
-
* - Concurrent async agent cap of 3 prevents resource exhaustion
|
|
15
|
-
* - Per-agent token budget tracking
|
|
16
|
-
*/
|
|
17
|
-
import { SubAgentResult } from "../agents/agentSpec.js";
|
|
18
|
-
import { AgentRegistry } from "../agents/agentRegistry.js";
|
|
19
|
-
import { DynamicToolInterface } from "../tools/index.js";
|
|
20
|
-
import { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
21
|
-
import { Runnable } from "@langchain/core/runnables";
|
|
22
|
-
export declare class SubAgentManager {
|
|
23
|
-
private registry;
|
|
24
|
-
private allTools;
|
|
25
|
-
private llm;
|
|
26
|
-
private asyncTasks;
|
|
27
|
-
private taskCounter;
|
|
28
|
-
constructor(registry: AgentRegistry, tools: DynamicToolInterface[], llm: Runnable | BaseChatModel);
|
|
29
|
-
/**
|
|
30
|
-
* Synchronous spawn — blocks until the sub-agent finishes.
|
|
31
|
-
*/
|
|
32
|
-
spawn(agentName: string, task: string, maxTurnsOverride?: number): Promise<SubAgentResult>;
|
|
33
|
-
/**
|
|
34
|
-
* Asynchronous spawn — returns immediately with a taskId.
|
|
35
|
-
* The main agent can poll with getResult(taskId).
|
|
36
|
-
*/
|
|
37
|
-
spawnAsync(agentName: string, task: string, maxTurnsOverride?: number): Promise<string>;
|
|
38
|
-
/**
|
|
39
|
-
* Check the status or get the result of an async task.
|
|
40
|
-
* Returns the result if completed, or a status message if still running.
|
|
41
|
-
*/
|
|
42
|
-
getResult(taskId: string): Promise<SubAgentResult | string>;
|
|
43
|
-
/**
|
|
44
|
-
* Core execution loop for a sub-agent.
|
|
45
|
-
* Creates an isolated conversation and runs a multi-turn loop.
|
|
46
|
-
*/
|
|
47
|
-
private runAgent;
|
|
48
|
-
/**
|
|
49
|
-
* Creates an error SubAgentResult.
|
|
50
|
-
*/
|
|
51
|
-
private makeErrorResult;
|
|
52
|
-
/**
|
|
53
|
-
* Clean up expired async tasks.
|
|
54
|
-
*/
|
|
55
|
-
private cleanupExpired;
|
|
56
|
-
}
|
package/dist/core/subAgent.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sub-Agent Manager
|
|
3
|
-
*
|
|
4
|
-
* Spawns and orchestrates isolated sub-agents for scoped tasks.
|
|
5
|
-
* Each sub-agent gets its own ExecutionHarness with a separate conversation
|
|
6
|
-
* history. Only the final SubAgentResult is returned to the main agent,
|
|
7
|
-
* discarding the sub-agent's internal conversation to save context.
|
|
8
|
-
*
|
|
9
|
-
* Supports both synchronous (blocking) and asynchronous (non-blocking) modes.
|
|
10
|
-
*
|
|
11
|
-
* Safety:
|
|
12
|
-
* - Depth limit of 1: sub-agents cannot spawn other sub-agents
|
|
13
|
-
* - maxTurns cap per agent prevents doom-loops
|
|
14
|
-
* - Concurrent async agent cap of 3 prevents resource exhaustion
|
|
15
|
-
* - Per-agent token budget tracking
|
|
16
|
-
*/
|
|
17
|
-
import { countMessageTokens } from "../core/tokenCounter.js";
|
|
18
|
-
import { HumanMessage, ToolMessage } from "@langchain/core/messages";
|
|
19
|
-
// ─── Constants ──────────────────────────────────────────────────────────────────
|
|
20
|
-
const DEFAULT_MAX_TURNS = 10;
|
|
21
|
-
const MAX_CONCURRENT_ASYNC = 3;
|
|
22
|
-
const ASYNC_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes
|
|
23
|
-
// ─── SubAgentManager ────────────────────────────────────────────────────────────
|
|
24
|
-
export class SubAgentManager {
|
|
25
|
-
registry;
|
|
26
|
-
allTools;
|
|
27
|
-
llm;
|
|
28
|
-
asyncTasks = new Map();
|
|
29
|
-
taskCounter = 0;
|
|
30
|
-
constructor(registry, tools, llm) {
|
|
31
|
-
this.registry = registry;
|
|
32
|
-
// Filter out spawn_agent and check_agent to prevent recursive nesting (depth-1 limit)
|
|
33
|
-
this.allTools = tools.filter((t) => t.name !== "spawn_agent" && t.name !== "check_agent");
|
|
34
|
-
this.llm = llm;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Synchronous spawn — blocks until the sub-agent finishes.
|
|
38
|
-
*/
|
|
39
|
-
async spawn(agentName, task, maxTurnsOverride) {
|
|
40
|
-
const spec = this.registry.get(agentName);
|
|
41
|
-
if (!spec) {
|
|
42
|
-
return this.makeErrorResult(agentName, task, `Unknown agent "${agentName}". Available: ${this.registry.getNames().join(", ")}`);
|
|
43
|
-
}
|
|
44
|
-
return this.runAgent(spec, task, maxTurnsOverride);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Asynchronous spawn — returns immediately with a taskId.
|
|
48
|
-
* The main agent can poll with getResult(taskId).
|
|
49
|
-
*/
|
|
50
|
-
async spawnAsync(agentName, task, maxTurnsOverride) {
|
|
51
|
-
// Cap concurrent async agents
|
|
52
|
-
this.cleanupExpired();
|
|
53
|
-
const activeCount = Array.from(this.asyncTasks.values())
|
|
54
|
-
.filter((t) => !t.completed).length;
|
|
55
|
-
if (activeCount >= MAX_CONCURRENT_ASYNC) {
|
|
56
|
-
throw new Error(`Maximum concurrent async agents reached (${MAX_CONCURRENT_ASYNC}). ` +
|
|
57
|
-
`Wait for existing tasks to complete or check them with check_agent.`);
|
|
58
|
-
}
|
|
59
|
-
const spec = this.registry.get(agentName);
|
|
60
|
-
if (!spec) {
|
|
61
|
-
throw new Error(`Unknown agent "${agentName}". Available: ${this.registry.getNames().join(", ")}`);
|
|
62
|
-
}
|
|
63
|
-
const taskId = `task_${++this.taskCounter}_${Date.now()}`;
|
|
64
|
-
const promise = this.runAgent(spec, task, maxTurnsOverride).then((result) => {
|
|
65
|
-
const asyncTask = this.asyncTasks.get(taskId);
|
|
66
|
-
if (asyncTask) {
|
|
67
|
-
asyncTask.result = result;
|
|
68
|
-
asyncTask.completed = true;
|
|
69
|
-
}
|
|
70
|
-
return result;
|
|
71
|
-
});
|
|
72
|
-
this.asyncTasks.set(taskId, {
|
|
73
|
-
taskId,
|
|
74
|
-
agentName,
|
|
75
|
-
taskDescription: task,
|
|
76
|
-
promise,
|
|
77
|
-
startedAt: Date.now(),
|
|
78
|
-
completed: false,
|
|
79
|
-
});
|
|
80
|
-
return taskId;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Check the status or get the result of an async task.
|
|
84
|
-
* Returns the result if completed, or a status message if still running.
|
|
85
|
-
*/
|
|
86
|
-
async getResult(taskId) {
|
|
87
|
-
const asyncTask = this.asyncTasks.get(taskId);
|
|
88
|
-
if (!asyncTask) {
|
|
89
|
-
return `Unknown task ID: ${taskId}. No such async task exists.`;
|
|
90
|
-
}
|
|
91
|
-
if (asyncTask.completed && asyncTask.result) {
|
|
92
|
-
// Clean up the task
|
|
93
|
-
this.asyncTasks.delete(taskId);
|
|
94
|
-
return asyncTask.result;
|
|
95
|
-
}
|
|
96
|
-
const elapsed = Math.round((Date.now() - asyncTask.startedAt) / 1000);
|
|
97
|
-
return `Task "${asyncTask.taskDescription}" (agent: ${asyncTask.agentName}) ` +
|
|
98
|
-
`is still running (${elapsed}s elapsed).`;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Core execution loop for a sub-agent.
|
|
102
|
-
* Creates an isolated conversation and runs a multi-turn loop.
|
|
103
|
-
*/
|
|
104
|
-
async runAgent(spec, task, maxTurnsOverride) {
|
|
105
|
-
const startTime = Date.now();
|
|
106
|
-
const maxTurns = maxTurnsOverride ?? spec.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
107
|
-
// Resolve available tools for this agent
|
|
108
|
-
const agentTools = spec.tools
|
|
109
|
-
? this.allTools.filter((t) => spec.tools.includes(t.name))
|
|
110
|
-
: this.allTools;
|
|
111
|
-
// Create isolated conversation history
|
|
112
|
-
const systemPrompt = new HumanMessage(`<system-directive>\n${spec.systemPrompt}\n\n--- Current Task ---\n${task}\n</system-directive>`);
|
|
113
|
-
const history = [
|
|
114
|
-
new HumanMessage(task),
|
|
115
|
-
];
|
|
116
|
-
let promptTokens = 0;
|
|
117
|
-
let completionTokens = 0;
|
|
118
|
-
let toolCallCount = 0;
|
|
119
|
-
let turnsUsed = 0;
|
|
120
|
-
let lastResponse = "";
|
|
121
|
-
const filesModified = new Set();
|
|
122
|
-
// Build LangChain tool declarations for binding
|
|
123
|
-
const toolDeclarations = agentTools.map((t) => ({
|
|
124
|
-
name: t.name,
|
|
125
|
-
description: t.description,
|
|
126
|
-
schema: t.schema,
|
|
127
|
-
}));
|
|
128
|
-
try {
|
|
129
|
-
// Bind tools to the LLM for this sub-agent session
|
|
130
|
-
let boundLlm;
|
|
131
|
-
if ("bindTools" in this.llm && typeof this.llm.bindTools === "function") {
|
|
132
|
-
boundLlm = this.llm.bindTools(toolDeclarations);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
boundLlm = this.llm;
|
|
136
|
-
}
|
|
137
|
-
for (let turn = 0; turn < maxTurns; turn++) {
|
|
138
|
-
turnsUsed++;
|
|
139
|
-
// Build the full message array
|
|
140
|
-
const messages = [systemPrompt, ...history];
|
|
141
|
-
const stepPromptTokens = countMessageTokens(messages);
|
|
142
|
-
promptTokens += stepPromptTokens;
|
|
143
|
-
// Invoke the LLM
|
|
144
|
-
const response = await boundLlm.invoke(messages);
|
|
145
|
-
const responseTokens = countMessageTokens([response]);
|
|
146
|
-
completionTokens += responseTokens;
|
|
147
|
-
const aiMessage = response;
|
|
148
|
-
history.push(aiMessage);
|
|
149
|
-
// Extract text content
|
|
150
|
-
if (typeof aiMessage.content === "string" && aiMessage.content.length > 0) {
|
|
151
|
-
lastResponse = aiMessage.content;
|
|
152
|
-
}
|
|
153
|
-
// Check for tool calls
|
|
154
|
-
if (!aiMessage.tool_calls || aiMessage.tool_calls.length === 0) {
|
|
155
|
-
// No tool calls — agent is done
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
// Execute tool calls
|
|
159
|
-
for (const call of aiMessage.tool_calls) {
|
|
160
|
-
if (!call.id)
|
|
161
|
-
continue;
|
|
162
|
-
const tool = agentTools.find((t) => t.name === call.name);
|
|
163
|
-
if (!tool) {
|
|
164
|
-
history.push(new ToolMessage({
|
|
165
|
-
content: `Error: Tool "${call.name}" is not available to this sub-agent.`,
|
|
166
|
-
tool_call_id: call.id,
|
|
167
|
-
}));
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
toolCallCount++;
|
|
171
|
-
try {
|
|
172
|
-
const result = await tool.execute(call.args);
|
|
173
|
-
const output = typeof result === "string" ? result : result.content;
|
|
174
|
-
// Track file modifications
|
|
175
|
-
if (call.name === "write_file" && call.args?.path) {
|
|
176
|
-
filesModified.add(call.args.path);
|
|
177
|
-
}
|
|
178
|
-
history.push(new ToolMessage({
|
|
179
|
-
content: output,
|
|
180
|
-
tool_call_id: call.id,
|
|
181
|
-
}));
|
|
182
|
-
}
|
|
183
|
-
catch (err) {
|
|
184
|
-
history.push(new ToolMessage({
|
|
185
|
-
content: `Tool error: ${err.message}`,
|
|
186
|
-
tool_call_id: call.id,
|
|
187
|
-
}));
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// Determine outcome
|
|
192
|
-
const outcome = turnsUsed >= maxTurns ? "partial" : "success";
|
|
193
|
-
return {
|
|
194
|
-
agentName: spec.name,
|
|
195
|
-
taskDescription: task,
|
|
196
|
-
outcome,
|
|
197
|
-
result: lastResponse || "(Sub-agent produced no text output)",
|
|
198
|
-
filesModified: Array.from(filesModified),
|
|
199
|
-
toolCallCount,
|
|
200
|
-
tokenUsage: { prompt: promptTokens, completion: completionTokens },
|
|
201
|
-
duration: Date.now() - startTime,
|
|
202
|
-
turnsUsed,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
catch (error) {
|
|
206
|
-
return this.makeErrorResult(spec.name, task, `Sub-agent error: ${error.message}`, { promptTokens, completionTokens, toolCallCount, turnsUsed, startTime, filesModified });
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Creates an error SubAgentResult.
|
|
211
|
-
*/
|
|
212
|
-
makeErrorResult(agentName, task, errorMsg, partial) {
|
|
213
|
-
return {
|
|
214
|
-
agentName,
|
|
215
|
-
taskDescription: task,
|
|
216
|
-
outcome: "failure",
|
|
217
|
-
result: errorMsg,
|
|
218
|
-
filesModified: partial ? Array.from(partial.filesModified) : [],
|
|
219
|
-
toolCallCount: partial?.toolCallCount ?? 0,
|
|
220
|
-
tokenUsage: {
|
|
221
|
-
prompt: partial?.promptTokens ?? 0,
|
|
222
|
-
completion: partial?.completionTokens ?? 0,
|
|
223
|
-
},
|
|
224
|
-
duration: partial ? Date.now() - partial.startTime : 0,
|
|
225
|
-
turnsUsed: partial?.turnsUsed ?? 0,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Clean up expired async tasks.
|
|
230
|
-
*/
|
|
231
|
-
cleanupExpired() {
|
|
232
|
-
const now = Date.now();
|
|
233
|
-
for (const [taskId, task] of this.asyncTasks.entries()) {
|
|
234
|
-
if (now - task.startedAt > ASYNC_EXPIRY_MS) {
|
|
235
|
-
this.asyncTasks.delete(taskId);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
//# sourceMappingURL=subAgent.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subAgent.js","sourceRoot":"","sources":["../../src/core/subAgent.ts"],"names":[],"mappings":"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"}
|
package/dist/debug_google.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/debug_google.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { ExecutionHarness } from "./core/agentLoop.js";
|
|
2
|
-
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
|
3
|
-
import { HumanMessage } from "@langchain/core/messages";
|
|
4
|
-
async function run() {
|
|
5
|
-
const llm = new ChatGoogleGenerativeAI({ apiKey: "dummy-key", modelName: "gemini-1.5-pro" });
|
|
6
|
-
const harness = new ExecutionHarness(llm, [], undefined, undefined, "google", "gemini-1.5-pro");
|
|
7
|
-
const state = {
|
|
8
|
-
globalSystemInstructions: `You are Joone...`,
|
|
9
|
-
projectMemory: "No project context loaded yet.",
|
|
10
|
-
sessionContext: `Environment: test\nCWD: test`,
|
|
11
|
-
conversationHistory: [
|
|
12
|
-
new HumanMessage("Hello Google AI")
|
|
13
|
-
]
|
|
14
|
-
};
|
|
15
|
-
try {
|
|
16
|
-
await harness.step(state);
|
|
17
|
-
}
|
|
18
|
-
catch (e) {
|
|
19
|
-
console.error("Caught in harness:", e.message);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
run();
|
|
23
|
-
//# sourceMappingURL=debug_google.js.map
|
package/dist/debug_google.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"debug_google.js","sourceRoot":"","sources":["../src/debug_google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,KAAK,UAAU,GAAG;IAChB,MAAM,GAAG,GAAG,IAAI,sBAAsB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEhG,MAAM,KAAK,GAAG;QACZ,wBAAwB,EAAE,kBAAkB;QAC5C,aAAa,EAAE,gCAAgC;QAC/C,cAAc,EAAE,8BAA8B;QAC9C,mBAAmB,EAAE;YACnB,IAAI,YAAY,CAAC,iBAAiB,CAAC;SACpC;KACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,GAAG,EAAE,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ToolCallContext, ToolMiddleware } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Intercepts bash tool calls to block dangerous or interactive commands.
|
|
4
|
-
*
|
|
5
|
-
* Categories of blocked commands:
|
|
6
|
-
* 1. Destructive: `rm -rf /`, `mkfs`, `dd if=`, fork bombs
|
|
7
|
-
* 2. Interactive/hanging: `vim`, `nano`, `less`, `top`, `htop`, `man`
|
|
8
|
-
* 3. Network abuse: `curl | sh`, `wget | bash`
|
|
9
|
-
*/
|
|
10
|
-
export declare class CommandSanitizerMiddleware implements ToolMiddleware {
|
|
11
|
-
readonly name = "CommandSanitizer";
|
|
12
|
-
/**
|
|
13
|
-
* Patterns that will cause a command to be blocked.
|
|
14
|
-
* Each entry is [regex, human-readable reason].
|
|
15
|
-
*/
|
|
16
|
-
private readonly blockedPatterns;
|
|
17
|
-
before(ctx: ToolCallContext): ToolCallContext | string;
|
|
18
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Intercepts bash tool calls to block dangerous or interactive commands.
|
|
3
|
-
*
|
|
4
|
-
* Categories of blocked commands:
|
|
5
|
-
* 1. Destructive: `rm -rf /`, `mkfs`, `dd if=`, fork bombs
|
|
6
|
-
* 2. Interactive/hanging: `vim`, `nano`, `less`, `top`, `htop`, `man`
|
|
7
|
-
* 3. Network abuse: `curl | sh`, `wget | bash`
|
|
8
|
-
*/
|
|
9
|
-
export class CommandSanitizerMiddleware {
|
|
10
|
-
name = "CommandSanitizer";
|
|
11
|
-
/**
|
|
12
|
-
* Patterns that will cause a command to be blocked.
|
|
13
|
-
* Each entry is [regex, human-readable reason].
|
|
14
|
-
*/
|
|
15
|
-
blockedPatterns = [
|
|
16
|
-
// Destructive
|
|
17
|
-
[/rm\s+(-\w*r\w*f\w*|-\w*f\w*r\w*)\s+\/(\*)?(?:\s|$)/, "destructive: rm -rf /"],
|
|
18
|
-
[/mkfs\b/, "destructive: filesystem format"],
|
|
19
|
-
[/\bdd\s+.*of=\/dev\//, "destructive: raw disk write"],
|
|
20
|
-
[/chmod\s+(-\w+\s+)*777\s+\//, "dangerous: chmod 777 on root"],
|
|
21
|
-
// Interactive / hanging
|
|
22
|
-
[/\b(vim|vi|nano|emacs|pico)\b/, "interactive: text editor (hangs the sandbox)"],
|
|
23
|
-
[/\b(less|more)\b/, "interactive: pager (hangs the sandbox)"],
|
|
24
|
-
[/\b(top|htop|glances)\b/, "interactive: process monitor (hangs the sandbox)"],
|
|
25
|
-
[/\bman\s+\w+/, "interactive: man page (hangs the sandbox)"],
|
|
26
|
-
// Network abuse: pipe-to-shell
|
|
27
|
-
[/curl\s+.*\|\s*(sh|bash|zsh)/, "unsafe: pipe remote script to shell"],
|
|
28
|
-
[/wget\s+.*\|\s*(sh|bash|zsh)/, "unsafe: pipe remote script to shell"],
|
|
29
|
-
];
|
|
30
|
-
before(ctx) {
|
|
31
|
-
// Only applies to bash/shell tool calls
|
|
32
|
-
if (ctx.toolName !== "bash") {
|
|
33
|
-
return ctx;
|
|
34
|
-
}
|
|
35
|
-
const command = ctx.args.command;
|
|
36
|
-
if (typeof command !== "string") {
|
|
37
|
-
return ctx;
|
|
38
|
-
}
|
|
39
|
-
for (const [pattern, reason] of this.blockedPatterns) {
|
|
40
|
-
if (pattern.test(command)) {
|
|
41
|
-
return (`⚠ Blocked: Command rejected by sanitizer.\n` +
|
|
42
|
-
`Reason: ${reason}\n` +
|
|
43
|
-
`Command: ${command}\n` +
|
|
44
|
-
`Use a safer alternative or refine your approach.`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return ctx;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
//# sourceMappingURL=commandSanitizer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commandSanitizer.js","sourceRoot":"","sources":["../../src/middleware/commandSanitizer.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,OAAO,0BAA0B;IAC5B,IAAI,GAAG,kBAAkB,CAAC;IAEnC;;;OAGG;IACc,eAAe,GAAuB;QACrD,cAAc;QACd,CAAC,oDAAoD,EAAE,uBAAuB,CAAC;QAC/E,CAAC,QAAQ,EAAE,gCAAgC,CAAC;QAC5C,CAAC,qBAAqB,EAAE,6BAA6B,CAAC;QACtD,CAAC,4BAA4B,EAAE,8BAA8B,CAAC;QAE9D,wBAAwB;QACxB,CAAC,8BAA8B,EAAE,8CAA8C,CAAC;QAChF,CAAC,iBAAiB,EAAE,wCAAwC,CAAC;QAC7D,CAAC,wBAAwB,EAAE,kDAAkD,CAAC;QAC9E,CAAC,aAAa,EAAE,2CAA2C,CAAC;QAE5D,+BAA+B;QAC/B,CAAC,6BAA6B,EAAE,qCAAqC,CAAC;QACtE,CAAC,6BAA6B,EAAE,qCAAqC,CAAC;KACvE,CAAC;IAEF,MAAM,CAAC,GAAoB;QACzB,wCAAwC;QACxC,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,GAAG,CAAC;QACb,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACrD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,OAAO,CACL,6CAA6C;oBAC7C,WAAW,MAAM,IAAI;oBACrB,YAAY,OAAO,IAAI;oBACvB,kDAAkD,CACnD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ToolCallContext, ToolMiddleware } from "./types.js";
|
|
2
|
-
export type PermissionMode = "auto" | "ask_dangerous" | "ask_all";
|
|
3
|
-
/**
|
|
4
|
-
* PermissionMiddleware — gates dangerous tool calls behind user approval.
|
|
5
|
-
*
|
|
6
|
-
* Behavior per mode:
|
|
7
|
-
* - `auto`: All tools execute without asking. (Default for power users.)
|
|
8
|
-
* - `ask_dangerous`: Only tools in DANGEROUS_TOOLS require approval.
|
|
9
|
-
* - `ask_all`: Every tool except SAFE_TOOLS requires approval.
|
|
10
|
-
*/
|
|
11
|
-
export declare class PermissionMiddleware implements ToolMiddleware {
|
|
12
|
-
name: string;
|
|
13
|
-
private mode;
|
|
14
|
-
constructor(mode?: PermissionMode);
|
|
15
|
-
before(ctx: ToolCallContext): Promise<ToolCallContext | string | void>;
|
|
16
|
-
private requiresApproval;
|
|
17
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { HITLBridge } from "../hitl/bridge.js";
|
|
2
|
-
/** Tools that are always safe and never need user approval. */
|
|
3
|
-
const SAFE_TOOLS = new Set([
|
|
4
|
-
"read_file",
|
|
5
|
-
"view_file_outline",
|
|
6
|
-
"search_skills",
|
|
7
|
-
"load_skill",
|
|
8
|
-
"search_tools",
|
|
9
|
-
"ask_user_question", // Meta: the ask tool itself is always safe
|
|
10
|
-
]);
|
|
11
|
-
/** Tools that perform destructive or side-effect-heavy operations. */
|
|
12
|
-
const DANGEROUS_TOOLS = new Set([
|
|
13
|
-
"bash",
|
|
14
|
-
"write_file",
|
|
15
|
-
"replace_file_content",
|
|
16
|
-
"multi_replace_file_content",
|
|
17
|
-
"install_deps",
|
|
18
|
-
"install_host_dependencies",
|
|
19
|
-
]);
|
|
20
|
-
/**
|
|
21
|
-
* PermissionMiddleware — gates dangerous tool calls behind user approval.
|
|
22
|
-
*
|
|
23
|
-
* Behavior per mode:
|
|
24
|
-
* - `auto`: All tools execute without asking. (Default for power users.)
|
|
25
|
-
* - `ask_dangerous`: Only tools in DANGEROUS_TOOLS require approval.
|
|
26
|
-
* - `ask_all`: Every tool except SAFE_TOOLS requires approval.
|
|
27
|
-
*/
|
|
28
|
-
export class PermissionMiddleware {
|
|
29
|
-
name = "PermissionMiddleware";
|
|
30
|
-
mode;
|
|
31
|
-
constructor(mode = "auto") {
|
|
32
|
-
this.mode = mode;
|
|
33
|
-
}
|
|
34
|
-
async before(ctx) {
|
|
35
|
-
if (this.mode === "auto")
|
|
36
|
-
return ctx;
|
|
37
|
-
const toolName = ctx.toolName;
|
|
38
|
-
const needsApproval = this.requiresApproval(toolName);
|
|
39
|
-
if (!needsApproval)
|
|
40
|
-
return ctx;
|
|
41
|
-
const bridge = HITLBridge.getInstance();
|
|
42
|
-
const approved = await bridge.requestPermission(toolName, ctx.args);
|
|
43
|
-
if (!approved) {
|
|
44
|
-
// Short-circuit: return a string to deny the tool call
|
|
45
|
-
return (`Permission denied: The user declined to approve the execution of "${toolName}". ` +
|
|
46
|
-
`Try an alternative approach or ask the user for guidance using the ask_user_question tool.`);
|
|
47
|
-
}
|
|
48
|
-
return ctx;
|
|
49
|
-
}
|
|
50
|
-
requiresApproval(toolName) {
|
|
51
|
-
if (SAFE_TOOLS.has(toolName))
|
|
52
|
-
return false;
|
|
53
|
-
if (this.mode === "ask_all")
|
|
54
|
-
return true;
|
|
55
|
-
if (this.mode === "ask_dangerous")
|
|
56
|
-
return DANGEROUS_TOOLS.has(toolName);
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
//# sourceMappingURL=permission.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"permission.js","sourceRoot":"","sources":["../../src/middleware/permission.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/C,+DAA+D;AAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACvB,WAAW;IACX,mBAAmB;IACnB,eAAe;IACf,YAAY;IACZ,cAAc;IACd,mBAAmB,EAAE,2CAA2C;CACnE,CAAC,CAAC;AAEH,sEAAsE;AACtE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC5B,MAAM;IACN,YAAY;IACZ,sBAAsB;IACtB,4BAA4B;IAC5B,cAAc;IACd,2BAA2B;CAC9B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,OAAO,oBAAoB;IAC7B,IAAI,GAAG,sBAAsB,CAAC;IACtB,IAAI,CAAiB;IAE7B,YAAY,OAAuB,MAAM;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAoB;QAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,GAAG,CAAC;QAErC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAEtD,IAAI,CAAC,aAAa;YAAE,OAAO,GAAG,CAAC;QAE/B,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,uDAAuD;YACvD,OAAO,CACH,qEAAqE,QAAQ,KAAK;gBAClF,4FAA4F,CAC/F,CAAC;QACN,CAAC;QAED,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,QAAgB;QACrC,IAAI,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAE3C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe;YAAE,OAAO,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExE,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { ToolCallContext, ToolMiddleware } from "./types.js";
|
|
2
|
-
import { ToolResult } from "../tools/index.js";
|
|
3
|
-
/**
|
|
4
|
-
* Executes tool calls through a chain of middleware hooks.
|
|
5
|
-
*
|
|
6
|
-
* Execution flow:
|
|
7
|
-
* 1. Run all `before()` hooks in registration order.
|
|
8
|
-
* - If any returns a string → short-circuit (tool is NOT executed).
|
|
9
|
-
* 2. Execute the actual tool function.
|
|
10
|
-
* 3. Run all `after()` hooks in reverse registration order.
|
|
11
|
-
* - Each can transform the result before it enters conversation history.
|
|
12
|
-
*/
|
|
13
|
-
export declare class MiddlewarePipeline {
|
|
14
|
-
private middlewares;
|
|
15
|
-
/**
|
|
16
|
-
* Register a middleware. Middlewares run in the order they are added.
|
|
17
|
-
*/
|
|
18
|
-
use(middleware: ToolMiddleware): void;
|
|
19
|
-
/**
|
|
20
|
-
* Returns the number of registered middlewares.
|
|
21
|
-
*/
|
|
22
|
-
get length(): number;
|
|
23
|
-
/**
|
|
24
|
-
* Execute a tool call through the middleware pipeline.
|
|
25
|
-
*
|
|
26
|
-
* @param ctx - The tool call context (name, args, callId).
|
|
27
|
-
* @param executeFn - The actual tool execution function.
|
|
28
|
-
* @returns The final result string (possibly transformed by after-hooks).
|
|
29
|
-
*/
|
|
30
|
-
run(ctx: ToolCallContext, executeFn: (ctx: ToolCallContext) => Promise<ToolResult> | ToolResult): Promise<string>;
|
|
31
|
-
}
|