@xalia/agent 0.6.4 → 0.6.6
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/agent/src/agent/agent.js +12 -11
- package/dist/agent/src/agent/dummyLLM.js +24 -15
- package/dist/agent/src/agent/llm.js +0 -22
- package/dist/agent/src/agent/mcpServerManager.js +73 -15
- package/dist/agent/src/agent/openAI.js +32 -0
- package/dist/agent/src/agent/openAILLM.js +25 -1
- package/dist/agent/src/agent/openAILLMStreaming.js +8 -3
- package/dist/agent/src/agent/sudoMcpServerManager.js +22 -9
- package/dist/agent/src/chat/client/chatClient.js +2 -1
- package/dist/agent/src/chat/client/sessionClient.js +28 -3
- package/dist/agent/src/chat/data/dbSessionFileModels.js +10 -0
- package/dist/agent/src/chat/protocol/messages.js +1 -0
- package/dist/agent/src/chat/server/chatContextManager.js +4 -4
- package/dist/agent/src/chat/server/conversation.js +1 -1
- package/dist/agent/src/chat/server/imageGeneratorTools.js +7 -4
- package/dist/agent/src/chat/server/openSession.js +85 -12
- package/dist/agent/src/chat/server/sessionFileManager.js +17 -6
- package/dist/agent/src/chat/server/sessionRegistry.js +1 -1
- package/dist/agent/src/chat/server/tools.js +58 -10
- package/dist/agent/src/test/agent.test.js +26 -2
- package/dist/agent/src/test/chatContextManager.test.js +5 -5
- package/dist/agent/src/test/mcpServerManager.test.js +5 -1
- package/dist/agent/src/test/testTools.js +5 -2
- package/dist/agent/src/tool/chatMain.js +23 -3
- package/dist/agent/src/tool/files.js +0 -27
- package/package.json +3 -3
- package/scripts/test_chat +3 -1
- package/src/agent/agent.ts +53 -47
- package/src/agent/agentUtils.ts +7 -7
- package/src/agent/compressingContextManager.ts +4 -9
- package/src/agent/context.ts +28 -37
- package/src/agent/dummyLLM.ts +38 -28
- package/src/agent/iAgentEventHandler.ts +6 -9
- package/src/agent/imageGenLLM.ts +11 -5
- package/src/agent/llm.ts +41 -106
- package/src/agent/mcpServerManager.ts +145 -29
- package/src/agent/openAI.ts +123 -0
- package/src/agent/openAILLM.ts +52 -5
- package/src/agent/openAILLMStreaming.ts +36 -32
- package/src/agent/repeatLLM.ts +5 -6
- package/src/agent/sudoMcpServerManager.ts +48 -16
- package/src/agent/tools.ts +3 -5
- package/src/chat/client/chatClient.ts +3 -1
- package/src/chat/client/sessionClient.ts +47 -7
- package/src/chat/data/dataModels.ts +3 -3
- package/src/chat/data/dbSessionFileModels.ts +22 -0
- package/src/chat/protocol/messages.ts +39 -13
- package/src/chat/server/chatContextManager.ts +20 -24
- package/src/chat/server/conversation.ts +10 -10
- package/src/chat/server/imageGeneratorTools.ts +18 -9
- package/src/chat/server/openSession.ts +111 -22
- package/src/chat/server/sessionFileManager.ts +33 -10
- package/src/chat/server/sessionRegistry.ts +1 -1
- package/src/chat/server/tools.ts +77 -18
- package/src/chat/utils/approvalManager.ts +2 -2
- package/src/test/agent.test.ts +56 -31
- package/src/test/approvalManager.test.ts +2 -2
- package/src/test/chatContextManager.test.ts +11 -14
- package/src/test/compressingContextManager.test.ts +3 -3
- package/src/test/context.test.ts +3 -3
- package/src/test/conversation.test.ts +7 -7
- package/src/test/dbSessionMessages.test.ts +3 -3
- package/src/test/mcpServerManager.test.ts +10 -1
- package/src/test/testTools.ts +44 -33
- package/src/tool/agentChat.ts +10 -8
- package/src/tool/agentMain.ts +2 -2
- package/src/tool/chatMain.ts +38 -6
- package/src/tool/commandPrompt.ts +2 -4
- package/src/tool/files.ts +0 -34
- package/test_data/dummyllm_script_image_gen.json +27 -17
- package/test_data/dummyllm_script_invoke_image_gen_tool.json +9 -2
- package/test_data/dummyllm_script_render_tool.json +29 -0
- package/test_data/dummyllm_script_test_auto_approve.json +81 -0
- package/test_data/dummyllm_script_test_simplecalc_addition.json +29 -0
package/src/test/agent.test.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { OpenAI } from "openai";
|
|
2
1
|
import { expect } from "vitest";
|
|
3
2
|
import { strict as assert } from "assert";
|
|
4
3
|
|
|
@@ -12,10 +11,12 @@ import {
|
|
|
12
11
|
completionToAssistantMessageParam,
|
|
13
12
|
} from "../agent/agent";
|
|
14
13
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
AssistantMessageParam,
|
|
15
|
+
Choice,
|
|
16
|
+
MessageParam,
|
|
17
|
+
MessageToolCall,
|
|
18
|
+
ToolDescriptor,
|
|
19
|
+
ToolMessageParam,
|
|
19
20
|
} from "../agent/llm";
|
|
20
21
|
import { ContextManager } from "../agent/context";
|
|
21
22
|
import { LOCAL_SERVER_URL, SkillManager } from "../agent/sudoMcpServerManager";
|
|
@@ -26,12 +27,13 @@ import {
|
|
|
26
27
|
TestDummyLLM,
|
|
27
28
|
TestErrorLLM,
|
|
28
29
|
} from "./testTools";
|
|
30
|
+
import { DummyLLMScriptEntry } from "../agent/dummyLLM";
|
|
29
31
|
|
|
30
32
|
function clone<T>(a: T): T {
|
|
31
33
|
return JSON.parse(JSON.stringify(a)) as T;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
const DUMMY_SCRIPT:
|
|
36
|
+
const DUMMY_SCRIPT: Choice[] = [
|
|
35
37
|
{
|
|
36
38
|
index: 0,
|
|
37
39
|
finish_reason: "stop",
|
|
@@ -59,13 +61,13 @@ function createCallTestToolScript(
|
|
|
59
61
|
param1: string,
|
|
60
62
|
param2: number
|
|
61
63
|
): {
|
|
62
|
-
script:
|
|
63
|
-
expectCompletions:
|
|
64
|
+
script: Choice[];
|
|
65
|
+
expectCompletions: AssistantMessageParam[];
|
|
64
66
|
expectAgentMessages: string[];
|
|
65
|
-
expectToolResults:
|
|
66
|
-
tool0_descriptor:
|
|
67
|
+
expectToolResults: ToolMessageParam[];
|
|
68
|
+
tool0_descriptor: ToolDescriptor;
|
|
67
69
|
tool0_fn: (agent: Agent, args: unknown) => Promise<ToolCallResult>;
|
|
68
|
-
test_tool_descriptor:
|
|
70
|
+
test_tool_descriptor: ToolDescriptor;
|
|
69
71
|
test_tool_fn: (agent: Agent, args: unknown) => Promise<ToolCallResult>;
|
|
70
72
|
} {
|
|
71
73
|
// A tool with no args
|
|
@@ -75,7 +77,7 @@ function createCallTestToolScript(
|
|
|
75
77
|
properties: {},
|
|
76
78
|
};
|
|
77
79
|
|
|
78
|
-
const tool0_descriptor:
|
|
80
|
+
const tool0_descriptor: ToolDescriptor = {
|
|
79
81
|
type: "function",
|
|
80
82
|
function: {
|
|
81
83
|
name: "tool0",
|
|
@@ -103,7 +105,7 @@ function createCallTestToolScript(
|
|
|
103
105
|
required: ["param1", "param2"],
|
|
104
106
|
};
|
|
105
107
|
|
|
106
|
-
const test_tool_descriptor:
|
|
108
|
+
const test_tool_descriptor: ToolDescriptor = {
|
|
107
109
|
type: "function",
|
|
108
110
|
function: {
|
|
109
111
|
name: "test_tool",
|
|
@@ -120,13 +122,13 @@ function createCallTestToolScript(
|
|
|
120
122
|
return new Promise((r) => {
|
|
121
123
|
r({
|
|
122
124
|
response: `tool_result: '${param1}' '${String(param2)}'`,
|
|
123
|
-
|
|
125
|
+
_meta: { type: "text/plain" },
|
|
124
126
|
});
|
|
125
127
|
});
|
|
126
128
|
};
|
|
127
129
|
|
|
128
|
-
const tool_calls:
|
|
129
|
-
const expectToolResults:
|
|
130
|
+
const tool_calls: MessageToolCall[] = [];
|
|
131
|
+
const expectToolResults: ToolMessageParam[] = [];
|
|
130
132
|
|
|
131
133
|
// First tool call (if requested) is test_tool
|
|
132
134
|
if (tool_call_ids.length > 0) {
|
|
@@ -143,7 +145,7 @@ function createCallTestToolScript(
|
|
|
143
145
|
content: `tool_result: '${param1}' '${String(param2)}'`,
|
|
144
146
|
role: "tool",
|
|
145
147
|
tool_call_id: id,
|
|
146
|
-
|
|
148
|
+
_meta: { type: "text/plain" },
|
|
147
149
|
});
|
|
148
150
|
}
|
|
149
151
|
|
|
@@ -172,7 +174,7 @@ function createCallTestToolScript(
|
|
|
172
174
|
|
|
173
175
|
// A script that uses the tools
|
|
174
176
|
|
|
175
|
-
const script:
|
|
177
|
+
const script: Choice[] = [
|
|
176
178
|
{
|
|
177
179
|
index: 0,
|
|
178
180
|
finish_reason: "tool_calls",
|
|
@@ -218,9 +220,7 @@ function createCallTestToolScript(
|
|
|
218
220
|
}
|
|
219
221
|
|
|
220
222
|
/// Return a dummy agent and a TestAgentEventHandler for tracking messages.
|
|
221
|
-
async function createTestAgent(
|
|
222
|
-
script: OpenAI.Chat.Completions.ChatCompletion.Choice[]
|
|
223
|
-
): Promise<{
|
|
223
|
+
async function createTestAgent(script: Choice[]): Promise<{
|
|
224
224
|
agent: Agent;
|
|
225
225
|
skillManager: SkillManager;
|
|
226
226
|
eventHandler: TestAgentEventHandler;
|
|
@@ -423,8 +423,7 @@ describe("Agent", () => {
|
|
|
423
423
|
// Take a copy of the script now, since this will be updated when the
|
|
424
424
|
// tools redacted their args.
|
|
425
425
|
|
|
426
|
-
const scriptCopy:
|
|
427
|
-
clone(script);
|
|
426
|
+
const scriptCopy: Choice[] = clone(script);
|
|
428
427
|
|
|
429
428
|
// Define the tool to update the arg. The transform is to up-case
|
|
430
429
|
// `param1: string` and add 100 to `param2: number`.
|
|
@@ -455,9 +454,7 @@ describe("Agent", () => {
|
|
|
455
454
|
// Check the event handler was called with all completions and tool
|
|
456
455
|
// results, in the correct order.
|
|
457
456
|
|
|
458
|
-
const transformToolCall = (
|
|
459
|
-
toolCall: ChatCompletionMessageToolCall
|
|
460
|
-
): ChatCompletionMessageToolCall => {
|
|
457
|
+
const transformToolCall = (toolCall: MessageToolCall): MessageToolCall => {
|
|
461
458
|
return {
|
|
462
459
|
...toolCall,
|
|
463
460
|
function: {
|
|
@@ -476,7 +473,7 @@ describe("Agent", () => {
|
|
|
476
473
|
],
|
|
477
474
|
});
|
|
478
475
|
|
|
479
|
-
const allExpect:
|
|
476
|
+
const allExpect: MessageParam[] = [
|
|
480
477
|
transformedFirstMsg,
|
|
481
478
|
...expectToolResults,
|
|
482
479
|
completionToAssistantMessageParam(scriptCopy[1].message),
|
|
@@ -527,16 +524,17 @@ describe("Agent", () => {
|
|
|
527
524
|
// Check the event handler was called with all completions and tool
|
|
528
525
|
// results as expected.
|
|
529
526
|
|
|
530
|
-
const expectToolCallResults:
|
|
531
|
-
|
|
527
|
+
const expectToolCallResults: MessageParam[] = expectToolResults.map(
|
|
528
|
+
(tr) => {
|
|
532
529
|
assert(typeof tr.content === "string");
|
|
533
530
|
return {
|
|
534
531
|
...tr,
|
|
535
532
|
content: transformResult(tr.content),
|
|
536
533
|
};
|
|
537
|
-
}
|
|
534
|
+
}
|
|
535
|
+
);
|
|
538
536
|
|
|
539
|
-
const allExpect:
|
|
537
|
+
const allExpect: MessageParam[] = [
|
|
540
538
|
completionToAssistantMessageParam(script[0].message),
|
|
541
539
|
...expectToolCallResults,
|
|
542
540
|
completionToAssistantMessageParam(script[1].message),
|
|
@@ -561,4 +559,31 @@ describe("Agent", () => {
|
|
|
561
559
|
// Check the Agent has not added the user messages.
|
|
562
560
|
expect(ctxMgr.getLLMContext().length).eql(1);
|
|
563
561
|
});
|
|
562
|
+
|
|
563
|
+
it("supports reasoning token callbacks", async function () {
|
|
564
|
+
const script: DummyLLMScriptEntry[] = [
|
|
565
|
+
{
|
|
566
|
+
finish_reason: "reasoning",
|
|
567
|
+
message: "Some reasoning tokens...",
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
index: 0,
|
|
571
|
+
finish_reason: "stop",
|
|
572
|
+
message: {
|
|
573
|
+
content: "Agent Message",
|
|
574
|
+
refusal: null,
|
|
575
|
+
role: "assistant",
|
|
576
|
+
},
|
|
577
|
+
logprobs: null,
|
|
578
|
+
},
|
|
579
|
+
];
|
|
580
|
+
|
|
581
|
+
const llm = new TestDummyLLM(script);
|
|
582
|
+
const eventHandler = new TestAgentEventHandler();
|
|
583
|
+
const ctxMgr = new ContextManager("SYSTEM_PROMPT", []);
|
|
584
|
+
const agent = Agent.initializeWithLLM(eventHandler, llm, ctxMgr);
|
|
585
|
+
|
|
586
|
+
await agent.userMessageEx("user message 1");
|
|
587
|
+
expect(eventHandler.getReasoning()).eql([script[0].message, ""]);
|
|
588
|
+
});
|
|
564
589
|
});
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ServerToClient,
|
|
10
10
|
} from "../chat/protocol/messages";
|
|
11
11
|
import { ISessionMessageSender } from "../chat/server/openSessionMessageSender";
|
|
12
|
-
import {
|
|
12
|
+
import { MessageToolCall } from "../agent/llm";
|
|
13
13
|
|
|
14
14
|
export class TestAgentPreferencesWriter implements IAgentPreferencesWriter {
|
|
15
15
|
public prefs: Record<string, AgentPreferences | undefined> = {};
|
|
@@ -41,7 +41,7 @@ export class TestMessageSender
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const tc:
|
|
44
|
+
const tc: MessageToolCall = {
|
|
45
45
|
type: "function",
|
|
46
46
|
id: "tool_call_0",
|
|
47
47
|
function: { name: "fn0", arguments: "" },
|
|
@@ -7,10 +7,7 @@ import {
|
|
|
7
7
|
resolveConversationWithCheckpoint,
|
|
8
8
|
} from "../chat/server/chatContextManager";
|
|
9
9
|
import { createUserMessageEnsure } from "../agent/agent";
|
|
10
|
-
import {
|
|
11
|
-
ChatCompletionAssistantMessageParam,
|
|
12
|
-
ChatCompletionToolMessageParam,
|
|
13
|
-
} from "../agent/llm";
|
|
10
|
+
import { AssistantMessageParam, ToolMessageParam } from "../agent/llm";
|
|
14
11
|
import { createCheckpointMessage } from "../agent/compressingContextManager";
|
|
15
12
|
import {
|
|
16
13
|
MESSAGE_INDEX_FULL_INCREMENT,
|
|
@@ -58,7 +55,7 @@ const MESSAGES: SessionMessage[] = [
|
|
|
58
55
|
role: "tool",
|
|
59
56
|
content: "msg501",
|
|
60
57
|
tool_call_id: "tool_call_0",
|
|
61
|
-
|
|
58
|
+
_meta: { type: "text/plain" },
|
|
62
59
|
},
|
|
63
60
|
},
|
|
64
61
|
{
|
|
@@ -115,7 +112,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
115
112
|
userMsgs.map((su) => {
|
|
116
113
|
return {
|
|
117
114
|
role: "user",
|
|
118
|
-
name: su.
|
|
115
|
+
name: su.user_uuid,
|
|
119
116
|
content: su.message,
|
|
120
117
|
};
|
|
121
118
|
})
|
|
@@ -142,7 +139,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
142
139
|
|
|
143
140
|
// A full response (with toolcall) is returned
|
|
144
141
|
|
|
145
|
-
const agentResponseWithToolCall:
|
|
142
|
+
const agentResponseWithToolCall: AssistantMessageParam = {
|
|
146
143
|
role: "assistant",
|
|
147
144
|
tool_calls: [
|
|
148
145
|
{
|
|
@@ -188,7 +185,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
188
185
|
// - 2*MESSAGE_INDEX_FULL_INCREMENT + 1*MESSAGE_INDEX_SUB_INCREMENT
|
|
189
186
|
// - 2*MESSAGE_INDEX_FULL_INCREMENT + 2*MESSAGE_INDEX_SUB_INCREMENT
|
|
190
187
|
|
|
191
|
-
const toolCallResults:
|
|
188
|
+
const toolCallResults: ToolMessageParam[] = [
|
|
192
189
|
{
|
|
193
190
|
role: "tool",
|
|
194
191
|
tool_call_id: "tool_call_0",
|
|
@@ -218,7 +215,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
218
215
|
|
|
219
216
|
// Final agent response
|
|
220
217
|
|
|
221
|
-
const finalAgentResponse:
|
|
218
|
+
const finalAgentResponse: AssistantMessageParam = {
|
|
222
219
|
role: "assistant",
|
|
223
220
|
content: "AgentMessage2",
|
|
224
221
|
};
|
|
@@ -246,7 +243,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
246
243
|
content: createUserMessageEnsure(
|
|
247
244
|
userMsgs[0].message,
|
|
248
245
|
userMsgs[0].imageB64,
|
|
249
|
-
"
|
|
246
|
+
"user0"
|
|
250
247
|
),
|
|
251
248
|
},
|
|
252
249
|
{
|
|
@@ -256,7 +253,7 @@ function testSuccessfulAgentLoop(cm: ChatContextManager, startIdx: number) {
|
|
|
256
253
|
content: createUserMessageEnsure(
|
|
257
254
|
userMsgs[1].message,
|
|
258
255
|
userMsgs[1].imageB64,
|
|
259
|
-
"
|
|
256
|
+
"user1"
|
|
260
257
|
),
|
|
261
258
|
},
|
|
262
259
|
// agent response with tool calls
|
|
@@ -448,14 +445,14 @@ describe("IndexingCompressingContextManager", () => {
|
|
|
448
445
|
expect(llmUserMessages).eql([
|
|
449
446
|
{
|
|
450
447
|
role: "user",
|
|
451
|
-
name: serverUserMessage0.
|
|
448
|
+
name: serverUserMessage0.user_uuid,
|
|
452
449
|
content: serverUserMessage0.message,
|
|
453
450
|
},
|
|
454
451
|
]);
|
|
455
452
|
|
|
456
453
|
// A full response (with toolcall) is returned
|
|
457
454
|
|
|
458
|
-
const agentResponseWithToolCall:
|
|
455
|
+
const agentResponseWithToolCall: AssistantMessageParam = {
|
|
459
456
|
role: "assistant",
|
|
460
457
|
tool_calls: [
|
|
461
458
|
{
|
|
@@ -488,7 +485,7 @@ describe("IndexingCompressingContextManager", () => {
|
|
|
488
485
|
// - 1*MESSAGE_INDEX_FULL_INCREMENT + 1*MESSAGE_INDEX_SUB_INCREMENT
|
|
489
486
|
// - 1*MESSAGE_INDEX_FULL_INCREMENT + 2*MESSAGE_INDEX_SUB_INCREMENT
|
|
490
487
|
|
|
491
|
-
const toolCallResults:
|
|
488
|
+
const toolCallResults: ToolMessageParam[] = [
|
|
492
489
|
{
|
|
493
490
|
role: "tool",
|
|
494
491
|
tool_call_id: "tool_call_0",
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
CompressingContextManager,
|
|
5
5
|
createCheckpointMessage,
|
|
6
6
|
} from "../agent/compressingContextManager";
|
|
7
|
-
import {
|
|
7
|
+
import { MessageParam } from "../agent/llm";
|
|
8
8
|
|
|
9
|
-
const MESSAGES:
|
|
9
|
+
const MESSAGES: MessageParam[] = [
|
|
10
10
|
{ role: "user", content: "msg200" },
|
|
11
11
|
{ role: "assistant", content: "msg300" },
|
|
12
12
|
{ role: "user", content: "msg400" },
|
|
@@ -59,7 +59,7 @@ describe("Compression context", () => {
|
|
|
59
59
|
// - new context is as expected
|
|
60
60
|
|
|
61
61
|
const expectSummary = "Message number 0";
|
|
62
|
-
const expectContext:
|
|
62
|
+
const expectContext: MessageParam[] = [
|
|
63
63
|
{
|
|
64
64
|
role: "system",
|
|
65
65
|
content: "New system prompt",
|
package/src/test/context.test.ts
CHANGED
|
@@ -3,11 +3,11 @@ import { strict as assert } from "assert";
|
|
|
3
3
|
|
|
4
4
|
import { ContextManagerWithWorkspace } from "../agent/context";
|
|
5
5
|
import { createUserMessage } from "../agent/agent";
|
|
6
|
-
import {
|
|
6
|
+
import { MessageParam } from "../agent/llm";
|
|
7
7
|
import { SystemPromptProvider } from "../agent/promptProvider";
|
|
8
8
|
|
|
9
9
|
describe("ContextManagerWithWorkspace", () => {
|
|
10
|
-
const msgs:
|
|
10
|
+
const msgs: MessageParam[] = [
|
|
11
11
|
{ role: "user", content: "message A" },
|
|
12
12
|
{ role: "assistant", content: "message B" },
|
|
13
13
|
{ role: "user", content: "message C" },
|
|
@@ -30,7 +30,7 @@ describe("ContextManagerWithWorkspace", () => {
|
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
32
|
// context with new message and workspace
|
|
33
|
-
const lastMsg:
|
|
33
|
+
const lastMsg: MessageParam = {
|
|
34
34
|
role: "user",
|
|
35
35
|
content: "hello",
|
|
36
36
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { expect } from "vitest";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
AssistantMessageParam,
|
|
4
|
+
MessageParam,
|
|
5
|
+
UserMessageParam,
|
|
6
6
|
} from "../agent/llm";
|
|
7
7
|
import {
|
|
8
8
|
MESSAGE_INDEX_FULL_INCREMENT,
|
|
@@ -13,13 +13,13 @@ import {
|
|
|
13
13
|
import { SessionMessage } from "../chat/data/dataModels";
|
|
14
14
|
|
|
15
15
|
// Fake conversation values.
|
|
16
|
-
const AGENT:
|
|
16
|
+
const AGENT: AssistantMessageParam[] = [
|
|
17
17
|
{ role: "assistant", content: "Message 0" },
|
|
18
18
|
{ role: "assistant", content: "Message 1" },
|
|
19
19
|
{ role: "assistant", content: "Message 2" },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
|
-
const USER:
|
|
22
|
+
const USER: UserMessageParam[] = [
|
|
23
23
|
{ role: "user", content: "Message 0", name: "userA" },
|
|
24
24
|
{ role: "user", content: "Message 1", name: "userA" },
|
|
25
25
|
{ role: "user", content: "Message 2", name: "userA" },
|
|
@@ -45,7 +45,7 @@ describe("Conversation tools", () => {
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
message_idx: 100,
|
|
48
|
-
content: {} as unknown as
|
|
48
|
+
content: {} as unknown as MessageParam,
|
|
49
49
|
is_for_llm: false,
|
|
50
50
|
},
|
|
51
51
|
{
|
|
@@ -85,7 +85,7 @@ describe("Conversation tools", () => {
|
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
message_idx: 5 * MESSAGE_INDEX_FULL_INCREMENT,
|
|
88
|
-
content: {} as unknown as
|
|
88
|
+
content: {} as unknown as MessageParam,
|
|
89
89
|
is_for_llm: false,
|
|
90
90
|
},
|
|
91
91
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect, beforeEach, afterEach, describe, it } from "vitest";
|
|
2
2
|
import { Database } from "../chat/data/database";
|
|
3
3
|
import { SessionMessage } from "../chat/data/dataModels";
|
|
4
|
-
import {
|
|
4
|
+
import { MessageParam } from "../agent/llm";
|
|
5
5
|
import {
|
|
6
6
|
TestUserSpec,
|
|
7
7
|
cleanupTestUser,
|
|
@@ -31,11 +31,11 @@ describe("DB Session Messages", () => {
|
|
|
31
31
|
it("should update conversations", async () => {
|
|
32
32
|
const { sessionId } = await createTestSession(db, testUsers[0]);
|
|
33
33
|
|
|
34
|
-
const CONV_0:
|
|
34
|
+
const CONV_0: MessageParam[] = [
|
|
35
35
|
{ role: "user", content: "message 0" },
|
|
36
36
|
{ role: "assistant", content: "message 1" },
|
|
37
37
|
];
|
|
38
|
-
const CONV_1:
|
|
38
|
+
const CONV_1: MessageParam[] = [
|
|
39
39
|
{ role: "user", content: "message 2" },
|
|
40
40
|
{ role: "assistant", content: "message 3" },
|
|
41
41
|
];
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/require-await */
|
|
2
2
|
import { describe, it, expect, afterAll } from "vitest";
|
|
3
|
+
import { strict as assert } from "assert";
|
|
4
|
+
|
|
3
5
|
import {
|
|
4
6
|
computeQualifiedName,
|
|
7
|
+
isMcpServerToolCallMetaData,
|
|
5
8
|
McpServerManager,
|
|
6
9
|
splitQualifiedName,
|
|
7
10
|
} from "../agent/mcpServerManager";
|
|
@@ -42,6 +45,7 @@ describe("McpServerManager", () => {
|
|
|
42
45
|
expect(availableTools.length).toBeGreaterThan(0);
|
|
43
46
|
|
|
44
47
|
// Initially, no tools are enabled.
|
|
48
|
+
|
|
45
49
|
expect(tm.getOpenAITools().length).toBe(0);
|
|
46
50
|
|
|
47
51
|
// Enable a tool and check we get a description for it.
|
|
@@ -59,7 +63,12 @@ describe("McpServerManager", () => {
|
|
|
59
63
|
const r = await tm.invoke(
|
|
60
64
|
tm.verifyToolCall(qualifiedName, { a: 1000, b: 10 })
|
|
61
65
|
);
|
|
62
|
-
|
|
66
|
+
|
|
67
|
+
assert(r._meta);
|
|
68
|
+
assert(isMcpServerToolCallMetaData(r._meta));
|
|
69
|
+
expect(r._meta["xalia/mcpServerName"]).eql("simplecalc");
|
|
70
|
+
|
|
71
|
+
console.log(`response: ${JSON.stringify(r)}`);
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
// Disable and check we don't get the spec anymore
|
package/src/test/testTools.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { OpenAI } from "openai";
|
|
2
|
-
|
|
3
1
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
AssistantMessageParam,
|
|
3
|
+
MessageParam,
|
|
4
|
+
MessageToolCall,
|
|
5
|
+
ToolMessageParam,
|
|
6
|
+
ContentPartImage,
|
|
7
|
+
ToolDescriptor,
|
|
8
|
+
Completion,
|
|
8
9
|
} from "../agent/llm";
|
|
9
10
|
import { IAgentEventHandler } from "../agent/iAgentEventHandler";
|
|
10
11
|
import { IPlatform } from "../agent/iplatform";
|
|
11
|
-
import { DummyLLM } from "../agent/dummyLLM";
|
|
12
|
+
import { DummyLLM, DummyLLMScriptEntry } from "../agent/dummyLLM";
|
|
12
13
|
import { ILLM } from "../agent/llm";
|
|
13
14
|
|
|
14
15
|
export const DUMMY_PLATFORM: IPlatform = {
|
|
@@ -27,25 +28,25 @@ export const DUMMY_PLATFORM: IPlatform = {
|
|
|
27
28
|
* IAgentEventHandler which records all calls, for testing.
|
|
28
29
|
*/
|
|
29
30
|
export class TestAgentEventHandler implements IAgentEventHandler {
|
|
30
|
-
private all:
|
|
31
|
-
private completions:
|
|
32
|
-
private images:
|
|
31
|
+
private all: MessageParam[] = [];
|
|
32
|
+
private completions: AssistantMessageParam[] = [];
|
|
33
|
+
private images: ContentPartImage[] = [];
|
|
33
34
|
private agentMessages: string[] = [""];
|
|
34
35
|
private reasoning: string[] = [""];
|
|
35
|
-
private toolCalls:
|
|
36
|
-
private agentToolCalls:
|
|
37
|
-
private toolCallResults:
|
|
36
|
+
private toolCalls: MessageToolCall[] = [];
|
|
37
|
+
private agentToolCalls: MessageToolCall[] = [];
|
|
38
|
+
private toolCallResults: ToolMessageParam[] = [];
|
|
38
39
|
|
|
39
|
-
onCompletion(result:
|
|
40
|
+
onCompletion(result: AssistantMessageParam) {
|
|
40
41
|
this.completions.push(result);
|
|
41
42
|
this.all.push(result);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
onImage(image:
|
|
45
|
+
onImage(image: ContentPartImage) {
|
|
45
46
|
this.images.push(image);
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
onToolCallResult(result:
|
|
49
|
+
onToolCallResult(result: ToolMessageParam): void {
|
|
49
50
|
this.toolCallResults.push(result);
|
|
50
51
|
this.all.push(result);
|
|
51
52
|
}
|
|
@@ -69,7 +70,7 @@ export class TestAgentEventHandler implements IAgentEventHandler {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
onToolCall(
|
|
72
|
-
toolCall:
|
|
73
|
+
toolCall: MessageToolCall,
|
|
73
74
|
isAgentTool: boolean
|
|
74
75
|
): Promise<boolean> {
|
|
75
76
|
return new Promise<boolean>((r) => {
|
|
@@ -81,11 +82,11 @@ export class TestAgentEventHandler implements IAgentEventHandler {
|
|
|
81
82
|
});
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
getAll():
|
|
85
|
+
getAll(): MessageParam[] {
|
|
85
86
|
return this.all;
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
getCompletions():
|
|
89
|
+
getCompletions(): AssistantMessageParam[] {
|
|
89
90
|
return this.completions;
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -93,22 +94,26 @@ export class TestAgentEventHandler implements IAgentEventHandler {
|
|
|
93
94
|
return this.agentMessages.slice(0, this.agentMessages.length - 1);
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
getToolCalls():
|
|
97
|
+
getToolCalls(): MessageToolCall[] {
|
|
97
98
|
return this.toolCalls;
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
getAgentToolCalls():
|
|
101
|
+
getAgentToolCalls(): MessageToolCall[] {
|
|
101
102
|
return this.agentToolCalls;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
getToolCallResults():
|
|
105
|
+
getToolCallResults(): ToolMessageParam[] {
|
|
105
106
|
return this.toolCallResults;
|
|
106
107
|
}
|
|
108
|
+
|
|
109
|
+
getReasoning(): string[] {
|
|
110
|
+
return this.reasoning;
|
|
111
|
+
}
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
export type TestLLMRequest = {
|
|
110
|
-
messages:
|
|
111
|
-
tools?:
|
|
115
|
+
messages: MessageParam[];
|
|
116
|
+
tools?: ToolDescriptor[];
|
|
112
117
|
};
|
|
113
118
|
|
|
114
119
|
/**
|
|
@@ -118,18 +123,24 @@ export type TestLLMRequest = {
|
|
|
118
123
|
export class TestDummyLLM extends DummyLLM {
|
|
119
124
|
private readonly requests: TestLLMRequest[];
|
|
120
125
|
|
|
121
|
-
constructor(script:
|
|
126
|
+
constructor(script: DummyLLMScriptEntry[]) {
|
|
122
127
|
super(script);
|
|
123
128
|
this.requests = [];
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
override getConversationResponse(
|
|
127
|
-
messages:
|
|
128
|
-
tools?:
|
|
129
|
-
onMessage?: (msg: string, end: boolean) => Promise<void
|
|
130
|
-
|
|
132
|
+
messages: MessageParam[],
|
|
133
|
+
tools?: ToolDescriptor[],
|
|
134
|
+
onMessage?: (msg: string, end: boolean) => Promise<void>,
|
|
135
|
+
onReasoning?: (reasoning: string) => Promise<void>
|
|
136
|
+
): Promise<Completion> {
|
|
131
137
|
this.requests.push({ messages, tools });
|
|
132
|
-
return super.getConversationResponse(
|
|
138
|
+
return super.getConversationResponse(
|
|
139
|
+
messages,
|
|
140
|
+
tools,
|
|
141
|
+
onMessage,
|
|
142
|
+
onReasoning
|
|
143
|
+
);
|
|
133
144
|
}
|
|
134
145
|
|
|
135
146
|
getRequests(): TestLLMRequest[] {
|
|
@@ -151,10 +162,10 @@ export class TestErrorLLM implements ILLM {
|
|
|
151
162
|
throw new Error("cannot set model");
|
|
152
163
|
}
|
|
153
164
|
getConversationResponse(
|
|
154
|
-
_messages:
|
|
155
|
-
_tools?:
|
|
165
|
+
_messages: MessageParam[],
|
|
166
|
+
_tools?: ToolDescriptor[],
|
|
156
167
|
_onMessage?: (msg: string, end: boolean) => Promise<void>
|
|
157
|
-
): Promise<
|
|
168
|
+
): Promise<Completion> {
|
|
158
169
|
throw new Error("LLM test error");
|
|
159
170
|
}
|
|
160
171
|
}
|
package/src/tool/agentChat.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import yocto from "yocto-spinner";
|
|
2
2
|
import { Spinner } from "yocto-spinner";
|
|
3
|
-
import OpenAI from "openai";
|
|
4
3
|
import chalk from "chalk";
|
|
5
4
|
|
|
6
5
|
import { configuration, utils } from "@xalia/xmcp/tool";
|
|
@@ -15,7 +14,12 @@ import { NODE_PLATFORM } from "./nodePlatform";
|
|
|
15
14
|
import { CommandPrompt } from "./commandPrompt";
|
|
16
15
|
import { IPrompt, Prompt } from "./prompt";
|
|
17
16
|
import { ContextManager } from "../agent/context";
|
|
18
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
ContentPartImage,
|
|
19
|
+
MessageParam,
|
|
20
|
+
MessageToolCall,
|
|
21
|
+
ToolMessageParam,
|
|
22
|
+
} from "../agent/llm";
|
|
19
23
|
|
|
20
24
|
const logger = getLogger();
|
|
21
25
|
|
|
@@ -37,7 +41,7 @@ async function write(msg: string): Promise<void> {
|
|
|
37
41
|
export async function runChat(
|
|
38
42
|
llmUrl: string,
|
|
39
43
|
agentProfile: AgentProfile,
|
|
40
|
-
conversation:
|
|
44
|
+
conversation: MessageParam[] | undefined,
|
|
41
45
|
prompt: string | undefined,
|
|
42
46
|
image: string | undefined,
|
|
43
47
|
llmApiKey: string | undefined,
|
|
@@ -89,7 +93,7 @@ export async function runChat(
|
|
|
89
93
|
const cmdPrompt = new CommandPrompt(repl);
|
|
90
94
|
|
|
91
95
|
let remainingApprovedToolCalls = approveToolsUpTo;
|
|
92
|
-
const onToolCall = async (toolCall:
|
|
96
|
+
const onToolCall = async (toolCall: MessageToolCall) => {
|
|
93
97
|
if (remainingApprovedToolCalls !== 0) {
|
|
94
98
|
--remainingApprovedToolCalls;
|
|
95
99
|
return true;
|
|
@@ -101,14 +105,12 @@ export async function runChat(
|
|
|
101
105
|
return result;
|
|
102
106
|
};
|
|
103
107
|
|
|
104
|
-
const onToolCallResult = (result:
|
|
108
|
+
const onToolCallResult = (result: ToolMessageParam) => {
|
|
105
109
|
// CLI doesn't need to display tool results - they're handled internally
|
|
106
110
|
logger.debug(`Tool call result: ${JSON.stringify(result)}`);
|
|
107
111
|
};
|
|
108
112
|
|
|
109
|
-
const onImage = (
|
|
110
|
-
image: OpenAI.Chat.Completions.ChatCompletionContentPartImage
|
|
111
|
-
) => {
|
|
113
|
+
const onImage = (image: ContentPartImage) => {
|
|
112
114
|
const dataUrl = image.image_url.url;
|
|
113
115
|
void NODE_PLATFORM.renderHTML(`<img src="${dataUrl}" />`);
|
|
114
116
|
};
|