@mrpatronz/nexusflow 1.6.0 → 1.8.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/README.md +15 -15
- package/dist/agent/AntigravityCliAdapter.d.ts +7 -0
- package/dist/agent/AntigravityCliAdapter.d.ts.map +1 -0
- package/dist/agent/AntigravityCliAdapter.js +13 -0
- package/dist/agent/AntigravityCliAdapter.js.map +1 -0
- package/dist/agent/ClaudeCliAdapter.d.ts +16 -0
- package/dist/agent/ClaudeCliAdapter.d.ts.map +1 -0
- package/dist/agent/ClaudeCliAdapter.js +34 -0
- package/dist/agent/ClaudeCliAdapter.js.map +1 -0
- package/dist/agent/CliAdapterBase.d.ts +48 -0
- package/dist/agent/CliAdapterBase.d.ts.map +1 -0
- package/dist/agent/CliAdapterBase.js +120 -0
- package/dist/agent/CliAdapterBase.js.map +1 -0
- package/dist/agent/NativeAgent.d.ts +13 -0
- package/dist/agent/NativeAgent.d.ts.map +1 -0
- package/dist/agent/NativeAgent.js +97 -0
- package/dist/agent/NativeAgent.js.map +1 -0
- package/dist/agent/NativeAgentBase.d.ts +27 -0
- package/dist/agent/NativeAgentBase.d.ts.map +1 -0
- package/dist/agent/NativeAgentBase.js +58 -0
- package/dist/agent/NativeAgentBase.js.map +1 -0
- package/dist/agent/NativeClaudeAgent.d.ts +13 -0
- package/dist/agent/NativeClaudeAgent.d.ts.map +1 -0
- package/dist/agent/NativeClaudeAgent.js +115 -0
- package/dist/agent/NativeClaudeAgent.js.map +1 -0
- package/dist/agent/NativeGoogleAgent.d.ts +13 -0
- package/dist/agent/NativeGoogleAgent.d.ts.map +1 -0
- package/dist/agent/NativeGoogleAgent.js +90 -0
- package/dist/agent/NativeGoogleAgent.js.map +1 -0
- package/dist/agent/ProviderRegistry.d.ts +31 -0
- package/dist/agent/ProviderRegistry.d.ts.map +1 -0
- package/dist/agent/ProviderRegistry.js +20 -0
- package/dist/agent/ProviderRegistry.js.map +1 -0
- package/dist/agent/ProviderRegistry.test.d.ts +2 -0
- package/dist/agent/ProviderRegistry.test.d.ts.map +1 -0
- package/dist/agent/ProviderRegistry.test.js +57 -0
- package/dist/agent/ProviderRegistry.test.js.map +1 -0
- package/dist/agent/adapters.d.ts +3 -0
- package/dist/agent/adapters.d.ts.map +1 -0
- package/dist/agent/adapters.js +48 -0
- package/dist/agent/adapters.js.map +1 -0
- package/dist/agent/nativeAgent.test.d.ts +2 -0
- package/dist/agent/nativeAgent.test.d.ts.map +1 -0
- package/dist/agent/nativeAgent.test.js +35 -0
- package/dist/agent/nativeAgent.test.js.map +1 -0
- package/dist/agent/nativeTools.d.ts +26 -0
- package/dist/agent/nativeTools.d.ts.map +1 -0
- package/dist/agent/nativeTools.js +62 -0
- package/dist/agent/nativeTools.js.map +1 -0
- package/dist/agent/nativeTools.test.d.ts +2 -0
- package/dist/agent/nativeTools.test.d.ts.map +1 -0
- package/dist/agent/nativeTools.test.js +67 -0
- package/dist/agent/nativeTools.test.js.map +1 -0
- package/dist/agent/session.d.ts +25 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +31 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/session.test.d.ts +2 -0
- package/dist/agent/session.test.d.ts.map +1 -0
- package/dist/agent/session.test.js +44 -0
- package/dist/agent/session.test.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +29 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/desktop.d.ts +4 -5
- package/dist/commands/desktop.d.ts.map +1 -1
- package/dist/commands/desktop.js +35 -89
- package/dist/commands/desktop.js.map +1 -1
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +3 -2
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/ui.d.ts +7 -3
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +12 -6
- package/dist/commands/ui.js.map +1 -1
- package/dist/core/adapters/registry.d.ts.map +1 -1
- package/dist/core/adapters/registry.js +0 -2
- package/dist/core/adapters/registry.js.map +1 -1
- package/dist/core/adapters/storage.test.js +0 -40
- package/dist/core/adapters/storage.test.js.map +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/knowledge.d.ts +5 -4
- package/dist/core/knowledge.d.ts.map +1 -1
- package/dist/core/knowledge.js +5 -4
- package/dist/core/knowledge.js.map +1 -1
- package/dist/core/new-repo.d.ts +27 -0
- package/dist/core/new-repo.d.ts.map +1 -0
- package/dist/core/new-repo.js +89 -0
- package/dist/core/new-repo.js.map +1 -0
- package/dist/core/new-repo.test.d.ts +2 -0
- package/dist/core/new-repo.test.d.ts.map +1 -0
- package/dist/core/new-repo.test.js +78 -0
- package/dist/core/new-repo.test.js.map +1 -0
- package/dist/core/workspace.create.test.js +19 -0
- package/dist/core/workspace.create.test.js.map +1 -1
- package/dist/core/workspace.d.ts +5 -3
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +13 -8
- package/dist/core/workspace.js.map +1 -1
- package/dist/core/worktree.d.ts +20 -7
- package/dist/core/worktree.d.ts.map +1 -1
- package/dist/core/worktree.js +31 -8
- package/dist/core/worktree.js.map +1 -1
- package/dist/core/worktree.test.js +42 -0
- package/dist/core/worktree.test.js.map +1 -1
- package/dist/desktop-server.d.ts +13 -0
- package/dist/desktop-server.d.ts.map +1 -0
- package/dist/desktop-server.js +23 -0
- package/dist/desktop-server.js.map +1 -0
- package/dist/gui/assets/index-CQTEzHj2.css +1 -0
- package/dist/gui/assets/index-DLmLdpqC.js +58 -0
- package/dist/gui/index.html +2 -2
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +152 -3
- package/dist/server.js.map +1 -1
- package/dist/server.test.js +50 -5
- package/dist/server.test.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/git.d.ts +16 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +33 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/prompts.d.ts +13 -0
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +63 -5
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/session-finder.d.ts +21 -1
- package/dist/utils/session-finder.d.ts.map +1 -1
- package/dist/utils/session-finder.js +220 -143
- package/dist/utils/session-finder.js.map +1 -1
- package/dist/utils/session-finder.test.d.ts +2 -0
- package/dist/utils/session-finder.test.d.ts.map +1 -0
- package/dist/utils/session-finder.test.js +65 -0
- package/dist/utils/session-finder.test.js.map +1 -0
- package/package.json +10 -1
- package/dist/core/adapters/obsidian-storage.d.ts +0 -28
- package/dist/core/adapters/obsidian-storage.d.ts.map +0 -1
- package/dist/core/adapters/obsidian-storage.js +0 -135
- package/dist/core/adapters/obsidian-storage.js.map +0 -1
- package/dist/gui/assets/index-Bdbld6yY.css +0 -1
- package/dist/gui/assets/index-ElroPpSP.js +0 -26
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { NativeAgentBase } from './NativeAgentBase.js';
|
|
3
|
+
import { NATIVE_TOOLS, NATIVE_STEP_LIMIT, STEP_LIMIT_NOTICE, buildSystemPrompt, executeNativeTool, } from './nativeTools.js';
|
|
4
|
+
export class NativeClaudeAgent extends NativeAgentBase {
|
|
5
|
+
label = 'NativeClaudeAgent';
|
|
6
|
+
anthropic = null;
|
|
7
|
+
messages = [];
|
|
8
|
+
modelName;
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.modelName = process.env.ANTHROPIC_MODEL || 'claude-sonnet-5';
|
|
12
|
+
}
|
|
13
|
+
client() {
|
|
14
|
+
return (this.anthropic ??= new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY || '' }));
|
|
15
|
+
}
|
|
16
|
+
configError() {
|
|
17
|
+
return process.env.ANTHROPIC_API_KEY ? null : 'Anthropic API key is not configured (set ANTHROPIC_API_KEY).';
|
|
18
|
+
}
|
|
19
|
+
resetHistory() {
|
|
20
|
+
this.messages = [];
|
|
21
|
+
}
|
|
22
|
+
async runLoop(userInput, signal) {
|
|
23
|
+
this.messages.push({ role: 'user', content: userInput });
|
|
24
|
+
const system = buildSystemPrompt(this.cwd);
|
|
25
|
+
const tools = NATIVE_TOOLS.map((t) => ({
|
|
26
|
+
name: t.name,
|
|
27
|
+
description: t.description,
|
|
28
|
+
input_schema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: { [t.argName]: { type: 'string', description: t.argDescription } },
|
|
31
|
+
required: [t.argName],
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
let completed = false;
|
|
35
|
+
for (let step = 0; step < NATIVE_STEP_LIMIT; step++) {
|
|
36
|
+
if (signal.aborted)
|
|
37
|
+
break;
|
|
38
|
+
const stream = await this.client().messages.create({
|
|
39
|
+
model: this.modelName,
|
|
40
|
+
max_tokens: 8192,
|
|
41
|
+
system,
|
|
42
|
+
messages: this.messages,
|
|
43
|
+
tools,
|
|
44
|
+
stream: true,
|
|
45
|
+
}, { signal });
|
|
46
|
+
let content = '';
|
|
47
|
+
const toolCalls = [];
|
|
48
|
+
let currentToolCall = null;
|
|
49
|
+
for await (const chunk of stream) {
|
|
50
|
+
if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
|
|
51
|
+
content += chunk.delta.text;
|
|
52
|
+
this.emit('data', chunk.delta.text);
|
|
53
|
+
}
|
|
54
|
+
else if (chunk.type === 'content_block_start' && chunk.content_block.type === 'tool_use') {
|
|
55
|
+
currentToolCall = { id: chunk.content_block.id, name: chunk.content_block.name, input: '' };
|
|
56
|
+
this.emit('data', `\n\n*Running tool: ${currentToolCall.name}*\n`);
|
|
57
|
+
}
|
|
58
|
+
else if (chunk.type === 'content_block_delta' && chunk.delta.type === 'input_json_delta' && currentToolCall) {
|
|
59
|
+
currentToolCall.input += chunk.delta.partial_json;
|
|
60
|
+
}
|
|
61
|
+
else if (chunk.type === 'content_block_stop') {
|
|
62
|
+
if (currentToolCall) {
|
|
63
|
+
toolCalls.push(currentToolCall);
|
|
64
|
+
currentToolCall = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Parse tool inputs up front. A tool_use block and its later tool_result
|
|
69
|
+
// must be paired: if the JSON is malformed we drop BOTH, otherwise the
|
|
70
|
+
// Anthropic API rejects the next request with a dangling tool_result and
|
|
71
|
+
// the whole session is wedged.
|
|
72
|
+
const assistantContent = [];
|
|
73
|
+
if (content)
|
|
74
|
+
assistantContent.push({ type: 'text', text: content });
|
|
75
|
+
const validCalls = [];
|
|
76
|
+
for (const tc of toolCalls) {
|
|
77
|
+
try {
|
|
78
|
+
const args = JSON.parse(tc.input || '{}');
|
|
79
|
+
assistantContent.push({ type: 'tool_use', id: tc.id, name: tc.name, input: args });
|
|
80
|
+
validCalls.push({ id: tc.id, name: tc.name, args });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Malformed tool input — skip the block entirely (no tool_result).
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Anthropic requires strictly alternating user/assistant turns with
|
|
87
|
+
// non-empty content. If the model returned nothing usable (no text and
|
|
88
|
+
// only malformed tool calls), record a minimal assistant turn so the
|
|
89
|
+
// next user message doesn't produce two consecutive user turns (400).
|
|
90
|
+
if (assistantContent.length === 0) {
|
|
91
|
+
assistantContent.push({ type: 'text', text: '(no response)' });
|
|
92
|
+
}
|
|
93
|
+
this.messages.push({ role: 'assistant', content: assistantContent });
|
|
94
|
+
if (validCalls.length === 0) {
|
|
95
|
+
completed = true;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
const toolResultContent = [];
|
|
99
|
+
for (const call of validCalls) {
|
|
100
|
+
try {
|
|
101
|
+
const result = await executeNativeTool(this.cwd, call.name, call.args);
|
|
102
|
+
toolResultContent.push({ type: 'tool_result', tool_use_id: call.id, content: result });
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
toolResultContent.push({ type: 'tool_result', tool_use_id: call.id, content: `Error: ${err.message}`, is_error: true });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.messages.push({ role: 'user', content: toolResultContent });
|
|
109
|
+
}
|
|
110
|
+
if (!completed && !signal.aborted) {
|
|
111
|
+
this.emit('data', STEP_LIMIT_NOTICE);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=NativeClaudeAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeClaudeAgent.js","sourceRoot":"","sources":["../../src/agent/NativeClaudeAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NativeAgentBase } from './NativeAgentBase.js';
|
|
2
|
+
export declare class NativeGoogleAgent extends NativeAgentBase {
|
|
3
|
+
protected readonly label = "NativeGoogleAgent";
|
|
4
|
+
private ai;
|
|
5
|
+
private history;
|
|
6
|
+
private modelName;
|
|
7
|
+
constructor();
|
|
8
|
+
private client;
|
|
9
|
+
protected configError(): string | null;
|
|
10
|
+
protected resetHistory(): void;
|
|
11
|
+
protected runLoop(userInput: string, signal: AbortSignal): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=NativeGoogleAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeGoogleAgent.d.ts","sourceRoot":"","sources":["../../src/agent/NativeGoogleAgent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AASvD,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,KAAK,uBAAuB;IAC/C,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,SAAS,CAAS;;IAQ1B,OAAO,CAAC,MAAM;IAId,SAAS,CAAC,WAAW,IAAI,MAAM,GAAG,IAAI;IAItC,SAAS,CAAC,YAAY;cAIN,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;CAyE/D"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { GoogleGenAI } from '@google/genai';
|
|
2
|
+
import { NativeAgentBase } from './NativeAgentBase.js';
|
|
3
|
+
import { NATIVE_TOOLS, NATIVE_STEP_LIMIT, STEP_LIMIT_NOTICE, buildSystemPrompt, executeNativeTool, } from './nativeTools.js';
|
|
4
|
+
export class NativeGoogleAgent extends NativeAgentBase {
|
|
5
|
+
label = 'NativeGoogleAgent';
|
|
6
|
+
ai = null;
|
|
7
|
+
history = [];
|
|
8
|
+
modelName;
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
// Allow users to override the model via env var, fallback to gemini-2.0-flash
|
|
12
|
+
this.modelName = process.env.GEMINI_MODEL || 'gemini-2.0-flash';
|
|
13
|
+
}
|
|
14
|
+
client() {
|
|
15
|
+
return (this.ai ??= new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY || '' }));
|
|
16
|
+
}
|
|
17
|
+
configError() {
|
|
18
|
+
return process.env.GEMINI_API_KEY ? null : 'Google API key is not configured (set GEMINI_API_KEY).';
|
|
19
|
+
}
|
|
20
|
+
resetHistory() {
|
|
21
|
+
this.history = [];
|
|
22
|
+
}
|
|
23
|
+
async runLoop(userInput, signal) {
|
|
24
|
+
this.history.push({ role: 'user', parts: [{ text: userInput }] });
|
|
25
|
+
const config = {
|
|
26
|
+
systemInstruction: buildSystemPrompt(this.cwd),
|
|
27
|
+
// Cancels an in-flight request when stop() aborts the controller.
|
|
28
|
+
abortSignal: signal,
|
|
29
|
+
tools: [{
|
|
30
|
+
functionDeclarations: NATIVE_TOOLS.map((t) => ({
|
|
31
|
+
name: t.name,
|
|
32
|
+
description: t.description,
|
|
33
|
+
parameters: {
|
|
34
|
+
type: 'OBJECT',
|
|
35
|
+
properties: { [t.argName]: { type: 'STRING', description: t.argDescription } },
|
|
36
|
+
required: [t.argName],
|
|
37
|
+
},
|
|
38
|
+
})),
|
|
39
|
+
}],
|
|
40
|
+
};
|
|
41
|
+
let completed = false;
|
|
42
|
+
for (let step = 0; step < NATIVE_STEP_LIMIT; step++) {
|
|
43
|
+
if (signal.aborted)
|
|
44
|
+
break;
|
|
45
|
+
const responseStream = await this.client().models.generateContentStream({
|
|
46
|
+
model: this.modelName,
|
|
47
|
+
contents: this.history,
|
|
48
|
+
config,
|
|
49
|
+
});
|
|
50
|
+
let fullText = '';
|
|
51
|
+
const functionCalls = [];
|
|
52
|
+
for await (const chunk of responseStream) {
|
|
53
|
+
if (chunk.text) {
|
|
54
|
+
fullText += chunk.text;
|
|
55
|
+
this.emit('data', chunk.text);
|
|
56
|
+
}
|
|
57
|
+
if (chunk.functionCalls && chunk.functionCalls.length > 0) {
|
|
58
|
+
functionCalls.push(...chunk.functionCalls);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const modelParts = [];
|
|
62
|
+
if (fullText)
|
|
63
|
+
modelParts.push({ text: fullText });
|
|
64
|
+
if (functionCalls.length > 0)
|
|
65
|
+
modelParts.push(...functionCalls.map((fc) => ({ functionCall: fc })));
|
|
66
|
+
this.history.push({ role: 'model', parts: modelParts });
|
|
67
|
+
if (functionCalls.length === 0) {
|
|
68
|
+
completed = true;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
const functionResponses = [];
|
|
72
|
+
for (const call of functionCalls) {
|
|
73
|
+
this.emit('data', `\n\n*Running tool: ${call.name}*\n`);
|
|
74
|
+
let result;
|
|
75
|
+
try {
|
|
76
|
+
result = await executeNativeTool(this.cwd, call.name, call.args || {});
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
result = `Error: ${e.message}`;
|
|
80
|
+
}
|
|
81
|
+
functionResponses.push({ functionResponse: { name: call.name, response: { result } } });
|
|
82
|
+
}
|
|
83
|
+
this.history.push({ role: 'user', parts: functionResponses });
|
|
84
|
+
}
|
|
85
|
+
if (!completed && !signal.aborted) {
|
|
86
|
+
this.emit('data', STEP_LIMIT_NOTICE);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=NativeGoogleAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeGoogleAgent.js","sourceRoot":"","sources":["../../src/agent/NativeGoogleAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AgentSession } from './session.js';
|
|
2
|
+
export interface ProviderStatus {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
isConfigured: boolean;
|
|
6
|
+
message?: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentHarness {
|
|
10
|
+
start(cwd: string, session?: AgentSession): Promise<void>;
|
|
11
|
+
send(data: string): Promise<void>;
|
|
12
|
+
stop(): void;
|
|
13
|
+
on(event: 'data' | 'close' | 'error' | 'system' | 'idle', listener: (...args: any[]) => void): this;
|
|
14
|
+
}
|
|
15
|
+
export interface ProviderAdapter {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
icon?: string;
|
|
19
|
+
isConfigured(): boolean;
|
|
20
|
+
getStatusMessage(): string | undefined;
|
|
21
|
+
createInstance(): AgentHarness;
|
|
22
|
+
}
|
|
23
|
+
declare class ProviderRegistryImpl {
|
|
24
|
+
private providers;
|
|
25
|
+
register(provider: ProviderAdapter): void;
|
|
26
|
+
getProvider(id: string): ProviderAdapter | undefined;
|
|
27
|
+
getAllStatus(): ProviderStatus[];
|
|
28
|
+
}
|
|
29
|
+
export declare const ProviderRegistry: ProviderRegistryImpl;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=ProviderRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.d.ts","sourceRoot":"","sources":["../../src/agent/ProviderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,IAAI,CAAC;IACb,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;CACrG;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,IAAI,OAAO,CAAC;IACxB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAAC;IACvC,cAAc,IAAI,YAAY,CAAC;CAChC;AAED,cAAM,oBAAoB;IACxB,OAAO,CAAC,SAAS,CAA2C;IAE5D,QAAQ,CAAC,QAAQ,EAAE,eAAe;IAIlC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIpD,YAAY,IAAI,cAAc,EAAE;CASjC;AAED,eAAO,MAAM,gBAAgB,sBAA6B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class ProviderRegistryImpl {
|
|
2
|
+
providers = new Map();
|
|
3
|
+
register(provider) {
|
|
4
|
+
this.providers.set(provider.id, provider);
|
|
5
|
+
}
|
|
6
|
+
getProvider(id) {
|
|
7
|
+
return this.providers.get(id);
|
|
8
|
+
}
|
|
9
|
+
getAllStatus() {
|
|
10
|
+
return Array.from(this.providers.values()).map(p => ({
|
|
11
|
+
id: p.id,
|
|
12
|
+
name: p.name,
|
|
13
|
+
icon: p.icon,
|
|
14
|
+
isConfigured: p.isConfigured(),
|
|
15
|
+
message: p.getStatusMessage()
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const ProviderRegistry = new ProviderRegistryImpl();
|
|
20
|
+
//# sourceMappingURL=ProviderRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.js","sourceRoot":"","sources":["../../src/agent/ProviderRegistry.ts"],"names":[],"mappings":"AA0BA,MAAM,oBAAoB;IAChB,SAAS,GAAiC,IAAI,GAAG,EAAE,CAAC;IAE5D,QAAQ,CAAC,QAAyB;QAChC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,WAAW,CAAC,EAAU;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,YAAY;QACV,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACnD,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE;YAC9B,OAAO,EAAE,CAAC,CAAC,gBAAgB,EAAE;SAC9B,CAAC,CAAC,CAAC;IACN,CAAC;CACF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.test.d.ts","sourceRoot":"","sources":["../../src/agent/ProviderRegistry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ProviderRegistry } from './ProviderRegistry.js';
|
|
3
|
+
class MockAgentHarness {
|
|
4
|
+
started = false;
|
|
5
|
+
async start(cwd) {
|
|
6
|
+
this.started = true;
|
|
7
|
+
}
|
|
8
|
+
async send(data) { }
|
|
9
|
+
stop() { }
|
|
10
|
+
on(event, listener) { return this; }
|
|
11
|
+
}
|
|
12
|
+
// The registry is a shared singleton without a reset method, so each test
|
|
13
|
+
// registers its own uniquely-named provider to stay order-independent.
|
|
14
|
+
function makeProvider(id, overrides = {}) {
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
name: 'Mock',
|
|
18
|
+
isConfigured: () => true,
|
|
19
|
+
getStatusMessage: () => undefined,
|
|
20
|
+
createInstance: () => new MockAgentHarness(),
|
|
21
|
+
...overrides
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
describe('ProviderRegistry', () => {
|
|
25
|
+
it('should register and retrieve a provider', () => {
|
|
26
|
+
ProviderRegistry.register(makeProvider('mock-retrieve'));
|
|
27
|
+
const retrieved = ProviderRegistry.getProvider('mock-retrieve');
|
|
28
|
+
expect(retrieved).toBeDefined();
|
|
29
|
+
expect(retrieved?.id).toBe('mock-retrieve');
|
|
30
|
+
expect(retrieved?.name).toBe('Mock');
|
|
31
|
+
});
|
|
32
|
+
it('should list all statuses correctly', () => {
|
|
33
|
+
ProviderRegistry.register(makeProvider('mock-unconfigured', {
|
|
34
|
+
name: 'Unconfigured',
|
|
35
|
+
isConfigured: () => false,
|
|
36
|
+
getStatusMessage: () => 'Missing API Key'
|
|
37
|
+
}));
|
|
38
|
+
const statuses = ProviderRegistry.getAllStatus();
|
|
39
|
+
const unconfiguredStatus = statuses.find(s => s.id === 'mock-unconfigured');
|
|
40
|
+
expect(unconfiguredStatus).toBeDefined();
|
|
41
|
+
expect(unconfiguredStatus?.isConfigured).toBe(false);
|
|
42
|
+
expect(unconfiguredStatus?.message).toBe('Missing API Key');
|
|
43
|
+
});
|
|
44
|
+
it('should create an instance correctly', () => {
|
|
45
|
+
ProviderRegistry.register(makeProvider('mock-instance'));
|
|
46
|
+
const provider = ProviderRegistry.getProvider('mock-instance');
|
|
47
|
+
expect(provider).toBeDefined();
|
|
48
|
+
if (provider) {
|
|
49
|
+
const instance = provider.createInstance();
|
|
50
|
+
expect(instance).toBeDefined();
|
|
51
|
+
expect(instance.started).toBe(false);
|
|
52
|
+
instance.start('/');
|
|
53
|
+
expect(instance.started).toBe(true);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=ProviderRegistry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderRegistry.test.js","sourceRoot":"","sources":["../../src/agent/ProviderRegistry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../../src/agent/adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAoDzD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ProviderRegistry } from './ProviderRegistry.js';
|
|
2
|
+
import { NativeClaudeAgent } from './NativeClaudeAgent.js';
|
|
3
|
+
import { NativeAgent } from './NativeAgent.js';
|
|
4
|
+
import { NativeGoogleAgent } from './NativeGoogleAgent.js';
|
|
5
|
+
import { ClaudeCliAdapter } from './ClaudeCliAdapter.js';
|
|
6
|
+
import { AntigravityCliAdapter } from './AntigravityCliAdapter.js';
|
|
7
|
+
ProviderRegistry.register({
|
|
8
|
+
id: 'claude-native',
|
|
9
|
+
name: 'Claude',
|
|
10
|
+
icon: 'Bot',
|
|
11
|
+
isConfigured: () => !!process.env.ANTHROPIC_API_KEY,
|
|
12
|
+
getStatusMessage: () => process.env.ANTHROPIC_API_KEY ? undefined : 'Anthropic API key is not configured in ANTHROPIC_API_KEY.',
|
|
13
|
+
createInstance: () => new NativeClaudeAgent()
|
|
14
|
+
});
|
|
15
|
+
ProviderRegistry.register({
|
|
16
|
+
id: 'openai-native',
|
|
17
|
+
name: 'OpenAI',
|
|
18
|
+
icon: 'Sparkles',
|
|
19
|
+
isConfigured: () => !!process.env.OPENAI_API_KEY,
|
|
20
|
+
getStatusMessage: () => process.env.OPENAI_API_KEY ? undefined : 'OpenAI API key is not configured in OPENAI_API_KEY.',
|
|
21
|
+
createInstance: () => new NativeAgent()
|
|
22
|
+
});
|
|
23
|
+
ProviderRegistry.register({
|
|
24
|
+
id: 'google-native',
|
|
25
|
+
name: 'Google Gemini',
|
|
26
|
+
icon: 'Sparkles',
|
|
27
|
+
isConfigured: () => !!process.env.GEMINI_API_KEY,
|
|
28
|
+
getStatusMessage: () => process.env.GEMINI_API_KEY ? undefined : 'Google API key is not configured in GEMINI_API_KEY.',
|
|
29
|
+
createInstance: () => new NativeGoogleAgent()
|
|
30
|
+
});
|
|
31
|
+
ProviderRegistry.register({
|
|
32
|
+
id: 'claude-cli',
|
|
33
|
+
name: 'Claude Code (Local CLI)',
|
|
34
|
+
icon: 'Terminal',
|
|
35
|
+
isConfigured: () => true, // Assume the CLI is installed for now
|
|
36
|
+
getStatusMessage: () => undefined, // No API key required!
|
|
37
|
+
createInstance: () => new ClaudeCliAdapter()
|
|
38
|
+
});
|
|
39
|
+
ProviderRegistry.register({
|
|
40
|
+
id: 'antigravity-cli',
|
|
41
|
+
name: 'Antigravity (Local CLI)',
|
|
42
|
+
icon: 'Terminal',
|
|
43
|
+
isConfigured: () => true, // Assume the CLI is installed for now
|
|
44
|
+
getStatusMessage: () => undefined, // No API key required!
|
|
45
|
+
createInstance: () => new AntigravityCliAdapter()
|
|
46
|
+
});
|
|
47
|
+
export { ProviderRegistry };
|
|
48
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../../src/agent/adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,gBAAgB,CAAC,QAAQ,CAAC;IACxB,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,KAAK;IACX,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB;IACnD,gBAAgB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,2DAA2D;IAC/H,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;CAC9C,CAAC,CAAC;AAEH,gBAAgB,CAAC,QAAQ,CAAC;IACxB,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,UAAU;IAChB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;IAChD,gBAAgB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qDAAqD;IACtH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,EAAE;CACxC,CAAC,CAAC;AAEH,gBAAgB,CAAC,QAAQ,CAAC;IACxB,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,UAAU;IAChB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc;IAChD,gBAAgB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qDAAqD;IACtH,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;CAC9C,CAAC,CAAC;AAEH,gBAAgB,CAAC,QAAQ,CAAC;IACxB,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE,UAAU;IAChB,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,sCAAsC;IAChE,gBAAgB,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,uBAAuB;IAC1D,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,gBAAgB,EAAE;CAC7C,CAAC,CAAC;AAEH,gBAAgB,CAAC,QAAQ,CAAC;IACxB,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,yBAAyB;IAC/B,IAAI,EAAE,UAAU;IAChB,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,sCAAsC;IAChE,gBAAgB,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,uBAAuB;IAC1D,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,qBAAqB,EAAE;CAClD,CAAC,CAAC;AAEH,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeAgent.test.d.ts","sourceRoot":"","sources":["../../src/agent/nativeAgent.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { NativeAgent } from './NativeAgent.js';
|
|
3
|
+
import { NativeClaudeAgent } from './NativeClaudeAgent.js';
|
|
4
|
+
import { NativeGoogleAgent } from './NativeGoogleAgent.js';
|
|
5
|
+
// Ensure no keys leak in from the environment.
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
delete process.env.OPENAI_API_KEY;
|
|
8
|
+
delete process.env.ANTHROPIC_API_KEY;
|
|
9
|
+
delete process.env.GEMINI_API_KEY;
|
|
10
|
+
});
|
|
11
|
+
const cases = [
|
|
12
|
+
['NativeAgent (OpenAI)', () => new NativeAgent(), /OpenAI API key is not configured/],
|
|
13
|
+
['NativeClaudeAgent', () => new NativeClaudeAgent(), /Anthropic API key is not configured/],
|
|
14
|
+
['NativeGoogleAgent', () => new NativeGoogleAgent(), /Google API key is not configured/],
|
|
15
|
+
];
|
|
16
|
+
describe('native agents without an API key', () => {
|
|
17
|
+
for (const [name, make, expected] of cases) {
|
|
18
|
+
it(`${name}: constructs without throwing and emits a clear config error on send`, async () => {
|
|
19
|
+
// Construction must not throw even though the SDK client would reject an
|
|
20
|
+
// empty key — the client is built lazily behind the config gate.
|
|
21
|
+
const agent = make();
|
|
22
|
+
const events = [];
|
|
23
|
+
agent.on('error', (e) => events.push({ type: 'error', message: e.message }));
|
|
24
|
+
agent.on('idle', () => events.push({ type: 'idle' }));
|
|
25
|
+
await agent.start('/tmp/ws');
|
|
26
|
+
await agent.send('hello');
|
|
27
|
+
const err = events.find((e) => e.type === 'error');
|
|
28
|
+
expect(err, 'expected an error event').toBeTruthy();
|
|
29
|
+
expect(err.message).toMatch(expected);
|
|
30
|
+
// No network call happened, and the turn settled.
|
|
31
|
+
expect(events.some((e) => e.type === 'idle')).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=nativeAgent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeAgent.test.js","sourceRoot":"","sources":["../../src/agent/nativeAgent.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,+CAA+C;AAC/C,UAAU,CAAC,GAAG,EAAE;IACd,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACrC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,MAAM,KAAK,GAAkC;IAC3C,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,EAAE,EAAE,kCAAkC,CAAC;IACrF,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE,EAAE,qCAAqC,CAAC;IAC3F,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE,EAAE,kCAAkC,CAAC;CACzF,CAAC;AAEF,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC;QAC3C,EAAE,CAAC,GAAG,IAAI,sEAAsE,EAAE,KAAK,IAAI,EAAE;YAC3F,yEAAyE;YACzE,iEAAiE;YACjE,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;YACrB,MAAM,MAAM,GAAyC,EAAE,CAAC;YACxD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACpF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YAEtD,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC7B,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE1B,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;YACnD,MAAM,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC,UAAU,EAAE,CAAC;YACpD,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvC,kDAAkD;YAClD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module agent/nativeTools
|
|
3
|
+
* Shared prompt, tool metadata, and execution for the SDK-backed native agents
|
|
4
|
+
* (OpenAI / Anthropic / Gemini). Keeping the tool executor here means the
|
|
5
|
+
* read-only workspace access — and its path-containment guard — is defined
|
|
6
|
+
* once instead of copied into three agent loops.
|
|
7
|
+
*/
|
|
8
|
+
export declare const NATIVE_STEP_LIMIT = 5;
|
|
9
|
+
export declare const STEP_LIMIT_NOTICE = "\n\n*Stopped after reaching the tool-step limit without a final answer. Send a follow-up message to continue.*\n";
|
|
10
|
+
export declare function buildSystemPrompt(cwd: string): string;
|
|
11
|
+
export interface NativeToolMeta {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
argName: string;
|
|
15
|
+
argDescription: string;
|
|
16
|
+
}
|
|
17
|
+
/** Provider-agnostic description of the two read-only tools. Each agent maps
|
|
18
|
+
* these into its own SDK's schema shape. */
|
|
19
|
+
export declare const NATIVE_TOOLS: NativeToolMeta[];
|
|
20
|
+
/**
|
|
21
|
+
* Execute a native tool call. Returns the tool's textual result; throws on an
|
|
22
|
+
* unknown tool, a path-containment violation, or a filesystem error (callers
|
|
23
|
+
* surface the message back to the model).
|
|
24
|
+
*/
|
|
25
|
+
export declare function executeNativeTool(cwd: string, name: string, args: any): Promise<string>;
|
|
26
|
+
//# sourceMappingURL=nativeTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeTools.d.ts","sourceRoot":"","sources":["../../src/agent/nativeTools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,qHACsF,CAAC;AAErH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;6CAC6C;AAC7C,eAAO,MAAM,YAAY,EAAE,cAAc,EAGxC,CAAC;AA4BF;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAU7F"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module agent/nativeTools
|
|
3
|
+
* Shared prompt, tool metadata, and execution for the SDK-backed native agents
|
|
4
|
+
* (OpenAI / Anthropic / Gemini). Keeping the tool executor here means the
|
|
5
|
+
* read-only workspace access — and its path-containment guard — is defined
|
|
6
|
+
* once instead of copied into three agent loops.
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
export const NATIVE_STEP_LIMIT = 5;
|
|
11
|
+
export const STEP_LIMIT_NOTICE = '\n\n*Stopped after reaching the tool-step limit without a final answer. Send a follow-up message to continue.*\n';
|
|
12
|
+
export function buildSystemPrompt(cwd) {
|
|
13
|
+
return `You are an expert coding assistant running within the NexusFlow IDE.
|
|
14
|
+
You have read-only access to the user's workspace at ${cwd} through your tools: you can read files and list directories, but you cannot edit files or run commands.
|
|
15
|
+
When suggesting code changes, include the proposed diff directly in your text response so the user can apply it themselves.`;
|
|
16
|
+
}
|
|
17
|
+
/** Provider-agnostic description of the two read-only tools. Each agent maps
|
|
18
|
+
* these into its own SDK's schema shape. */
|
|
19
|
+
export const NATIVE_TOOLS = [
|
|
20
|
+
{ name: 'read_file', description: 'Read the contents of a file', argName: 'filePath', argDescription: 'Path to file relative to workspace' },
|
|
21
|
+
{ name: 'list_directory', description: 'List the contents of a directory', argName: 'dirPath', argDescription: 'Path to directory relative to workspace' },
|
|
22
|
+
];
|
|
23
|
+
function assertWithin(base, target, rel) {
|
|
24
|
+
// Trailing separator stops a sibling like `workspace-secret` from passing
|
|
25
|
+
// the prefix test for base `workspace`.
|
|
26
|
+
if (target !== base && !target.startsWith(base + path.sep)) {
|
|
27
|
+
throw new Error(`Path escapes the workspace: ${String(rel)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a workspace-relative path and refuse anything that escapes `cwd`,
|
|
32
|
+
* including via symlinks. The lexical check catches `..`/absolute paths; the
|
|
33
|
+
* realpath check catches a symlink inside the workspace that points outside.
|
|
34
|
+
*/
|
|
35
|
+
async function resolveWithin(cwd, rel) {
|
|
36
|
+
const base = path.resolve(cwd);
|
|
37
|
+
const resolved = path.resolve(base, typeof rel === 'string' ? rel : '');
|
|
38
|
+
assertWithin(base, resolved, rel);
|
|
39
|
+
// Follow symlinks and re-check. realpath throws ENOENT for a missing target,
|
|
40
|
+
// which the fs read below would raise anyway — let it surface as-is.
|
|
41
|
+
const realBase = await fs.realpath(base);
|
|
42
|
+
const realTarget = await fs.realpath(resolved);
|
|
43
|
+
assertWithin(realBase, realTarget, rel);
|
|
44
|
+
return realTarget;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute a native tool call. Returns the tool's textual result; throws on an
|
|
48
|
+
* unknown tool, a path-containment violation, or a filesystem error (callers
|
|
49
|
+
* surface the message back to the model).
|
|
50
|
+
*/
|
|
51
|
+
export async function executeNativeTool(cwd, name, args) {
|
|
52
|
+
if (name === 'read_file') {
|
|
53
|
+
const abs = await resolveWithin(cwd, args?.filePath);
|
|
54
|
+
return await fs.readFile(abs, 'utf8');
|
|
55
|
+
}
|
|
56
|
+
if (name === 'list_directory') {
|
|
57
|
+
const abs = await resolveWithin(cwd, args?.dirPath);
|
|
58
|
+
return (await fs.readdir(abs)).join('\n');
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=nativeTools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeTools.js","sourceRoot":"","sources":["../../src/agent/nativeTools.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,iBAAiB,GAC5B,kHAAkH,CAAC;AAErH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO;uDAC8C,GAAG;4HACkE,CAAC;AAC7H,CAAC;AASD;6CAC6C;AAC7C,MAAM,CAAC,MAAM,YAAY,GAAqB;IAC5C,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,6BAA6B,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,oCAAoC,EAAE;IAC5I,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,kCAAkC,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,yCAAyC,EAAE;CAC3J,CAAC;AAEF,SAAS,YAAY,CAAC,IAAY,EAAE,MAAc,EAAE,GAAY;IAC9D,0EAA0E;IAC1E,wCAAwC;IACxC,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,GAAY;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACxE,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAElC,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IACxC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,IAAY,EAAE,IAAS;IAC1E,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACrD,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nativeTools.test.d.ts","sourceRoot":"","sources":["../../src/agent/nativeTools.test.ts"],"names":[],"mappings":""}
|