joonecli 0.1.1 → 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 -97
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/builtinCommands.js +6 -6
- package/dist/commands/builtinCommands.js.map +1 -1
- package/dist/commands/commandRegistry.d.ts +3 -1
- package/dist/commands/commandRegistry.js.map +1 -1
- package/dist/core/agentLoop.d.ts +11 -28
- package/dist/core/agentLoop.js +68 -229
- package/dist/core/agentLoop.js.map +1 -1
- package/dist/core/compactor.js +2 -2
- package/dist/core/compactor.js.map +1 -1
- package/dist/core/contextGuard.d.ts +5 -0
- package/dist/core/contextGuard.js +30 -3
- package/dist/core/contextGuard.js.map +1 -1
- package/dist/core/events.d.ts +45 -0
- package/dist/core/events.js +8 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/promptBuilder.js.map +1 -1
- package/dist/core/sessionStore.js +3 -2
- package/dist/core/sessionStore.js.map +1 -1
- package/dist/core/tokenCounter.d.ts +8 -1
- package/dist/core/tokenCounter.js +28 -0
- package/dist/core/tokenCounter.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 -27
- package/dist/tools/index.js +9 -181
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/installHostDeps.d.ts +8 -0
- package/dist/tools/installHostDeps.js +44 -0
- package/dist/tools/installHostDeps.js.map +1 -0
- package/dist/tracing/sessionTracer.d.ts +1 -0
- package/dist/tracing/sessionTracer.js +4 -1
- package/dist/tracing/sessionTracer.js.map +1 -1
- package/dist/ui/App.js +116 -55
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/ActionLog.d.ts +7 -0
- package/dist/ui/components/ActionLog.js +63 -0
- package/dist/ui/components/ActionLog.js.map +1 -0
- package/dist/ui/components/FileBrowser.d.ts +2 -0
- package/dist/ui/components/FileBrowser.js +41 -0
- package/dist/ui/components/FileBrowser.js.map +1 -0
- package/dist/ui/components/MessageBubble.js +1 -1
- package/dist/ui/components/MessageBubble.js.map +1 -1
- package/package.json +8 -5
- package/AGENTS.md +0 -56
- package/Handover.md +0 -115
- package/PROGRESS.md +0 -160
- 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 -59
- 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 -111
- 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 -75
- 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 -130
- 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/docs/01_insights_and_patterns.md +0 -27
- package/docs/02_edge_cases_and_mitigations.md +0 -143
- package/docs/03_initial_implementation_plan.md +0 -66
- package/docs/04_tech_stack_proposal.md +0 -20
- package/docs/05_prd.md +0 -87
- package/docs/06_user_stories.md +0 -72
- package/docs/07_system_architecture.md +0 -138
- package/docs/08_roadmap.md +0 -200
- package/e2b/Dockerfile +0 -26
- package/src/__tests__/bootstrap.test.ts +0 -111
- package/src/__tests__/config.test.ts +0 -97
- package/src/__tests__/m55.test.ts +0 -238
- package/src/__tests__/middleware.test.ts +0 -219
- package/src/__tests__/modelFactory.test.ts +0 -63
- package/src/__tests__/optimizations.test.ts +0 -201
- package/src/__tests__/promptBuilder.test.ts +0 -141
- package/src/__tests__/sandbox.test.ts +0 -102
- package/src/__tests__/security.test.ts +0 -122
- package/src/__tests__/streaming.test.ts +0 -82
- package/src/__tests__/toolRouter.test.ts +0 -52
- package/src/__tests__/tools.test.ts +0 -146
- package/src/__tests__/tracing.test.ts +0 -196
- package/src/agents/agentRegistry.ts +0 -69
- package/src/agents/agentSpec.ts +0 -67
- package/src/agents/builtinAgents.ts +0 -142
- package/src/cli/config.ts +0 -124
- package/src/cli/index.ts +0 -742
- package/src/cli/modelFactory.ts +0 -174
- package/src/cli/postinstall.ts +0 -28
- package/src/cli/providers.ts +0 -107
- package/src/commands/builtinCommands.ts +0 -293
- package/src/commands/commandRegistry.ts +0 -194
- package/src/core/agentLoop.d.ts.map +0 -1
- package/src/core/agentLoop.ts +0 -312
- package/src/core/autoSave.ts +0 -95
- package/src/core/compactor.ts +0 -252
- package/src/core/contextGuard.ts +0 -129
- package/src/core/errors.ts +0 -202
- package/src/core/promptBuilder.d.ts.map +0 -1
- package/src/core/promptBuilder.ts +0 -139
- package/src/core/reasoningRouter.ts +0 -121
- package/src/core/retry.ts +0 -75
- package/src/core/sessionResumer.ts +0 -90
- package/src/core/sessionStore.ts +0 -216
- package/src/core/subAgent.ts +0 -339
- package/src/core/tokenCounter.ts +0 -64
- package/src/evals/dataset.ts +0 -67
- package/src/evals/evaluator.ts +0 -81
- package/src/hitl/bridge.ts +0 -160
- package/src/middleware/commandSanitizer.ts +0 -60
- package/src/middleware/loopDetection.ts +0 -63
- package/src/middleware/permission.ts +0 -72
- package/src/middleware/pipeline.ts +0 -75
- package/src/middleware/preCompletion.ts +0 -94
- package/src/middleware/types.ts +0 -45
- package/src/sandbox/bootstrap.ts +0 -121
- package/src/sandbox/manager.ts +0 -239
- package/src/sandbox/sync.ts +0 -157
- package/src/skills/loader.ts +0 -143
- package/src/skills/tools.ts +0 -99
- package/src/skills/types.ts +0 -13
- package/src/test_cache.ts +0 -72
- package/src/tools/askUser.ts +0 -47
- package/src/tools/browser.ts +0 -137
- package/src/tools/index.d.ts.map +0 -1
- package/src/tools/index.ts +0 -237
- package/src/tools/registry.ts +0 -198
- package/src/tools/router.ts +0 -78
- package/src/tools/security.ts +0 -220
- package/src/tools/spawnAgent.ts +0 -158
- package/src/tools/webSearch.ts +0 -142
- package/src/tracing/analyzer.ts +0 -265
- package/src/tracing/langsmith.ts +0 -63
- package/src/tracing/sessionTracer.ts +0 -202
- package/src/tracing/types.ts +0 -49
- package/src/types/valyu.d.ts +0 -37
- package/src/ui/App.tsx +0 -404
- package/src/ui/components/HITLPrompt.tsx +0 -119
- package/src/ui/components/Header.tsx +0 -51
- package/src/ui/components/MessageBubble.tsx +0 -46
- package/src/ui/components/StatusBar.tsx +0 -138
- package/src/ui/components/StreamingText.tsx +0 -48
- package/src/ui/components/ToolCallPanel.tsx +0 -80
- package/tests/commands/commands.test.ts +0 -356
- package/tests/core/compactor.test.ts +0 -217
- package/tests/core/retryAndErrors.test.ts +0 -164
- package/tests/core/sessionResumer.test.ts +0 -95
- package/tests/core/sessionStore.test.ts +0 -84
- package/tests/core/stability.test.ts +0 -165
- package/tests/core/subAgent.test.ts +0 -238
- package/tests/hitl/hitlBridge.test.ts +0 -115
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -10
- package/vitest.out +0 -48
- /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
package/src/test_cache.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
|
-
import { ChatAnthropic } from "@langchain/anthropic";
|
|
3
|
-
import { ExecutionHarness } from "./core/agentLoop.js";
|
|
4
|
-
import { ContextState } from "./core/promptBuilder.js";
|
|
5
|
-
import { HumanMessage } from "@langchain/core/messages";
|
|
6
|
-
|
|
7
|
-
async function runCacheTest() {
|
|
8
|
-
console.log("=== Starting Prompt Caching Test ===\n");
|
|
9
|
-
|
|
10
|
-
// We need Anthropic API Key for this to actually hit the network and measure cache
|
|
11
|
-
if (!process.env.ANTHROPIC_API_KEY) {
|
|
12
|
-
console.warn("WARNING: ANTHROPIC_API_KEY is not set in .env file. The LLM call will fail.");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const model = new ChatAnthropic({
|
|
16
|
-
modelName: "claude-3-5-sonnet-20241022",
|
|
17
|
-
temperature: 0,
|
|
18
|
-
maxTokens: 4096,
|
|
19
|
-
}); // No tools needed for this basic string test
|
|
20
|
-
|
|
21
|
-
const harness = new ExecutionHarness(model, []);
|
|
22
|
-
|
|
23
|
-
// 1. Create a massive static prefix (simulating a lot of project context)
|
|
24
|
-
// We repeat a string many times to ensure we pass the 1024 token minimum for Anthropic caching.
|
|
25
|
-
const massiveProjectMemory = Array(500).fill("Project Rule: Always write clean, modular TypeScript code with strict typings. ").join("\n");
|
|
26
|
-
|
|
27
|
-
const state: ContextState = {
|
|
28
|
-
globalSystemInstructions: "You are a helpful coding assistant. You remember rules carefully.",
|
|
29
|
-
projectMemory: massiveProjectMemory,
|
|
30
|
-
sessionContext: "User OS: Windows 11",
|
|
31
|
-
conversationHistory: []
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
console.log("Turn 1: Initial Query (Should create cache)");
|
|
35
|
-
state.conversationHistory.push(new HumanMessage("Hello! What is one of the project rules?"));
|
|
36
|
-
|
|
37
|
-
const response1 = await harness.step(state);
|
|
38
|
-
state.conversationHistory.push(response1);
|
|
39
|
-
|
|
40
|
-
// In @langchain/anthropic, the actual usage stats (including cache hits/misses)
|
|
41
|
-
// are stored in the response_metadata of the AIMessage.
|
|
42
|
-
console.log(`Response 1: ${response1.content}`);
|
|
43
|
-
console.log(`Token Usage 1: ${JSON.stringify(response1.response_metadata?.usage, null, 2)}\n`);
|
|
44
|
-
|
|
45
|
-
// --- TURN 2 ---
|
|
46
|
-
console.log("Turn 2: Follow-up Query (Should hit cache)");
|
|
47
|
-
// We DO NOT change the globalSystemInstructions, projectMemory, or sessionContext.
|
|
48
|
-
// We only append to the conversation history. This preserves the prefix!
|
|
49
|
-
state.conversationHistory.push(new HumanMessage("Could you summarize the rule again briefly?"));
|
|
50
|
-
|
|
51
|
-
const response2 = await harness.step(state);
|
|
52
|
-
state.conversationHistory.push(response2);
|
|
53
|
-
|
|
54
|
-
console.log(`Response 2: ${response2.content}`);
|
|
55
|
-
console.log(`Token Usage 2: ${JSON.stringify(response2.response_metadata?.usage, null, 2)}\n`);
|
|
56
|
-
|
|
57
|
-
// --- TURN 3: The System Reminder Pattern ---
|
|
58
|
-
console.log("Turn 3: Using <system-reminder> to simulate environment change without breaking cache");
|
|
59
|
-
// If a file changed, we DON'T update `state.projectMemory`. We inject a reminder.
|
|
60
|
-
state.conversationHistory.push(new HumanMessage(
|
|
61
|
-
"<system-reminder>\nThe file 'auth.ts' has just been deleted by the user.\n</system-reminder>\nWhat should we do if we need auth now?"
|
|
62
|
-
));
|
|
63
|
-
|
|
64
|
-
const response3 = await harness.step(state);
|
|
65
|
-
state.conversationHistory.push(response3);
|
|
66
|
-
|
|
67
|
-
console.log(`Response 3: ${response3.content}`);
|
|
68
|
-
console.log(`Token Usage 3: ${JSON.stringify(response3.response_metadata?.usage, null, 2)}\n`);}
|
|
69
|
-
|
|
70
|
-
if (require.main === module) {
|
|
71
|
-
runCacheTest().catch(console.error);
|
|
72
|
-
}
|
package/src/tools/askUser.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { HITLBridge } from "../hitl/bridge.js";
|
|
2
|
-
import { DynamicToolInterface, ToolResult } from "./index.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* AskUserQuestionTool — allows the agent to ask the user a clarifying question mid-turn.
|
|
6
|
-
*
|
|
7
|
-
* Use cases:
|
|
8
|
-
* - Resolving ambiguous requirements before coding.
|
|
9
|
-
* - Getting user preferences (framework choice, styling, naming).
|
|
10
|
-
* - Requesting approval of an implementation plan before proceeding.
|
|
11
|
-
*/
|
|
12
|
-
export const AskUserQuestionTool: DynamicToolInterface = {
|
|
13
|
-
name: "ask_user_question",
|
|
14
|
-
description:
|
|
15
|
-
"Ask the user a question and wait for their response. " +
|
|
16
|
-
"Use this when you need clarification on the task, user preferences, " +
|
|
17
|
-
"or approval before proceeding with a significant change. " +
|
|
18
|
-
"You may optionally provide a list of answer choices.",
|
|
19
|
-
schema: {
|
|
20
|
-
type: "object" as const,
|
|
21
|
-
properties: {
|
|
22
|
-
question: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: "The question to ask the user.",
|
|
25
|
-
},
|
|
26
|
-
options: {
|
|
27
|
-
type: "array",
|
|
28
|
-
items: { type: "string" },
|
|
29
|
-
description: "Optional list of predefined answer choices.",
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
required: ["question"],
|
|
33
|
-
},
|
|
34
|
-
async execute(args: Record<string, unknown>): Promise<ToolResult> {
|
|
35
|
-
const question = args.question as string;
|
|
36
|
-
const options = args.options as string[] | undefined;
|
|
37
|
-
|
|
38
|
-
if (!question || question.trim() === "") {
|
|
39
|
-
return { content: "Error: You must provide a non-empty question.", isError: true };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const bridge = HITLBridge.getInstance();
|
|
43
|
-
const answer = await bridge.askUser(question, options);
|
|
44
|
-
|
|
45
|
-
return { content: answer };
|
|
46
|
-
},
|
|
47
|
-
};
|
package/src/tools/browser.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { SandboxManager } from "../sandbox/manager.js";
|
|
2
|
-
import { LazyInstaller } from "../sandbox/bootstrap.js";
|
|
3
|
-
import { DynamicToolInterface, ToolResult } from "./index.js";
|
|
4
|
-
|
|
5
|
-
// ─── Sandbox + Installer references ─────────────────────────────────────────
|
|
6
|
-
|
|
7
|
-
let _sandboxManager: SandboxManager | null = null;
|
|
8
|
-
let _installer: LazyInstaller | null = null;
|
|
9
|
-
|
|
10
|
-
export function bindBrowserSandbox(
|
|
11
|
-
sandbox: SandboxManager,
|
|
12
|
-
installer: LazyInstaller
|
|
13
|
-
): void {
|
|
14
|
-
_sandboxManager = sandbox;
|
|
15
|
-
_installer = installer;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ─── Helpers ────────────────────────────────────────────────────────────────────
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Escapes a string so it can be safely used as an argument in a Bash shell command.
|
|
22
|
-
* It wraps the string in single quotes and safely escapes internal single quotes.
|
|
23
|
-
*/
|
|
24
|
-
function escapeBashArg(arg: string): string {
|
|
25
|
-
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// ─── BrowserTool ────────────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Web Browser Tool — wraps Vercel Labs' `agent-browser` CLI.
|
|
32
|
-
*
|
|
33
|
-
* Provides compact accessibility-tree output optimized for LLMs
|
|
34
|
-
* (low token usage vs raw HTML). Runs inside the E2B sandbox.
|
|
35
|
-
*
|
|
36
|
-
* Supported actions:
|
|
37
|
-
* - navigate: Go to a URL
|
|
38
|
-
* - snapshot: Get the accessibility tree (compact text representation)
|
|
39
|
-
* - click: Click an element by ref
|
|
40
|
-
* - type: Type text into a form field by ref
|
|
41
|
-
* - screenshot: Capture a screenshot
|
|
42
|
-
* - scroll: Scroll the page up or down
|
|
43
|
-
*/
|
|
44
|
-
export const BrowserTool: DynamicToolInterface = {
|
|
45
|
-
name: "browser",
|
|
46
|
-
description:
|
|
47
|
-
"Interact with web pages using a headless browser. Actions: navigate, snapshot, click, type, screenshot, scroll. " +
|
|
48
|
-
"Returns compact accessibility-tree text output optimized for AI consumption.",
|
|
49
|
-
schema: {
|
|
50
|
-
type: "object",
|
|
51
|
-
properties: {
|
|
52
|
-
action: {
|
|
53
|
-
type: "string",
|
|
54
|
-
enum: ["navigate", "snapshot", "click", "type", "screenshot", "scroll"],
|
|
55
|
-
description: "The browser action to perform",
|
|
56
|
-
},
|
|
57
|
-
url: {
|
|
58
|
-
type: "string",
|
|
59
|
-
description: "URL to navigate to (required for 'navigate')",
|
|
60
|
-
},
|
|
61
|
-
ref: {
|
|
62
|
-
type: "string",
|
|
63
|
-
description:
|
|
64
|
-
"Element reference from the accessibility tree (required for 'click' and 'type')",
|
|
65
|
-
},
|
|
66
|
-
text: {
|
|
67
|
-
type: "string",
|
|
68
|
-
description: "Text to type (required for 'type')",
|
|
69
|
-
},
|
|
70
|
-
direction: {
|
|
71
|
-
type: "string",
|
|
72
|
-
enum: ["up", "down"],
|
|
73
|
-
description: "Scroll direction for 'scroll' action (optional, defaults to 'down')",
|
|
74
|
-
}, },
|
|
75
|
-
required: ["action"],
|
|
76
|
-
},
|
|
77
|
-
execute: async (args: {
|
|
78
|
-
action: string;
|
|
79
|
-
url?: string;
|
|
80
|
-
ref?: string;
|
|
81
|
-
text?: string;
|
|
82
|
-
direction?: string;
|
|
83
|
-
}): Promise<ToolResult> => {
|
|
84
|
-
if (!_sandboxManager || !_sandboxManager.isActive()) {
|
|
85
|
-
return { content: "Sandbox is not active. Cannot use browser tool.", isError: true };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Build the CLI command
|
|
89
|
-
let command: string;
|
|
90
|
-
|
|
91
|
-
switch (args.action) {
|
|
92
|
-
case "navigate":
|
|
93
|
-
if (!args.url) return { content: "Error: 'url' is required for navigate action.", isError: true };
|
|
94
|
-
command = `agent-browser navigate ${escapeBashArg(args.url)} 2>&1`;
|
|
95
|
-
break;
|
|
96
|
-
|
|
97
|
-
case "snapshot":
|
|
98
|
-
command = "agent-browser snapshot 2>&1";
|
|
99
|
-
break;
|
|
100
|
-
|
|
101
|
-
case "click":
|
|
102
|
-
if (!args.ref) return { content: "Error: 'ref' is required for click action.", isError: true };
|
|
103
|
-
command = `agent-browser click ${escapeBashArg(args.ref)} 2>&1`;
|
|
104
|
-
break;
|
|
105
|
-
|
|
106
|
-
case "type":
|
|
107
|
-
if (!args.ref) return { content: "Error: 'ref' is required for type action.", isError: true };
|
|
108
|
-
if (!args.text) return { content: "Error: 'text' is required for type action.", isError: true };
|
|
109
|
-
command = `agent-browser type ${escapeBashArg(args.ref)} ${escapeBashArg(args.text)} 2>&1`;
|
|
110
|
-
break;
|
|
111
|
-
|
|
112
|
-
case "screenshot":
|
|
113
|
-
command = "agent-browser screenshot 2>&1";
|
|
114
|
-
break;
|
|
115
|
-
|
|
116
|
-
case "scroll":
|
|
117
|
-
const dir = args.direction || "down";
|
|
118
|
-
command = `agent-browser scroll ${escapeBashArg(dir)} 2>&1`;
|
|
119
|
-
break;
|
|
120
|
-
|
|
121
|
-
default:
|
|
122
|
-
return { content: `Error: Unknown action "${args.action}". Use: navigate, snapshot, click, type, screenshot, scroll.`, isError: true };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const result = await _sandboxManager.exec(command);
|
|
126
|
-
|
|
127
|
-
if (result.exitCode !== 0) {
|
|
128
|
-
return {
|
|
129
|
-
content: `Browser action failed (exit code ${result.exitCode}):\n${result.stdout}\n${result.stderr}`,
|
|
130
|
-
metadata: { exitCode: result.exitCode },
|
|
131
|
-
isError: true
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return { content: result.stdout || "(no output)", metadata: { exitCode: result.exitCode }, isError: false };
|
|
136
|
-
},
|
|
137
|
-
};
|
package/src/tools/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpD;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,oBActB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,oBAc1B,CAAC;AAEF,eAAO,MAAM,UAAU,wBAA2B,CAAC"}
|
package/src/tools/index.ts
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import { SandboxManager } from "../sandbox/manager.js";
|
|
4
|
-
import { FileSync } from "../sandbox/sync.js";
|
|
5
|
-
|
|
6
|
-
export interface ToolResult {
|
|
7
|
-
content: string;
|
|
8
|
-
metadata?: Record<string, any>;
|
|
9
|
-
isError?: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface DynamicToolInterface {
|
|
13
|
-
name: string;
|
|
14
|
-
description: string;
|
|
15
|
-
schema: Record<string, any>;
|
|
16
|
-
execute: (args: any) => Promise<ToolResult> | ToolResult;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// ─── Configuration ──────────────────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
/** Maximum file size (in bytes) the agent is allowed to read into context. */
|
|
22
|
-
const MAX_FILE_SIZE_BYTES = 512 * 1024; // 512 KB
|
|
23
|
-
|
|
24
|
-
/** Maximum number of lines to return if file exceeds line limit. */
|
|
25
|
-
const MAX_FILE_LINES = 2000;
|
|
26
|
-
|
|
27
|
-
// ─── Sandbox reference (set at session start) ───────────────────────────────────
|
|
28
|
-
|
|
29
|
-
let _sandboxManager: SandboxManager | null = null;
|
|
30
|
-
let _fileSync: FileSync | null = null;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Binds the tools to a SandboxManager and FileSync instance.
|
|
34
|
-
* Must be called at session start before any tool executions.
|
|
35
|
-
*/
|
|
36
|
-
export function bindSandbox(sandbox: SandboxManager, fileSync: FileSync): void {
|
|
37
|
-
_sandboxManager = sandbox;
|
|
38
|
-
_fileSync = fileSync;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Security: Validates that a resolved path is strictly inside the given workspace dir.
|
|
43
|
-
* Prevents directory traversal attacks from accessing sensitive host files.
|
|
44
|
-
*/
|
|
45
|
-
export function isPathInsideWorkspace(
|
|
46
|
-
resolvedPath: string,
|
|
47
|
-
workspaceDir = process.cwd()
|
|
48
|
-
): boolean {
|
|
49
|
-
const normalizedWorkspace = path.resolve(workspaceDir);
|
|
50
|
-
// path.relative returns a path relative to the first argument.
|
|
51
|
-
// If it starts with '..' or is absolute, it means resolvedPath has escaped normalizedWorkspace.
|
|
52
|
-
const relative = path.relative(normalizedWorkspace, resolvedPath);
|
|
53
|
-
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ─── BashTool ───────────────────────────────────────────────────────────────────
|
|
57
|
-
// Executes shell commands inside the E2B sandbox.
|
|
58
|
-
// The ToolRouter routes this to SANDBOX — the host machine is never exposed.
|
|
59
|
-
|
|
60
|
-
export const BashTool: DynamicToolInterface = {
|
|
61
|
-
name: "bash",
|
|
62
|
-
description:
|
|
63
|
-
"Runs a shell command inside an isolated sandbox. Use for tests, scripts, or installing dependencies. The host machine is never exposed.",
|
|
64
|
-
schema: {
|
|
65
|
-
type: "object",
|
|
66
|
-
properties: {
|
|
67
|
-
command: {
|
|
68
|
-
type: "string",
|
|
69
|
-
description: "The shell command to execute",
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
required: ["command"],
|
|
73
|
-
},
|
|
74
|
-
execute: async (args: { command: string }): Promise<ToolResult> => {
|
|
75
|
-
if (!_sandboxManager || !_sandboxManager.isActive()) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"Sandbox is not active. Cannot execute bash commands without an active sandbox session."
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Sync any dirty files from host → sandbox before executing
|
|
82
|
-
if (_fileSync && _fileSync.pendingCount() > 0) {
|
|
83
|
-
await _fileSync.syncToSandbox(_sandboxManager);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const result = await _sandboxManager.exec(args.command);
|
|
87
|
-
|
|
88
|
-
if (result.exitCode !== 0) {
|
|
89
|
-
return {
|
|
90
|
-
content: `Command failed (exit code ${result.exitCode}):\nSTDOUT:\n${result.stdout}\nSTDERR:\n${result.stderr}`,
|
|
91
|
-
metadata: { exitCode: result.exitCode },
|
|
92
|
-
isError: true
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
content: result.stdout || "(no output)",
|
|
98
|
-
metadata: { exitCode: result.exitCode },
|
|
99
|
-
isError: false
|
|
100
|
-
};
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// ─── ReadFileTool ───────────────────────────────────────────────────────────────
|
|
105
|
-
// Reads files from the HOST filesystem (so the user's real project is visible).
|
|
106
|
-
// Includes a built-in file size guardrail to prevent sending huge files to the LLM.
|
|
107
|
-
|
|
108
|
-
export const ReadFileTool: DynamicToolInterface = {
|
|
109
|
-
name: "read_file",
|
|
110
|
-
description:
|
|
111
|
-
"Reads a file from the host filesystem. Includes a file size guardrail — files over 512KB are truncated to prevent context overflow.",
|
|
112
|
-
schema: {
|
|
113
|
-
type: "object",
|
|
114
|
-
properties: {
|
|
115
|
-
path: {
|
|
116
|
-
type: "string",
|
|
117
|
-
description: "Absolute or relative path to the file",
|
|
118
|
-
},
|
|
119
|
-
startLine: {
|
|
120
|
-
type: "number",
|
|
121
|
-
description: "Optional 1-indexed start line for partial reads",
|
|
122
|
-
},
|
|
123
|
-
endLine: {
|
|
124
|
-
type: "number",
|
|
125
|
-
description: "Optional 1-indexed end line for partial reads",
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
required: ["path"],
|
|
129
|
-
},
|
|
130
|
-
execute: async (args: { path: string; startLine?: number; endLine?: number }): Promise<ToolResult> => {
|
|
131
|
-
const filePath = path.resolve(args.path);
|
|
132
|
-
|
|
133
|
-
// ── Security Guardrail ──
|
|
134
|
-
if (!isPathInsideWorkspace(filePath)) {
|
|
135
|
-
return {
|
|
136
|
-
content: `Security Error: Access Denied. Cannot read files outside the current project workspace (${process.cwd()}).`,
|
|
137
|
-
isError: true
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// ── Check existence ──
|
|
142
|
-
if (!fs.existsSync(filePath)) {
|
|
143
|
-
return {
|
|
144
|
-
content: `Error: File not found — ${filePath}`,
|
|
145
|
-
isError: true
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ── File Size Guardrail ──
|
|
150
|
-
const stat = fs.statSync(filePath);
|
|
151
|
-
if (stat.size > MAX_FILE_SIZE_BYTES) {
|
|
152
|
-
return {
|
|
153
|
-
content: `Error: File too large (${Math.round(stat.size / 1024)}KB). Maximum size is 512KB. Use line ranges or grep_search.`,
|
|
154
|
-
isError: true
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const fileContent = fs.readFileSync(filePath, "utf-8");
|
|
159
|
-
const lines = fileContent.split("\n");
|
|
160
|
-
|
|
161
|
-
if (args.startLine !== undefined || args.endLine !== undefined) {
|
|
162
|
-
const start = Math.max(1, args.startLine ?? 1) - 1;
|
|
163
|
-
const end = Math.min(lines.length, args.endLine ?? lines.length);
|
|
164
|
-
const sliced = lines.slice(start, end);
|
|
165
|
-
return { content: sliced.map((line, i) => `${start + i + 1}: ${line}`).join("\n") };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ── Line count guardrail ──
|
|
169
|
-
if (lines.length > MAX_FILE_LINES) {
|
|
170
|
-
const truncated = lines.slice(0, MAX_FILE_LINES);
|
|
171
|
-
return {
|
|
172
|
-
content: truncated.map((line, i) => `${i + 1}: ${line}`).join("\n") +
|
|
173
|
-
`\n\n--- Truncated at ${MAX_FILE_LINES} lines (total: ${lines.length}) ---`
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return { content: fileContent };
|
|
178
|
-
},
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// ─── WriteFileTool ──────────────────────────────────────────────────────────────
|
|
182
|
-
// Writes files to the HOST filesystem (so the user sees changes in their IDE).
|
|
183
|
-
// Marks written files as dirty so FileSync uploads them before sandbox execution.
|
|
184
|
-
|
|
185
|
-
export const WriteFileTool: DynamicToolInterface = {
|
|
186
|
-
name: "write_file",
|
|
187
|
-
description:
|
|
188
|
-
"Writes content to a file on the host filesystem. The user will see changes in their IDE immediately. The file is automatically synced to the sandbox before the next command execution.",
|
|
189
|
-
schema: {
|
|
190
|
-
type: "object",
|
|
191
|
-
properties: {
|
|
192
|
-
path: {
|
|
193
|
-
type: "string",
|
|
194
|
-
description: "Absolute or relative path to the file",
|
|
195
|
-
},
|
|
196
|
-
content: {
|
|
197
|
-
type: "string",
|
|
198
|
-
description: "The full file content to write",
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
required: ["path", "content"],
|
|
202
|
-
},
|
|
203
|
-
execute: async (args: { path: string; content: string }): Promise<ToolResult> => {
|
|
204
|
-
const filePath = path.resolve(args.path);
|
|
205
|
-
|
|
206
|
-
// ── Security Guardrail ──
|
|
207
|
-
if (!isPathInsideWorkspace(filePath)) {
|
|
208
|
-
return {
|
|
209
|
-
content: `Security Error: Access Denied. Cannot write files outside the current project workspace (${process.cwd()}).`,
|
|
210
|
-
isError: true
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Create parent directories if needed
|
|
215
|
-
const dir = path.dirname(filePath);
|
|
216
|
-
if (!fs.existsSync(dir)) {
|
|
217
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
fs.writeFileSync(filePath, args.content, "utf-8");
|
|
221
|
-
|
|
222
|
-
// Mark file as dirty for next sandbox sync
|
|
223
|
-
if (_fileSync) {
|
|
224
|
-
_fileSync.markDirty(filePath);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return { content: `File written: ${filePath}` };
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
// ─── Core Tool Set ──────────────────────────────────────────────────────────────
|
|
232
|
-
|
|
233
|
-
export const CORE_TOOLS: DynamicToolInterface[] = [
|
|
234
|
-
BashTool,
|
|
235
|
-
ReadFileTool,
|
|
236
|
-
WriteFileTool,
|
|
237
|
-
];
|