@xalia/agent 0.6.2 → 0.6.3
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 +8 -5
- package/dist/agent/src/agent/agentUtils.js +9 -12
- package/dist/agent/src/chat/client/chatClient.js +88 -240
- package/dist/agent/src/chat/client/constants.js +1 -2
- package/dist/agent/src/chat/client/sessionClient.js +4 -13
- package/dist/agent/src/chat/client/sessionFiles.js +3 -3
- package/dist/agent/src/chat/protocol/messages.js +0 -1
- package/dist/agent/src/chat/server/chatContextManager.js +5 -9
- package/dist/agent/src/chat/server/connectionManager.test.js +1 -0
- package/dist/agent/src/chat/server/conversation.js +9 -4
- package/dist/agent/src/chat/server/openSession.js +241 -238
- package/dist/agent/src/chat/server/openSessionMessageSender.js +2 -0
- package/dist/agent/src/chat/server/sessionRegistry.js +17 -12
- package/dist/agent/src/chat/utils/approvalManager.js +82 -64
- package/dist/agent/src/chat/{client/responseHandler.js → utils/responseAwaiter.js} +41 -18
- package/dist/agent/src/test/agent.test.js +90 -53
- package/dist/agent/src/test/approvalManager.test.js +79 -35
- package/dist/agent/src/test/chatContextManager.test.js +12 -17
- package/dist/agent/src/test/responseAwaiter.test.js +74 -0
- package/dist/agent/src/tool/agentChat.js +1 -1
- package/dist/agent/src/tool/chatMain.js +2 -2
- package/package.json +1 -1
- package/scripts/setup_chat +2 -2
- package/scripts/test_chat +61 -60
- package/src/agent/agent.ts +9 -5
- package/src/agent/agentUtils.ts +14 -27
- package/src/chat/client/chatClient.ts +167 -296
- package/src/chat/client/constants.ts +0 -2
- package/src/chat/client/sessionClient.ts +15 -19
- package/src/chat/client/sessionFiles.ts +9 -12
- package/src/chat/data/dataModels.ts +1 -0
- package/src/chat/protocol/messages.ts +9 -12
- package/src/chat/server/chatContextManager.ts +7 -12
- package/src/chat/server/connectionManager.test.ts +1 -0
- package/src/chat/server/conversation.ts +19 -11
- package/src/chat/server/openSession.ts +383 -340
- package/src/chat/server/openSessionMessageSender.ts +4 -0
- package/src/chat/server/sessionRegistry.ts +33 -12
- package/src/chat/utils/approvalManager.ts +153 -81
- package/src/chat/{client/responseHandler.ts → utils/responseAwaiter.ts} +73 -23
- package/src/test/agent.test.ts +130 -62
- package/src/test/approvalManager.test.ts +108 -40
- package/src/test/chatContextManager.test.ts +19 -20
- package/src/test/responseAwaiter.test.ts +103 -0
- package/src/tool/agentChat.ts +2 -2
- package/src/tool/chatMain.ts +2 -2
- package/dist/agent/src/test/responseHandler.test.js +0 -61
- package/src/test/responseHandler.test.ts +0 -78
|
@@ -18,18 +18,16 @@ import {
|
|
|
18
18
|
ClientSessionMessage,
|
|
19
19
|
ClientSessionMessageData,
|
|
20
20
|
ServerSessionScopedMessage,
|
|
21
|
-
ServerSessionInfo,
|
|
22
21
|
ClientSetWorkspace,
|
|
23
22
|
ClientToServer,
|
|
24
23
|
isServerSessionFileMessage,
|
|
25
24
|
} from "../protocol/messages";
|
|
26
25
|
import { SessionParticipantMap } from "../data/dataModels";
|
|
27
|
-
import { createSessionParticipantMap } from "../data/database";
|
|
28
26
|
import { ISessionMessageSender } from "./interfaces";
|
|
29
27
|
import { IMessageSender } from "./connection";
|
|
30
28
|
import { SessionFiles } from "./sessionFiles";
|
|
31
29
|
import { SessionFileDescriptor } from "../data/dbSessionFileModels";
|
|
32
|
-
import {
|
|
30
|
+
import { ResponseAwaiter } from "../utils/responseAwaiter";
|
|
33
31
|
|
|
34
32
|
const logger = getLogger();
|
|
35
33
|
|
|
@@ -205,16 +203,18 @@ class RemoteSudoMcpServerManager implements ISkillManager {
|
|
|
205
203
|
async shutdown(): Promise<void> {}
|
|
206
204
|
}
|
|
207
205
|
|
|
206
|
+
type ServerResponseMessages = Extract<
|
|
207
|
+
ServerSessionScopedMessage,
|
|
208
|
+
{ client_message_id?: string }
|
|
209
|
+
>;
|
|
210
|
+
|
|
208
211
|
export class SessionClient implements ISessionMessageSender, IConversation {
|
|
209
212
|
private readonly sessionUUID: string;
|
|
210
213
|
private readonly savedAgentProfile: SavedAgentProfile;
|
|
211
214
|
private readonly sender: IMessageSender<ClientToServer>;
|
|
212
215
|
private readonly smsm: RemoteSudoMcpServerManager;
|
|
213
216
|
private readonly sessionFiles: SessionFiles;
|
|
214
|
-
private readonly responseHandler:
|
|
215
|
-
ClientSessionMessage,
|
|
216
|
-
ServerSessionScopedMessage
|
|
217
|
-
>;
|
|
217
|
+
private readonly responseHandler: ResponseAwaiter<ServerResponseMessages>;
|
|
218
218
|
private participants: SessionParticipantMap;
|
|
219
219
|
private systemPrompt: string;
|
|
220
220
|
private model: string;
|
|
@@ -234,7 +234,10 @@ export class SessionClient implements ISessionMessageSender, IConversation {
|
|
|
234
234
|
this.sender = sender;
|
|
235
235
|
this.smsm = new RemoteSudoMcpServerManager(this, serverBriefs);
|
|
236
236
|
this.sessionFiles = new SessionFiles(sessionUUID, fileList, sender);
|
|
237
|
-
this.responseHandler =
|
|
237
|
+
this.responseHandler = ResponseAwaiter.init(
|
|
238
|
+
"session_error",
|
|
239
|
+
(msg: ServerResponseMessages) => msg.client_message_id
|
|
240
|
+
);
|
|
238
241
|
this.participants = participants;
|
|
239
242
|
this.systemPrompt = "";
|
|
240
243
|
this.model = "";
|
|
@@ -381,12 +384,6 @@ export class SessionClient implements ISessionMessageSender, IConversation {
|
|
|
381
384
|
this.sender.send(enrichedMessage);
|
|
382
385
|
}
|
|
383
386
|
|
|
384
|
-
public updateSessionInfo(sessionInfo: ServerSessionInfo): void {
|
|
385
|
-
// TODO: Determine the correct approach. Cache the workspace?
|
|
386
|
-
const infoStr = JSON.stringify(sessionInfo.workspace);
|
|
387
|
-
logger.debug(`[SessionClient] ignoring session info: ${infoStr}`);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
387
|
public setWorkspace(
|
|
391
388
|
message: string | undefined,
|
|
392
389
|
imageB64: string | undefined
|
|
@@ -428,7 +425,9 @@ export class SessionClient implements ISessionMessageSender, IConversation {
|
|
|
428
425
|
};
|
|
429
426
|
|
|
430
427
|
this.sender.send(msg);
|
|
431
|
-
const response = await this.responseHandler.waitForResponse(
|
|
428
|
+
const response = await this.responseHandler.waitForResponse(
|
|
429
|
+
msg.client_message_id
|
|
430
|
+
);
|
|
432
431
|
if (response.type === "session_shared") {
|
|
433
432
|
return response.access_token;
|
|
434
433
|
}
|
|
@@ -470,10 +469,7 @@ export class SessionClient implements ISessionMessageSender, IConversation {
|
|
|
470
469
|
this.model = message.model;
|
|
471
470
|
break;
|
|
472
471
|
case "session_info":
|
|
473
|
-
//
|
|
474
|
-
if ("participants" in message) {
|
|
475
|
-
this.participants = createSessionParticipantMap(message.participants);
|
|
476
|
-
}
|
|
472
|
+
// This is handled in the layer above, in the chatClient
|
|
477
473
|
break;
|
|
478
474
|
case "user_added":
|
|
479
475
|
this.participants.set(message.user_uuid, {
|
|
@@ -8,16 +8,11 @@ import {
|
|
|
8
8
|
ServerSessionFileContent,
|
|
9
9
|
ServerSessionFileMessage,
|
|
10
10
|
} from "../protocol/messages";
|
|
11
|
-
import { ResponseHandler } from "./responseHandler";
|
|
12
11
|
import { IMessageSender } from "./connection";
|
|
12
|
+
import { ResponseAwaiter } from "../utils/responseAwaiter";
|
|
13
13
|
|
|
14
14
|
const logger = getLogger();
|
|
15
15
|
|
|
16
|
-
type ClientRequestContent = Extract<
|
|
17
|
-
ClientToServer,
|
|
18
|
-
{ type: "session_file_get_content" }
|
|
19
|
-
>;
|
|
20
|
-
|
|
21
16
|
/// Object for the UI to use to interact with the FileManager. If the UI
|
|
22
17
|
/// receives ServerSessionFileChanged or ServerSessionFileDeleted then it
|
|
23
18
|
/// should call `listFiles()` to get the new list of files, and optionally
|
|
@@ -25,10 +20,7 @@ type ClientRequestContent = Extract<
|
|
|
25
20
|
export class SessionFiles {
|
|
26
21
|
readonly sessionUUID: string;
|
|
27
22
|
readonly descriptors: Map<string, SessionFileDescriptor>;
|
|
28
|
-
readonly responseHandler:
|
|
29
|
-
ClientRequestContent,
|
|
30
|
-
ServerSessionFileContent
|
|
31
|
-
>;
|
|
23
|
+
readonly responseHandler: ResponseAwaiter<ServerSessionFileContent>;
|
|
32
24
|
readonly sender: IMessageSender<ClientToServer>;
|
|
33
25
|
|
|
34
26
|
constructor(
|
|
@@ -38,7 +30,10 @@ export class SessionFiles {
|
|
|
38
30
|
) {
|
|
39
31
|
this.sessionUUID = sessionUUID;
|
|
40
32
|
this.descriptors = new Map(initialFileList.map((d) => [d.name, d]));
|
|
41
|
-
this.responseHandler =
|
|
33
|
+
this.responseHandler = ResponseAwaiter.init(
|
|
34
|
+
undefined,
|
|
35
|
+
(msg) => msg.client_message_id
|
|
36
|
+
);
|
|
42
37
|
this.sender = sender;
|
|
43
38
|
}
|
|
44
39
|
|
|
@@ -57,7 +52,9 @@ export class SessionFiles {
|
|
|
57
52
|
client_message_id: uuidv4(),
|
|
58
53
|
};
|
|
59
54
|
this.sender.send(msg);
|
|
60
|
-
const response = await this.responseHandler.waitForResponse(
|
|
55
|
+
const response = await this.responseHandler.waitForResponse(
|
|
56
|
+
msg.client_message_id
|
|
57
|
+
);
|
|
61
58
|
if (response.name !== name) {
|
|
62
59
|
throw new Error(
|
|
63
60
|
`invalid name for file ${name}: ${JSON.stringify(response)}`
|
|
@@ -129,6 +129,7 @@ export type ClientControlMessage =
|
|
|
129
129
|
|
|
130
130
|
export type ClientUserMessage = {
|
|
131
131
|
type: "msg";
|
|
132
|
+
race_mode?: boolean;
|
|
132
133
|
} & UserMessageData;
|
|
133
134
|
|
|
134
135
|
export type ClientSetWorkspace = {
|
|
@@ -224,6 +225,12 @@ export type ClientShareSession = {
|
|
|
224
225
|
type: "share_session";
|
|
225
226
|
};
|
|
226
227
|
|
|
228
|
+
export type ClientRaceModeResult = {
|
|
229
|
+
type: "race_mode_result";
|
|
230
|
+
message_id: string;
|
|
231
|
+
result: string;
|
|
232
|
+
} & UserMessageData;
|
|
233
|
+
|
|
227
234
|
export type ClientSessionMessageData =
|
|
228
235
|
| ClientUserMessage
|
|
229
236
|
| ClientSetWorkspace
|
|
@@ -341,6 +348,7 @@ export type ServerHistory = {
|
|
|
341
348
|
export type ServerUserMessage = {
|
|
342
349
|
type: "user_msg";
|
|
343
350
|
user_uuid: string;
|
|
351
|
+
user_nickname: string;
|
|
344
352
|
message_idx: number;
|
|
345
353
|
} & UserMessageData &
|
|
346
354
|
ServerSessionMessage;
|
|
@@ -355,6 +363,7 @@ export type ServerAgentMessageChunk = {
|
|
|
355
363
|
type: "agent_msg_chunk";
|
|
356
364
|
message: string;
|
|
357
365
|
message_idx: number;
|
|
366
|
+
alternative?: string;
|
|
358
367
|
end: boolean;
|
|
359
368
|
} & ServerSessionMessage;
|
|
360
369
|
|
|
@@ -378,10 +387,6 @@ export type ServerUserLeft = {
|
|
|
378
387
|
user_uuid: string;
|
|
379
388
|
} & ServerSessionMessage;
|
|
380
389
|
|
|
381
|
-
export type ServerSessionUpdate = {
|
|
382
|
-
type: "session_update";
|
|
383
|
-
title?: string;
|
|
384
|
-
} & ServerSessionMessage;
|
|
385
390
|
|
|
386
391
|
// Note: ChatCompletionMessageToolCall contains the tool call id so we don't
|
|
387
392
|
// need an extra id field.
|
|
@@ -432,7 +437,6 @@ export type ServerUserTyping = {
|
|
|
432
437
|
export type ServerToClientNotifications =
|
|
433
438
|
| ServerUserJoined
|
|
434
439
|
| ServerUserLeft
|
|
435
|
-
| ServerSessionUpdate
|
|
436
440
|
| ServerToolAutoApprovalSet
|
|
437
441
|
| ServerToolCall
|
|
438
442
|
| ServerToolCallApprovalResult
|
|
@@ -471,12 +475,6 @@ export type ServerSessionFileMessage =
|
|
|
471
475
|
//
|
|
472
476
|
// state updates
|
|
473
477
|
//
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* A new team has been created.
|
|
477
|
-
* The members array contains the members of the team.
|
|
478
|
-
* The members array contains undefined for failed lookups.
|
|
479
|
-
*/
|
|
480
478
|
export type ServerMcpServerAdded = {
|
|
481
479
|
type: "mcp_server_added";
|
|
482
480
|
server_name: string;
|
|
@@ -731,7 +729,6 @@ export function isServerSessionScopedMessage(
|
|
|
731
729
|
case "agent_reasoning_chunk":
|
|
732
730
|
case "user_joined":
|
|
733
731
|
case "user_left":
|
|
734
|
-
case "session_update":
|
|
735
732
|
case "tool_auto_approval_set":
|
|
736
733
|
case "tool_call":
|
|
737
734
|
case "tool_call_approval_result":
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
ClientUserMessage,
|
|
20
20
|
ServerAgentMessage,
|
|
21
21
|
ServerAgentMessageChunk,
|
|
22
|
-
ServerSessionError,
|
|
23
22
|
ServerToolCallResult,
|
|
24
23
|
ServerUserMessage,
|
|
25
24
|
} from "../protocol/messages";
|
|
@@ -213,7 +212,8 @@ export class ChatContextManager
|
|
|
213
212
|
|
|
214
213
|
processUserMessage(
|
|
215
214
|
msg: ClientUserMessage,
|
|
216
|
-
|
|
215
|
+
from_uuid: string,
|
|
216
|
+
from_nickname: string
|
|
217
217
|
): ServerUserMessage | undefined {
|
|
218
218
|
// TODO: maintain a queue internally instead of relying on the caller to
|
|
219
219
|
// pass in our generated messages back into `startAgentResponse`.
|
|
@@ -229,7 +229,8 @@ export class ChatContextManager
|
|
|
229
229
|
session_id: this.sessionUUID,
|
|
230
230
|
message_idx,
|
|
231
231
|
message: msg.message,
|
|
232
|
-
user_uuid:
|
|
232
|
+
user_uuid: from_uuid,
|
|
233
|
+
user_nickname: from_nickname,
|
|
233
234
|
};
|
|
234
235
|
if (msg.imageB64) {
|
|
235
236
|
userMessage.imageB64 = msg.imageB64;
|
|
@@ -288,7 +289,7 @@ export class ChatContextManager
|
|
|
288
289
|
const userMsg = createUserMessage(
|
|
289
290
|
msg.message,
|
|
290
291
|
msg.imageB64,
|
|
291
|
-
msg.
|
|
292
|
+
msg.user_nickname
|
|
292
293
|
);
|
|
293
294
|
if (userMsg) {
|
|
294
295
|
llmUserMessages.push(userMsg);
|
|
@@ -366,7 +367,7 @@ export class ChatContextManager
|
|
|
366
367
|
if (JSON.stringify(sMsg.content) !== JSON.stringify(lMsg)) {
|
|
367
368
|
messageListError(
|
|
368
369
|
`newSessionMessages[${String(i)}].content !== ` +
|
|
369
|
-
`newLLMMessages[${String(i)}]
|
|
370
|
+
`newLLMMessages[${String(i)}]`
|
|
370
371
|
);
|
|
371
372
|
}
|
|
372
373
|
if (sMsg.message_idx !== pMsg.message_idx) {
|
|
@@ -399,7 +400,7 @@ export class ChatContextManager
|
|
|
399
400
|
* This function checks that nothing has been entered into the LLM context,
|
|
400
401
|
* and drops any new user messages or responses before the error.
|
|
401
402
|
*/
|
|
402
|
-
revertAgentResponse(errMsg: string):
|
|
403
|
+
revertAgentResponse(errMsg: string): void {
|
|
403
404
|
logger.warn(`[ChatContextManager.revertAgentResponse] error: ${errMsg}`);
|
|
404
405
|
|
|
405
406
|
assert(typeof this.startingLLMContextLength !== "undefined");
|
|
@@ -425,12 +426,6 @@ export class ChatContextManager
|
|
|
425
426
|
this.startingLLMContextLength = undefined;
|
|
426
427
|
this.pendingMessages = undefined;
|
|
427
428
|
this.curAgentMsgIdx = undefined;
|
|
428
|
-
|
|
429
|
-
return {
|
|
430
|
-
type: "session_error",
|
|
431
|
-
session_id: this.sessionUUID,
|
|
432
|
-
message: errMsg,
|
|
433
|
-
};
|
|
434
429
|
}
|
|
435
430
|
|
|
436
431
|
processAgentMessage(msg: string, end: boolean): ServerAgentMessageChunk {
|
|
@@ -104,19 +104,24 @@ export function sessionMessagesToLLMConversation(
|
|
|
104
104
|
*/
|
|
105
105
|
export function userMessageToConversationMessage(
|
|
106
106
|
userMessage: ChatCompletionUserMessageParam,
|
|
107
|
+
user_uuid: string,
|
|
107
108
|
message_idx: number,
|
|
108
|
-
defaultUserUuid: string,
|
|
109
109
|
session_id: string
|
|
110
110
|
): ServerUserMessage {
|
|
111
111
|
// The name on the message should be the uuid
|
|
112
112
|
|
|
113
113
|
const userMsgData = llmUserMessageToUserMessageData(userMessage);
|
|
114
|
-
const
|
|
114
|
+
const user_nickname = userMessage.name;
|
|
115
|
+
assert(
|
|
116
|
+
user_nickname,
|
|
117
|
+
`ChatCompletionUserMessageParam without user ${JSON.stringify(userMessage)}`
|
|
118
|
+
);
|
|
115
119
|
const msg: ServerUserMessage = {
|
|
116
120
|
type: "user_msg",
|
|
117
121
|
message: userMsgData.message,
|
|
118
122
|
message_idx,
|
|
119
123
|
user_uuid,
|
|
124
|
+
user_nickname,
|
|
120
125
|
session_id,
|
|
121
126
|
};
|
|
122
127
|
if (userMsgData.imageB64) {
|
|
@@ -183,14 +188,17 @@ export function sessionMessagesToConversationMessages(
|
|
|
183
188
|
);
|
|
184
189
|
break;
|
|
185
190
|
case "user":
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
191
|
+
{
|
|
192
|
+
const user_uuid = sm.sender_uuid || defaultUserUuid;
|
|
193
|
+
msgs.push(
|
|
194
|
+
userMessageToConversationMessage(
|
|
195
|
+
ccmp,
|
|
196
|
+
user_uuid,
|
|
197
|
+
message_idx,
|
|
198
|
+
session_id
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
194
202
|
break;
|
|
195
203
|
case "tool":
|
|
196
204
|
msgs.push(
|
|
@@ -267,7 +275,7 @@ export function chatUserMessageToSessionMessage(
|
|
|
267
275
|
const userMsg = createUserMessage(
|
|
268
276
|
chatMessage.message,
|
|
269
277
|
chatMessage.imageB64,
|
|
270
|
-
chatMessage.
|
|
278
|
+
chatMessage.user_nickname
|
|
271
279
|
);
|
|
272
280
|
assert(userMsg);
|
|
273
281
|
return {
|