@xalia/agent 0.6.10 → 0.6.11
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/package.json +5 -2
- package/.env.development +0 -6
- package/.env.test +0 -7
- package/.prettierrc.json +0 -11
- package/context_system.md +0 -498
- package/eslint.config.mjs +0 -38
- package/scripts/chat_server +0 -8
- package/scripts/git_message +0 -31
- package/scripts/git_wip +0 -21
- package/scripts/pr_message +0 -18
- package/scripts/pr_review +0 -16
- package/scripts/setup_chat +0 -90
- package/scripts/shutdown_chat_server +0 -42
- package/scripts/start_chat_server +0 -24
- package/scripts/sudomcp_import +0 -23
- package/scripts/test_chat +0 -327
- package/src/agent/agent.ts +0 -699
- package/src/agent/agentUtils.ts +0 -286
- package/src/agent/compressingContextManager.ts +0 -129
- package/src/agent/context.ts +0 -265
- package/src/agent/contextWithWorkspace.ts +0 -162
- package/src/agent/documentSummarizer.ts +0 -157
- package/src/agent/dummyLLM.ts +0 -130
- package/src/agent/iAgentEventHandler.ts +0 -64
- package/src/agent/imageGenLLM.ts +0 -101
- package/src/agent/imageGenerator.ts +0 -45
- package/src/agent/iplatform.ts +0 -18
- package/src/agent/llm.ts +0 -74
- package/src/agent/mcpServerManager.ts +0 -541
- package/src/agent/nullAgentEventHandler.ts +0 -26
- package/src/agent/nullPlatform.ts +0 -13
- package/src/agent/openAI.ts +0 -123
- package/src/agent/openAILLM.ts +0 -99
- package/src/agent/openAILLMStreaming.ts +0 -648
- package/src/agent/promptProvider.ts +0 -87
- package/src/agent/repeatLLM.ts +0 -62
- package/src/agent/sudoMcpServerManager.ts +0 -361
- package/src/agent/test_data/harrypotter.txt +0 -6065
- package/src/agent/tokenAuth.ts +0 -50
- package/src/agent/tokenCounter.test.ts +0 -243
- package/src/agent/tokenCounter.ts +0 -483
- package/src/agent/toolSettings.ts +0 -24
- package/src/agent/tools/calculatorTool.ts +0 -50
- package/src/agent/tools/contentExtractors/htmlToText.ts +0 -61
- package/src/agent/tools/contentExtractors/pdfToText.ts +0 -60
- package/src/agent/tools/datetimeTool.ts +0 -41
- package/src/agent/tools/fileManager/fileManagerTool.ts +0 -199
- package/src/agent/tools/fileManager/index.ts +0 -50
- package/src/agent/tools/fileManager/memoryFileManager.ts +0 -120
- package/src/agent/tools/fileManager/mimeTypes.ts +0 -60
- package/src/agent/tools/fileManager/prompt.ts +0 -38
- package/src/agent/tools/fileManager/types.ts +0 -189
- package/src/agent/tools/index.ts +0 -49
- package/src/agent/tools/openUrlTool.ts +0 -62
- package/src/agent/tools/renderTool.ts +0 -92
- package/src/agent/tools/utils.ts +0 -74
- package/src/agent/tools/webSearch.ts +0 -138
- package/src/agent/tools/webSearchTool.ts +0 -44
- package/src/chat/client/chatClient.ts +0 -967
- package/src/chat/client/connection.test.ts +0 -241
- package/src/chat/client/connection.ts +0 -286
- package/src/chat/client/constants.ts +0 -1
- package/src/chat/client/index.ts +0 -21
- package/src/chat/client/interfaces.ts +0 -34
- package/src/chat/client/sessionClient.ts +0 -574
- package/src/chat/client/sessionFiles.ts +0 -142
- package/src/chat/client/teamManager.ts +0 -29
- package/src/chat/constants.ts +0 -6
- package/src/chat/data/apiKeyManager.ts +0 -76
- package/src/chat/data/dataModels.ts +0 -107
- package/src/chat/data/database.ts +0 -997
- package/src/chat/data/dbMcpServerConfigs.ts +0 -59
- package/src/chat/data/dbSessionFiles.ts +0 -107
- package/src/chat/data/dbSessionMessages.ts +0 -102
- package/src/chat/protocol/connectionMessages.ts +0 -49
- package/src/chat/protocol/constants.ts +0 -55
- package/src/chat/protocol/errors.ts +0 -16
- package/src/chat/protocol/messages.ts +0 -899
- package/src/chat/server/README.md +0 -127
- package/src/chat/server/chatContextManager.ts +0 -660
- package/src/chat/server/connectionManager.test.ts +0 -246
- package/src/chat/server/connectionManager.ts +0 -506
- package/src/chat/server/conversation.ts +0 -319
- package/src/chat/server/errorUtils.ts +0 -28
- package/src/chat/server/imageGeneratorTools.ts +0 -179
- package/src/chat/server/openAIRouterLLM.ts +0 -168
- package/src/chat/server/openSession.ts +0 -1945
- package/src/chat/server/openSessionMessageSender.ts +0 -4
- package/src/chat/server/promptRefiner.ts +0 -106
- package/src/chat/server/server.ts +0 -178
- package/src/chat/server/sessionFileManager.ts +0 -151
- package/src/chat/server/sessionRegistry.test.ts +0 -137
- package/src/chat/server/sessionRegistry.ts +0 -1553
- package/src/chat/server/test-utils/mockFactories.ts +0 -422
- package/src/chat/server/titleGenerator.test.ts +0 -103
- package/src/chat/server/titleGenerator.ts +0 -143
- package/src/chat/server/tools.ts +0 -170
- package/src/chat/utils/agentSessionMap.ts +0 -76
- package/src/chat/utils/approvalManager.ts +0 -189
- package/src/chat/utils/asyncLock.ts +0 -43
- package/src/chat/utils/asyncQueue.ts +0 -62
- package/src/chat/utils/multiAsyncQueue.ts +0 -66
- package/src/chat/utils/responseAwaiter.ts +0 -181
- package/src/chat/utils/userResolver.ts +0 -48
- package/src/chat/utils/websocket.ts +0 -16
- package/src/index.ts +0 -0
- package/src/test/agent.test.ts +0 -584
- package/src/test/approvalManager.test.ts +0 -141
- package/src/test/chatContextManager.test.ts +0 -552
- package/src/test/clientServerConnection.test.ts +0 -205
- package/src/test/compressingContextManager.test.ts +0 -77
- package/src/test/context.test.ts +0 -150
- package/src/test/contextTestTools.ts +0 -95
- package/src/test/conversation.test.ts +0 -109
- package/src/test/db.test.ts +0 -363
- package/src/test/dbMcpServerConfigs.test.ts +0 -112
- package/src/test/dbSessionFiles.test.ts +0 -258
- package/src/test/dbSessionMessages.test.ts +0 -85
- package/src/test/dbTestTools.ts +0 -157
- package/src/test/imageLoad.test.ts +0 -15
- package/src/test/mcpServerManager.test.ts +0 -114
- package/src/test/multiAsyncQueue.test.ts +0 -183
- package/src/test/openaiStreaming.test.ts +0 -177
- package/src/test/prompt.test.ts +0 -27
- package/src/test/promptProvider.test.ts +0 -33
- package/src/test/responseAwaiter.test.ts +0 -103
- package/src/test/sudoMcpServerManager.test.ts +0 -63
- package/src/test/testTools.ts +0 -176
- package/src/test/tools.test.ts +0 -64
- package/src/tool/agentChat.ts +0 -203
- package/src/tool/agentMain.ts +0 -180
- package/src/tool/chatMain.ts +0 -621
- package/src/tool/commandPrompt.ts +0 -264
- package/src/tool/files.ts +0 -82
- package/src/tool/main.ts +0 -25
- package/src/tool/nodePlatform.ts +0 -73
- package/src/tool/options.ts +0 -144
- package/src/tool/prompt.ts +0 -101
- package/test_data/background_test_profile.json +0 -6
- package/test_data/background_test_script.json +0 -11
- package/test_data/dummyllm_script_crash.json +0 -32
- package/test_data/dummyllm_script_image_gen.json +0 -19
- package/test_data/dummyllm_script_image_gen_fe.json +0 -29
- package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
- package/test_data/dummyllm_script_render_tool.json +0 -29
- package/test_data/dummyllm_script_simplecalc.json +0 -28
- package/test_data/dummyllm_script_test_auto_approve.json +0 -81
- package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
- package/test_data/frog.png +0 -0
- package/test_data/frog.png.b64 +0 -1
- package/test_data/git_message_profile.json +0 -4
- package/test_data/git_wip_system.txt +0 -5
- package/test_data/image_gen_test_profile.json +0 -5
- package/test_data/pr_message_profile.json +0 -4
- package/test_data/pr_review_profile.json +0 -4
- package/test_data/prompt_simplecalc.txt +0 -1
- package/test_data/simplecalc_profile.json +0 -4
- package/test_data/sudomcp_import_profile.json +0 -4
- package/test_data/test_script_profile.json +0 -8
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -39
package/src/test/testTools.ts
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AssistantMessageParam,
|
|
3
|
-
MessageParam,
|
|
4
|
-
MessageToolCall,
|
|
5
|
-
ToolMessageParam,
|
|
6
|
-
ContentPartImage,
|
|
7
|
-
ToolDescriptor,
|
|
8
|
-
Completion,
|
|
9
|
-
} from "../agent/llm";
|
|
10
|
-
import { IAgentEventHandler } from "../agent/iAgentEventHandler";
|
|
11
|
-
import { IPlatform } from "../agent/iplatform";
|
|
12
|
-
import { DummyLLM, DummyLLMScriptEntry } from "../agent/dummyLLM";
|
|
13
|
-
import { ILLM } from "../agent/llm";
|
|
14
|
-
|
|
15
|
-
export const DUMMY_PLATFORM: IPlatform = {
|
|
16
|
-
openUrl: () => {
|
|
17
|
-
throw Error("unimpl");
|
|
18
|
-
},
|
|
19
|
-
load: () => {
|
|
20
|
-
throw Error("unimpl");
|
|
21
|
-
},
|
|
22
|
-
renderHTML: () => {
|
|
23
|
-
throw Error("unimpl");
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* IAgentEventHandler which records all calls, for testing.
|
|
29
|
-
*/
|
|
30
|
-
export class TestAgentEventHandler implements IAgentEventHandler {
|
|
31
|
-
private all: MessageParam[] = [];
|
|
32
|
-
private completions: AssistantMessageParam[] = [];
|
|
33
|
-
private images: ContentPartImage[] = [];
|
|
34
|
-
private agentMessages: string[] = [""];
|
|
35
|
-
private reasoning: string[] = [""];
|
|
36
|
-
private toolCalls: MessageToolCall[] = [];
|
|
37
|
-
private agentToolCalls: MessageToolCall[] = [];
|
|
38
|
-
private toolCallResults: ToolMessageParam[] = [];
|
|
39
|
-
|
|
40
|
-
onCompletion(result: AssistantMessageParam) {
|
|
41
|
-
this.completions.push(result);
|
|
42
|
-
this.all.push(result);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
onImage(image: ContentPartImage) {
|
|
46
|
-
this.images.push(image);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
onToolCallResult(result: ToolMessageParam): void {
|
|
50
|
-
this.toolCallResults.push(result);
|
|
51
|
-
this.all.push(result);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
onAgentMessage(chunk: string, isEnd: boolean): Promise<void> {
|
|
55
|
-
this.agentMessages[this.agentMessages.length - 1] += chunk;
|
|
56
|
-
if (isEnd) {
|
|
57
|
-
this.agentMessages.push("");
|
|
58
|
-
this.reasoning.push("");
|
|
59
|
-
}
|
|
60
|
-
return new Promise<void>((r) => {
|
|
61
|
-
r();
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
onReasoning(reasoning: string): Promise<void> {
|
|
66
|
-
this.reasoning[this.reasoning.length - 1] += reasoning;
|
|
67
|
-
return new Promise<void>((r) => {
|
|
68
|
-
r();
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
onToolCall(
|
|
73
|
-
toolCall: MessageToolCall,
|
|
74
|
-
isAgentTool: boolean
|
|
75
|
-
): Promise<boolean> {
|
|
76
|
-
return new Promise<boolean>((r) => {
|
|
77
|
-
this.toolCalls.push(toolCall);
|
|
78
|
-
if (isAgentTool) {
|
|
79
|
-
this.agentToolCalls.push(toolCall);
|
|
80
|
-
}
|
|
81
|
-
r(true);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
getAll(): MessageParam[] {
|
|
86
|
-
return this.all;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getCompletions(): AssistantMessageParam[] {
|
|
90
|
-
return this.completions;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
getAgentMessages(): string[] {
|
|
94
|
-
return this.agentMessages.slice(0, this.agentMessages.length - 1);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
getToolCalls(): MessageToolCall[] {
|
|
98
|
-
return this.toolCalls;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
getAgentToolCalls(): MessageToolCall[] {
|
|
102
|
-
return this.agentToolCalls;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
getToolCallResults(): ToolMessageParam[] {
|
|
106
|
-
return this.toolCallResults;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
getReasoning(): string[] {
|
|
110
|
-
return this.reasoning;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export type TestLLMRequest = {
|
|
115
|
-
messages: MessageParam[];
|
|
116
|
-
tools?: ToolDescriptor[];
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Extension of Dummy which records requests. Doesn't inherit due to the
|
|
121
|
-
* static initializers.
|
|
122
|
-
*/
|
|
123
|
-
export class TestDummyLLM extends DummyLLM {
|
|
124
|
-
private readonly requests: TestLLMRequest[];
|
|
125
|
-
|
|
126
|
-
constructor(script: DummyLLMScriptEntry[]) {
|
|
127
|
-
super(script);
|
|
128
|
-
this.requests = [];
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
override getConversationResponse(
|
|
132
|
-
messages: MessageParam[],
|
|
133
|
-
tools?: ToolDescriptor[],
|
|
134
|
-
onMessage?: (msg: string, end: boolean) => Promise<void>,
|
|
135
|
-
onReasoning?: (reasoning: string) => Promise<void>
|
|
136
|
-
): Promise<{ stop: (msg: string) => void; completion: Promise<Completion> }> {
|
|
137
|
-
this.requests.push({ messages, tools });
|
|
138
|
-
return super.getConversationResponse(
|
|
139
|
-
messages,
|
|
140
|
-
tools,
|
|
141
|
-
onMessage,
|
|
142
|
-
onReasoning
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
getRequests(): TestLLMRequest[] {
|
|
147
|
-
return this.requests;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* An LLM which always errors out.
|
|
153
|
-
*/
|
|
154
|
-
export class TestErrorLLM implements ILLM {
|
|
155
|
-
getModel(): string {
|
|
156
|
-
return "error";
|
|
157
|
-
}
|
|
158
|
-
getUrl(): string {
|
|
159
|
-
return "error://";
|
|
160
|
-
}
|
|
161
|
-
setModel(_model: string): void {
|
|
162
|
-
throw new Error("cannot set model");
|
|
163
|
-
}
|
|
164
|
-
getConversationResponse(
|
|
165
|
-
_messages: MessageParam[],
|
|
166
|
-
_tools?: ToolDescriptor[],
|
|
167
|
-
_onMessage?: (msg: string, end: boolean) => Promise<void>
|
|
168
|
-
): Promise<{ stop: (msg: string) => void; completion: Promise<Completion> }> {
|
|
169
|
-
return Promise.resolve({
|
|
170
|
-
stop: () => {},
|
|
171
|
-
completion: ((): Promise<Completion> => {
|
|
172
|
-
throw new Error("LLM test error");
|
|
173
|
-
})(),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
}
|
package/src/test/tools.test.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { readFileSync } from "fs";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import {
|
|
5
|
-
calculatorEval,
|
|
6
|
-
isoWithTimezone,
|
|
7
|
-
makeParseArgsFn,
|
|
8
|
-
openURL,
|
|
9
|
-
} from "../agent/tools";
|
|
10
|
-
import { pdfToText } from "../agent/tools/contentExtractors/pdfToText";
|
|
11
|
-
|
|
12
|
-
describe("Tools", () => {
|
|
13
|
-
it("time_now should contain timezone", function () {
|
|
14
|
-
let time = isoWithTimezone("UTC");
|
|
15
|
-
console.log(time);
|
|
16
|
-
expect(time).includes("UTC");
|
|
17
|
-
|
|
18
|
-
time = isoWithTimezone("Asia/Tokyo");
|
|
19
|
-
console.log(time);
|
|
20
|
-
expect(time).includes("GMT+9");
|
|
21
|
-
expect(time).includes("Asia/Tokyo");
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("arithmetic should eval expressions", function () {
|
|
25
|
-
expect(calculatorEval("(3*4)-2")).toEqual("10");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("openUrl grabs text from url without error", async function () {
|
|
29
|
-
const text = await openURL("https://www.google.com/");
|
|
30
|
-
console.log(text);
|
|
31
|
-
expect(text).not.contains("rror");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("makeParseArgsFn behaves correctly", () => {
|
|
35
|
-
const parseNameValue = makeParseArgsFn(["name", "value"] as const);
|
|
36
|
-
expect(parseNameValue({ name: "adsf", value: "qwer" })).toEqual({
|
|
37
|
-
name: "adsf",
|
|
38
|
-
value: "qwer",
|
|
39
|
-
});
|
|
40
|
-
expect(() => parseNameValue({ name: "adsf" })).toThrow();
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("PDF extraction", () => {
|
|
45
|
-
// GAIA benchmark test case: extract fish bag volume from Leicester paper
|
|
46
|
-
it("extracts text from PDF file (GAIA benchmark)", async function () {
|
|
47
|
-
// Use local PDF file instead of fetching from external URL
|
|
48
|
-
// The PDF is the University of Leicester paper about dragon diet
|
|
49
|
-
const pdfPath = join(__dirname, "../../..", "frontend/tests/paper.pdf");
|
|
50
|
-
const pdfBuffer = readFileSync(pdfPath);
|
|
51
|
-
const arrayBuffer = pdfBuffer.buffer.slice(
|
|
52
|
-
pdfBuffer.byteOffset,
|
|
53
|
-
pdfBuffer.byteOffset + pdfBuffer.byteLength
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const text = await pdfToText(arrayBuffer);
|
|
57
|
-
|
|
58
|
-
// The paper should contain the fish bag volume calculation: 0.1777 m³
|
|
59
|
-
expect(text).toContain("0.1777");
|
|
60
|
-
|
|
61
|
-
// Should also contain key terms from the paper
|
|
62
|
-
expect(text.toLowerCase()).toContain("fish");
|
|
63
|
-
});
|
|
64
|
-
});
|
package/src/tool/agentChat.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
|
|
3
|
-
type Spinner = {
|
|
4
|
-
start: () => Spinner;
|
|
5
|
-
stop: () => Spinner;
|
|
6
|
-
clear: () => Spinner;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
async function createSpinner(): Promise<Spinner> {
|
|
10
|
-
const { default: yocto } = await import("yocto-spinner");
|
|
11
|
-
return yocto();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
import { configuration, utils } from "@xalia/xmcp/tool";
|
|
15
|
-
import { getLogger } from "@xalia/xmcp/sdk";
|
|
16
|
-
|
|
17
|
-
import { AgentProfile } from "../agent/agent";
|
|
18
|
-
import { createAgentWithSkills } from "../agent/agentUtils";
|
|
19
|
-
import { IAgentEventHandler } from "../agent/iAgentEventHandler";
|
|
20
|
-
|
|
21
|
-
import { loadImageAsDataUrlOrUndefined } from "./files";
|
|
22
|
-
import { NODE_PLATFORM } from "./nodePlatform";
|
|
23
|
-
import { CommandPrompt } from "./commandPrompt";
|
|
24
|
-
import { IPrompt, Prompt } from "./prompt";
|
|
25
|
-
import { ContextManager } from "../agent/context";
|
|
26
|
-
import {
|
|
27
|
-
ContentPartImage,
|
|
28
|
-
MessageParam,
|
|
29
|
-
MessageToolCall,
|
|
30
|
-
ToolMessageParam,
|
|
31
|
-
} from "../agent/llm";
|
|
32
|
-
|
|
33
|
-
const logger = getLogger();
|
|
34
|
-
|
|
35
|
-
export const DEFAULT_AGENT_LLM_MODEL =
|
|
36
|
-
process.env["DEFAULT_LLM_MODEL"] || "anthropic/claude-sonnet-4.5";
|
|
37
|
-
|
|
38
|
-
async function write(msg: string): Promise<void> {
|
|
39
|
-
return new Promise((resolve, err) => {
|
|
40
|
-
process.stdout.write(msg, (e) => {
|
|
41
|
-
if (e) {
|
|
42
|
-
err(e);
|
|
43
|
-
} else {
|
|
44
|
-
resolve();
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function runChat(
|
|
51
|
-
llmUrl: string,
|
|
52
|
-
agentProfile: AgentProfile,
|
|
53
|
-
conversation: MessageParam[] | undefined,
|
|
54
|
-
prompt: string | undefined,
|
|
55
|
-
image: string | undefined,
|
|
56
|
-
llmApiKey: string | undefined,
|
|
57
|
-
sudomcpConfig: configuration.Configuration,
|
|
58
|
-
approveToolsUpTo: number,
|
|
59
|
-
stream: boolean
|
|
60
|
-
) {
|
|
61
|
-
// In chat mode, just print the messages. Ask for tool confirmation
|
|
62
|
-
// unless approveTools is set.
|
|
63
|
-
|
|
64
|
-
const spinner: Spinner = await createSpinner();
|
|
65
|
-
let first = true;
|
|
66
|
-
let reasoningFirst = true;
|
|
67
|
-
|
|
68
|
-
const onAgentMessage = async (msg: string, msgEnd: boolean) => {
|
|
69
|
-
if (first) {
|
|
70
|
-
first = false;
|
|
71
|
-
|
|
72
|
-
if (!reasoningFirst) {
|
|
73
|
-
await write(`${chalk.grey("]")}\n`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
await write("AGENT: ");
|
|
77
|
-
spinner.stop().clear();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (msg) {
|
|
81
|
-
await write(msg);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (msgEnd) {
|
|
85
|
-
await write("\n");
|
|
86
|
-
first = true;
|
|
87
|
-
reasoningFirst = true;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const onReasoning = async (reasoning: string) => {
|
|
92
|
-
logger.debug(`[AgentChat.onReasoning]: ${reasoning}`);
|
|
93
|
-
if (reasoningFirst) {
|
|
94
|
-
spinner.stop().clear();
|
|
95
|
-
await write(chalk.grey("[REASONING: "));
|
|
96
|
-
reasoningFirst = false;
|
|
97
|
-
}
|
|
98
|
-
await write(chalk.grey(reasoning));
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const repl: IPrompt = new Prompt();
|
|
102
|
-
const cmdPrompt = new CommandPrompt(repl);
|
|
103
|
-
|
|
104
|
-
let remainingApprovedToolCalls = approveToolsUpTo;
|
|
105
|
-
const onToolCall = async (toolCall: MessageToolCall) => {
|
|
106
|
-
if (remainingApprovedToolCalls !== 0) {
|
|
107
|
-
--remainingApprovedToolCalls;
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
spinner.stop().clear();
|
|
112
|
-
const result = await cmdPrompt.promptToolCall(toolCall);
|
|
113
|
-
spinner.start();
|
|
114
|
-
return result;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const onToolCallResult = (result: ToolMessageParam) => {
|
|
118
|
-
// CLI doesn't need to display tool results - they're handled internally
|
|
119
|
-
logger.debug(`Tool call result: ${JSON.stringify(result)}`);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const onImage = (image: ContentPartImage) => {
|
|
123
|
-
const dataUrl = image.image_url.url;
|
|
124
|
-
void NODE_PLATFORM.renderHTML(`<img src="${dataUrl}" />`);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// Create event handler for CLI agent
|
|
128
|
-
const eventHandler: IAgentEventHandler = {
|
|
129
|
-
onCompletion: () => {},
|
|
130
|
-
onImage,
|
|
131
|
-
onAgentMessage,
|
|
132
|
-
onReasoning,
|
|
133
|
-
onToolCall,
|
|
134
|
-
onToolCallResult,
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// Create agent
|
|
138
|
-
|
|
139
|
-
const [agent, sudoMcpServerManager] = await createAgentWithSkills(
|
|
140
|
-
llmUrl,
|
|
141
|
-
agentProfile.model || DEFAULT_AGENT_LLM_MODEL,
|
|
142
|
-
eventHandler,
|
|
143
|
-
NODE_PLATFORM,
|
|
144
|
-
new ContextManager(agentProfile.system_prompt, conversation || []),
|
|
145
|
-
llmApiKey,
|
|
146
|
-
sudomcpConfig,
|
|
147
|
-
agentProfile.mcp_settings,
|
|
148
|
-
utils.FRONTEND_PROD_AUTHORIZED_URL,
|
|
149
|
-
stream
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
// Opening banner
|
|
153
|
-
console.log(chalk.green("SudoMCP Agent CLI"));
|
|
154
|
-
console.log(
|
|
155
|
-
`(Type ${chalk.yellow("/h")} for help, ${chalk.yellow("/q")} to quit.)`
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// Display first prompt if supplied
|
|
159
|
-
if (prompt) {
|
|
160
|
-
console.log(`USER: ${prompt}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Conversation loop
|
|
164
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
165
|
-
while (true) {
|
|
166
|
-
if (!prompt) {
|
|
167
|
-
const [msg, img] = await cmdPrompt.getNextPrompt(
|
|
168
|
-
agent,
|
|
169
|
-
sudoMcpServerManager
|
|
170
|
-
);
|
|
171
|
-
if (!msg && !img) {
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
prompt = msg;
|
|
175
|
-
image = img;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
image = loadImageAsDataUrlOrUndefined(image);
|
|
179
|
-
|
|
180
|
-
// Pass the prompt and image to the Agent
|
|
181
|
-
try {
|
|
182
|
-
spinner.start();
|
|
183
|
-
await agent.userMessageEx(prompt, image);
|
|
184
|
-
} catch (e) {
|
|
185
|
-
console.log(`ERROR: ${String(e)}`);
|
|
186
|
-
console.log(` STACK: ${(e as Error).stack ?? "undefined"}`);
|
|
187
|
-
}
|
|
188
|
-
prompt = undefined;
|
|
189
|
-
image = undefined;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Shutdown the agent
|
|
193
|
-
|
|
194
|
-
await cmdPrompt.shutdown();
|
|
195
|
-
await agent.shutdown();
|
|
196
|
-
|
|
197
|
-
logger.debug("shutdown done");
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Read lines from the prompt, parsing any commands, and return once there is
|
|
202
|
-
* a prompt and/or image for the llm. Both undefined means exit.
|
|
203
|
-
*/
|
package/src/tool/agentMain.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as dotenv from "dotenv";
|
|
3
|
-
import { command, option, flag, optional, string } from "cmd-ts";
|
|
4
|
-
import { strict as assert } from "assert";
|
|
5
|
-
|
|
6
|
-
import { configuration, utils } from "@xalia/xmcp/tool";
|
|
7
|
-
import { getLogger } from "@xalia/xmcp/sdk";
|
|
8
|
-
|
|
9
|
-
import { AgentProfile } from "../agent/agent";
|
|
10
|
-
import { runOneShot } from "../agent/agentUtils";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
llmUrl,
|
|
14
|
-
llmApiKey,
|
|
15
|
-
promptFile,
|
|
16
|
-
oneShot,
|
|
17
|
-
approveTools,
|
|
18
|
-
approveToolsUpTo,
|
|
19
|
-
imageFile,
|
|
20
|
-
} from "./options";
|
|
21
|
-
import {
|
|
22
|
-
loadFileOrUndefined,
|
|
23
|
-
loadFileOrStdin,
|
|
24
|
-
loadImageAsDataUrlOrUndefined,
|
|
25
|
-
} from "./files";
|
|
26
|
-
import { DEFAULT_AGENT_LLM_MODEL, runChat } from "./agentChat";
|
|
27
|
-
import { NODE_PLATFORM } from "./nodePlatform";
|
|
28
|
-
import { MessageParam } from "../agent/llm";
|
|
29
|
-
|
|
30
|
-
dotenv.config();
|
|
31
|
-
|
|
32
|
-
const logger = getLogger();
|
|
33
|
-
|
|
34
|
-
export const agentMain = command({
|
|
35
|
-
name: "main",
|
|
36
|
-
args: {
|
|
37
|
-
promptFile,
|
|
38
|
-
imageFile,
|
|
39
|
-
llmUrl,
|
|
40
|
-
llmApiKey,
|
|
41
|
-
oneShot,
|
|
42
|
-
approveTools,
|
|
43
|
-
approveToolsUpTo,
|
|
44
|
-
sudomcpConfigFile: option({
|
|
45
|
-
type: optional(string),
|
|
46
|
-
long: "sudomcp-config-file",
|
|
47
|
-
description:
|
|
48
|
-
"SudoMCP config file (content or file, default: ~/config/..)",
|
|
49
|
-
env: "SUDOMCP_CONFIG",
|
|
50
|
-
}),
|
|
51
|
-
conversationFile: option({
|
|
52
|
-
type: optional(string),
|
|
53
|
-
long: "conversation",
|
|
54
|
-
description: "Restore conversation (content or file) (see /wc)",
|
|
55
|
-
env: "CONVERSATION",
|
|
56
|
-
}),
|
|
57
|
-
conversationOutputFile: option({
|
|
58
|
-
type: optional(string),
|
|
59
|
-
long: "conversation-output",
|
|
60
|
-
description: "Save final conversation to file (--one-shot mode)",
|
|
61
|
-
env: "CONVERSATION_OUTPUT",
|
|
62
|
-
}),
|
|
63
|
-
agentProfileFile: option({
|
|
64
|
-
type: optional(string),
|
|
65
|
-
long: "agent-profile",
|
|
66
|
-
description: "Agent profile (content or filename)",
|
|
67
|
-
env: "AGENT_PROFILE",
|
|
68
|
-
}),
|
|
69
|
-
noStreaming: flag({
|
|
70
|
-
long: "no-stream",
|
|
71
|
-
description: "Disable streaming (chat mode only)",
|
|
72
|
-
}),
|
|
73
|
-
},
|
|
74
|
-
handler: async ({
|
|
75
|
-
promptFile,
|
|
76
|
-
imageFile,
|
|
77
|
-
llmUrl,
|
|
78
|
-
llmApiKey,
|
|
79
|
-
oneShot,
|
|
80
|
-
approveTools,
|
|
81
|
-
approveToolsUpTo,
|
|
82
|
-
sudomcpConfigFile,
|
|
83
|
-
conversationFile,
|
|
84
|
-
conversationOutputFile,
|
|
85
|
-
agentProfileFile,
|
|
86
|
-
noStreaming,
|
|
87
|
-
}): Promise<void> => {
|
|
88
|
-
approveToolsUpTo = (() => {
|
|
89
|
-
if (typeof approveToolsUpTo === "undefined") {
|
|
90
|
-
// For the non-interactive case, `--approve-tools` is ignored.
|
|
91
|
-
if (oneShot) {
|
|
92
|
-
return -1;
|
|
93
|
-
}
|
|
94
|
-
return approveTools ? -1 : 0;
|
|
95
|
-
}
|
|
96
|
-
return approveToolsUpTo;
|
|
97
|
-
})();
|
|
98
|
-
assert(typeof approveToolsUpTo === "number");
|
|
99
|
-
|
|
100
|
-
// Load the AgentProfile or use a default
|
|
101
|
-
|
|
102
|
-
const agentProfile: AgentProfile = (() => {
|
|
103
|
-
let agentProfile = utils.loadContentOrFileOrUndefined(
|
|
104
|
-
agentProfileFile,
|
|
105
|
-
AgentProfile
|
|
106
|
-
);
|
|
107
|
-
if (!agentProfile) {
|
|
108
|
-
agentProfile = new AgentProfile(
|
|
109
|
-
undefined,
|
|
110
|
-
"You are a helpful agent",
|
|
111
|
-
{}
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return agentProfile;
|
|
116
|
-
})();
|
|
117
|
-
logger.debug(`agent config: ${JSON.stringify(agentProfile)}`);
|
|
118
|
-
|
|
119
|
-
// Read sudomcp config file. This will be used for SudoMcpServerManager,
|
|
120
|
-
// and also to fall back to the sudomcp api key if an explicit llmApiKey
|
|
121
|
-
// was not given.
|
|
122
|
-
|
|
123
|
-
const sudomcpConfig = configuration.loadEnsureConfig(sudomcpConfigFile);
|
|
124
|
-
if (!llmApiKey) {
|
|
125
|
-
llmApiKey = sudomcpConfig.api_key;
|
|
126
|
-
logger.debug(`using xmcp api key: ${llmApiKey}`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Restore conversation from value or file.
|
|
130
|
-
|
|
131
|
-
const startingConversation: MessageParam[] | undefined =
|
|
132
|
-
utils.loadContentOrFileOrUndefined(conversationFile);
|
|
133
|
-
logger.debug(
|
|
134
|
-
`startingConversation: ${JSON.stringify(startingConversation)}`
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
// Run in one-shot mode or chat-mode
|
|
138
|
-
|
|
139
|
-
if (oneShot) {
|
|
140
|
-
if (!promptFile) {
|
|
141
|
-
throw new Error("one-shot mode requires a prompt");
|
|
142
|
-
}
|
|
143
|
-
const prompt = await loadFileOrStdin(promptFile);
|
|
144
|
-
|
|
145
|
-
const { response, conversation } = await runOneShot(
|
|
146
|
-
llmUrl,
|
|
147
|
-
agentProfile,
|
|
148
|
-
DEFAULT_AGENT_LLM_MODEL,
|
|
149
|
-
startingConversation,
|
|
150
|
-
NODE_PLATFORM,
|
|
151
|
-
prompt,
|
|
152
|
-
loadImageAsDataUrlOrUndefined(imageFile),
|
|
153
|
-
llmApiKey,
|
|
154
|
-
sudomcpConfig,
|
|
155
|
-
approveToolsUpTo
|
|
156
|
-
);
|
|
157
|
-
console.log(response);
|
|
158
|
-
|
|
159
|
-
if (conversationOutputFile) {
|
|
160
|
-
logger.debug(`writing conversation to ${conversationOutputFile}:`);
|
|
161
|
-
logger.debug(` conversation: ${JSON.stringify(conversation)}`);
|
|
162
|
-
|
|
163
|
-
fs.writeFileSync(conversationOutputFile, JSON.stringify(conversation));
|
|
164
|
-
}
|
|
165
|
-
} else {
|
|
166
|
-
const prompt = loadFileOrUndefined(promptFile);
|
|
167
|
-
return runChat(
|
|
168
|
-
llmUrl,
|
|
169
|
-
agentProfile,
|
|
170
|
-
startingConversation,
|
|
171
|
-
prompt,
|
|
172
|
-
imageFile,
|
|
173
|
-
llmApiKey,
|
|
174
|
-
sudomcpConfig,
|
|
175
|
-
approveToolsUpTo,
|
|
176
|
-
!noStreaming
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
});
|