@nextclaw/ncp-toolkit 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -5
- package/dist/index.js +230 -121
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NcpAgentConversationStateManager, NcpAgentConversationSnapshot, NcpAgentConversationHydrationParams, NcpEndpointEvent, NcpMessageSentPayload, NcpMessageAbortPayload, NcpTextStartPayload, NcpTextDeltaPayload, NcpTextEndPayload, NcpReasoningStartPayload, NcpReasoningDeltaPayload, NcpReasoningEndPayload, NcpToolCallStartPayload, NcpToolCallArgsPayload, NcpToolCallArgsDeltaPayload, NcpToolCallEndPayload, NcpToolCallResultPayload, NcpRunStartedPayload, NcpRunFinishedPayload, NcpRunErrorPayload, NcpRunMetadataPayload, NcpError, NcpAgentServerEndpoint, NcpAgentClientEndpoint, NcpEndpointSubscriber, NcpAgentRuntime, NcpRequestEnvelope, NcpMessage, NcpSessionApi, NcpAgentStreamProvider, NcpAgentRunApi, NcpEndpointManifest, NcpAgentRunSendOptions, NcpStreamRequestPayload, NcpAgentRunStreamOptions, NcpSessionSummary, NcpErrorCode } from '@nextclaw/ncp';
|
|
1
|
+
import { NcpAgentConversationStateManager, NcpAgentConversationSnapshot, NcpAgentConversationHydrationParams, NcpEndpointEvent, NcpMessageSentPayload, NcpMessageAbortPayload, NcpTextStartPayload, NcpTextDeltaPayload, NcpTextEndPayload, NcpReasoningStartPayload, NcpReasoningDeltaPayload, NcpReasoningEndPayload, NcpToolCallStartPayload, NcpToolCallArgsPayload, NcpToolCallArgsDeltaPayload, NcpToolCallEndPayload, NcpToolCallResultPayload, NcpRunStartedPayload, NcpRunFinishedPayload, NcpRunErrorPayload, NcpRunMetadataPayload, NcpError, NcpAgentServerEndpoint, NcpAgentClientEndpoint, NcpEndpointSubscriber, NcpAgentRuntime, NcpRequestEnvelope, NcpMessage, NcpSessionApi, NcpAgentStreamProvider, NcpAgentRunApi, NcpEndpointManifest, NcpAgentRunSendOptions, NcpStreamRequestPayload, NcpAgentRunStreamOptions, NcpSessionSummary, NcpSessionPatch, NcpErrorCode } from '@nextclaw/ncp';
|
|
2
2
|
|
|
3
3
|
declare class DefaultNcpAgentConversationStateManager implements NcpAgentConversationStateManager {
|
|
4
4
|
private messages;
|
|
@@ -38,14 +38,10 @@ declare class DefaultNcpAgentConversationStateManager implements NcpAgentConvers
|
|
|
38
38
|
private ensureStreamingMessage;
|
|
39
39
|
private resolveToolCallTargetMessage;
|
|
40
40
|
private updateMessageContainingToolCall;
|
|
41
|
-
private findToolInvocationPart;
|
|
42
|
-
private findToolNameByCallId;
|
|
43
|
-
private upsertToolInvocationPart;
|
|
44
41
|
private upsertMessage;
|
|
45
42
|
private replaceStreamingMessage;
|
|
46
43
|
private setError;
|
|
47
44
|
private clearActiveRun;
|
|
48
|
-
private clearToolCallTrackingByMessageId;
|
|
49
45
|
private notifyListeners;
|
|
50
46
|
}
|
|
51
47
|
|
|
@@ -68,6 +64,8 @@ declare class EventPublisher {
|
|
|
68
64
|
type RuntimeFactoryParams = {
|
|
69
65
|
sessionId: string;
|
|
70
66
|
stateManager: NcpAgentConversationStateManager;
|
|
67
|
+
sessionMetadata: Record<string, unknown>;
|
|
68
|
+
setSessionMetadata: (nextMetadata: Record<string, unknown>) => void;
|
|
71
69
|
};
|
|
72
70
|
type CreateRuntimeFn = (params: RuntimeFactoryParams) => NcpAgentRuntime;
|
|
73
71
|
type AgentSessionRecord = {
|
|
@@ -87,6 +85,7 @@ type LiveSessionState = {
|
|
|
87
85
|
sessionId: string;
|
|
88
86
|
runtime: NcpAgentRuntime;
|
|
89
87
|
stateManager: NcpAgentConversationStateManager;
|
|
88
|
+
metadata: Record<string, unknown>;
|
|
90
89
|
activeExecution: LiveSessionExecution | null;
|
|
91
90
|
};
|
|
92
91
|
interface AgentSessionStore {
|
|
@@ -128,6 +127,7 @@ declare class DefaultNcpAgentBackend implements NcpAgentServerEndpoint, NcpSessi
|
|
|
128
127
|
listSessions(): Promise<NcpSessionSummary[]>;
|
|
129
128
|
listSessionMessages(sessionId: string): Promise<NcpMessage[]>;
|
|
130
129
|
getSession(sessionId: string): Promise<NcpSessionSummary | null>;
|
|
130
|
+
updateSession(sessionId: string, patch: NcpSessionPatch): Promise<NcpSessionSummary | null>;
|
|
131
131
|
deleteSession(sessionId: string): Promise<void>;
|
|
132
132
|
private ensureStarted;
|
|
133
133
|
private startSessionExecution;
|
package/dist/index.js
CHANGED
|
@@ -16,9 +16,8 @@ function normalizeConversationMessage(message) {
|
|
|
16
16
|
return cloneConversationMessage(sanitizeAssistantReplyTags(message));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// src/agent/agent-conversation-state-manager.ts
|
|
20
|
-
|
|
21
|
-
var buildRuntimeError = (payload) => {
|
|
19
|
+
// src/agent/agent-conversation-state-manager.utils.ts
|
|
20
|
+
function buildRuntimeError(payload) {
|
|
22
21
|
const message = payload.error?.trim();
|
|
23
22
|
return {
|
|
24
23
|
code: "runtime-error",
|
|
@@ -30,7 +29,64 @@ var buildRuntimeError = (payload) => {
|
|
|
30
29
|
runId: payload.runId
|
|
31
30
|
}
|
|
32
31
|
};
|
|
33
|
-
}
|
|
32
|
+
}
|
|
33
|
+
function shouldPromoteStreamingMessageId(message, nextMessageId) {
|
|
34
|
+
if (!nextMessageId.trim()) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (message.id.startsWith("tool-")) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return message.parts.some((part) => part.type === "tool-invocation");
|
|
41
|
+
}
|
|
42
|
+
function remapTrackedToolCallsToMessageId(toolCallMessageIdByCallId, fromMessageId, toMessageId) {
|
|
43
|
+
for (const [toolCallId, trackedMessageId] of toolCallMessageIdByCallId) {
|
|
44
|
+
if (trackedMessageId !== fromMessageId) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
toolCallMessageIdByCallId.set(toolCallId, toMessageId);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function clearToolCallTrackingByMessageId(toolCallMessageIdByCallId, toolCallArgsRawByCallId, messageId) {
|
|
51
|
+
for (const [toolCallId, trackedMessageId] of toolCallMessageIdByCallId) {
|
|
52
|
+
if (trackedMessageId !== messageId) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
toolCallMessageIdByCallId.delete(toolCallId);
|
|
56
|
+
toolCallArgsRawByCallId.delete(toolCallId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function findToolInvocationPart(parts, toolCallId) {
|
|
60
|
+
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
61
|
+
const part = parts[index];
|
|
62
|
+
if (part.type === "tool-invocation" && part.toolCallId === toolCallId) {
|
|
63
|
+
return part;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function findToolNameByCallId(parts, toolCallId) {
|
|
69
|
+
const part = findToolInvocationPart(parts, toolCallId);
|
|
70
|
+
return part?.toolName ?? null;
|
|
71
|
+
}
|
|
72
|
+
function upsertToolInvocationPart(parts, toolPart) {
|
|
73
|
+
const nextParts = [...parts];
|
|
74
|
+
for (let index = nextParts.length - 1; index >= 0; index -= 1) {
|
|
75
|
+
const part = nextParts[index];
|
|
76
|
+
if (part.type === "tool-invocation" && part.toolCallId === toolPart.toolCallId) {
|
|
77
|
+
nextParts[index] = {
|
|
78
|
+
...part,
|
|
79
|
+
...toolPart
|
|
80
|
+
};
|
|
81
|
+
return nextParts;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
nextParts.push(toolPart);
|
|
85
|
+
return nextParts;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/agent/agent-conversation-state-manager.ts
|
|
89
|
+
var DEFAULT_ASSISTANT_ROLE = "assistant";
|
|
34
90
|
var DefaultNcpAgentConversationStateManager = class {
|
|
35
91
|
messages = [];
|
|
36
92
|
streamingMessage = null;
|
|
@@ -167,9 +223,17 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
167
223
|
});
|
|
168
224
|
this.replaceStreamingMessage(null);
|
|
169
225
|
if (targetMessageId) {
|
|
170
|
-
|
|
226
|
+
clearToolCallTrackingByMessageId(
|
|
227
|
+
this.toolCallMessageIdByCallId,
|
|
228
|
+
this.toolCallArgsRawByCallId,
|
|
229
|
+
targetMessageId
|
|
230
|
+
);
|
|
171
231
|
} else {
|
|
172
|
-
|
|
232
|
+
clearToolCallTrackingByMessageId(
|
|
233
|
+
this.toolCallMessageIdByCallId,
|
|
234
|
+
this.toolCallArgsRawByCallId,
|
|
235
|
+
streamingMessageId
|
|
236
|
+
);
|
|
173
237
|
}
|
|
174
238
|
}
|
|
175
239
|
}
|
|
@@ -246,7 +310,7 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
246
310
|
payload.messageId
|
|
247
311
|
);
|
|
248
312
|
this.toolCallArgsRawByCallId.set(payload.toolCallId, "");
|
|
249
|
-
const nextParts =
|
|
313
|
+
const nextParts = upsertToolInvocationPart(targetMessage.parts, {
|
|
250
314
|
type: "tool-invocation",
|
|
251
315
|
toolCallId: payload.toolCallId,
|
|
252
316
|
toolName: payload.toolName,
|
|
@@ -273,10 +337,10 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
273
337
|
handleMessageToolCallEnd(payload) {
|
|
274
338
|
const targetMessage = this.resolveToolCallTargetMessage(payload.sessionId, payload.toolCallId);
|
|
275
339
|
const args = this.toolCallArgsRawByCallId.get(payload.toolCallId) ?? "";
|
|
276
|
-
const nextParts =
|
|
340
|
+
const nextParts = upsertToolInvocationPart(targetMessage.parts, {
|
|
277
341
|
type: "tool-invocation",
|
|
278
342
|
toolCallId: payload.toolCallId,
|
|
279
|
-
toolName:
|
|
343
|
+
toolName: findToolNameByCallId(targetMessage.parts, payload.toolCallId) ?? "unknown",
|
|
280
344
|
state: "call",
|
|
281
345
|
args
|
|
282
346
|
});
|
|
@@ -296,11 +360,11 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
296
360
|
args: existingPart.args,
|
|
297
361
|
result: payload.content
|
|
298
362
|
};
|
|
299
|
-
return
|
|
363
|
+
return upsertToolInvocationPart(targetMessage.parts, mergedPart);
|
|
300
364
|
});
|
|
301
365
|
if (!updated) {
|
|
302
366
|
const fallbackMessage = this.resolveToolCallTargetMessage(payload.sessionId, payload.toolCallId);
|
|
303
|
-
const nextParts =
|
|
367
|
+
const nextParts = upsertToolInvocationPart(fallbackMessage.parts, {
|
|
304
368
|
type: "tool-invocation",
|
|
305
369
|
toolCallId: payload.toolCallId,
|
|
306
370
|
toolName: "unknown",
|
|
@@ -330,7 +394,11 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
330
394
|
};
|
|
331
395
|
this.upsertMessage(finalizedMessage);
|
|
332
396
|
this.replaceStreamingMessage(null);
|
|
333
|
-
|
|
397
|
+
clearToolCallTrackingByMessageId(
|
|
398
|
+
this.toolCallMessageIdByCallId,
|
|
399
|
+
this.toolCallArgsRawByCallId,
|
|
400
|
+
finalizedMessage.id
|
|
401
|
+
);
|
|
334
402
|
}
|
|
335
403
|
this.setError(null);
|
|
336
404
|
this.clearActiveRun();
|
|
@@ -343,7 +411,11 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
343
411
|
};
|
|
344
412
|
this.upsertMessage(failedMessage);
|
|
345
413
|
this.replaceStreamingMessage(null);
|
|
346
|
-
|
|
414
|
+
clearToolCallTrackingByMessageId(
|
|
415
|
+
this.toolCallMessageIdByCallId,
|
|
416
|
+
this.toolCallArgsRawByCallId,
|
|
417
|
+
failedMessage.id
|
|
418
|
+
);
|
|
347
419
|
}
|
|
348
420
|
this.setError(buildRuntimeError(payload));
|
|
349
421
|
this.clearActiveRun();
|
|
@@ -367,8 +439,8 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
367
439
|
}
|
|
368
440
|
applyToolCallArgs(sessionId, toolCallId, args, messageId) {
|
|
369
441
|
const targetMessage = this.resolveToolCallTargetMessage(sessionId, toolCallId, messageId);
|
|
370
|
-
const toolName =
|
|
371
|
-
const nextParts =
|
|
442
|
+
const toolName = findToolNameByCallId(targetMessage.parts, toolCallId) ?? "unknown";
|
|
443
|
+
const nextParts = upsertToolInvocationPart(targetMessage.parts, {
|
|
372
444
|
type: "tool-invocation",
|
|
373
445
|
toolCallId,
|
|
374
446
|
toolName,
|
|
@@ -408,6 +480,22 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
408
480
|
this.replaceStreamingMessage(nextStreamingMessage2);
|
|
409
481
|
return nextStreamingMessage2;
|
|
410
482
|
}
|
|
483
|
+
const existingStreamingMessage = this.streamingMessage;
|
|
484
|
+
if (existingStreamingMessage && existingStreamingMessage.id !== messageId && existingStreamingMessage.sessionId === sessionId && shouldPromoteStreamingMessageId(existingStreamingMessage, messageId)) {
|
|
485
|
+
const nextStreamingMessage2 = {
|
|
486
|
+
...existingStreamingMessage,
|
|
487
|
+
id: messageId,
|
|
488
|
+
sessionId,
|
|
489
|
+
status
|
|
490
|
+
};
|
|
491
|
+
remapTrackedToolCallsToMessageId(
|
|
492
|
+
this.toolCallMessageIdByCallId,
|
|
493
|
+
existingStreamingMessage.id,
|
|
494
|
+
messageId
|
|
495
|
+
);
|
|
496
|
+
this.replaceStreamingMessage(nextStreamingMessage2);
|
|
497
|
+
return nextStreamingMessage2;
|
|
498
|
+
}
|
|
411
499
|
const nextStreamingMessage = {
|
|
412
500
|
id: messageId,
|
|
413
501
|
sessionId,
|
|
@@ -426,7 +514,7 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
426
514
|
}
|
|
427
515
|
updateMessageContainingToolCall(toolCallId, updater) {
|
|
428
516
|
if (this.streamingMessage) {
|
|
429
|
-
const part =
|
|
517
|
+
const part = findToolInvocationPart(this.streamingMessage.parts, toolCallId);
|
|
430
518
|
if (part) {
|
|
431
519
|
const nextParts = updater(this.streamingMessage, part);
|
|
432
520
|
this.replaceStreamingMessage({ ...this.streamingMessage, parts: nextParts });
|
|
@@ -435,7 +523,7 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
435
523
|
}
|
|
436
524
|
for (let index = this.messages.length - 1; index >= 0; index -= 1) {
|
|
437
525
|
const candidateMessage = this.messages[index];
|
|
438
|
-
const part =
|
|
526
|
+
const part = findToolInvocationPart(candidateMessage.parts, toolCallId);
|
|
439
527
|
if (!part) {
|
|
440
528
|
continue;
|
|
441
529
|
}
|
|
@@ -450,34 +538,6 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
450
538
|
}
|
|
451
539
|
return false;
|
|
452
540
|
}
|
|
453
|
-
findToolInvocationPart(parts, toolCallId) {
|
|
454
|
-
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
455
|
-
const part = parts[index];
|
|
456
|
-
if (part.type === "tool-invocation" && part.toolCallId === toolCallId) {
|
|
457
|
-
return part;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
findToolNameByCallId(parts, toolCallId) {
|
|
463
|
-
const part = this.findToolInvocationPart(parts, toolCallId);
|
|
464
|
-
return part?.toolName ?? null;
|
|
465
|
-
}
|
|
466
|
-
upsertToolInvocationPart(parts, toolPart) {
|
|
467
|
-
const nextParts = [...parts];
|
|
468
|
-
for (let index = nextParts.length - 1; index >= 0; index -= 1) {
|
|
469
|
-
const part = nextParts[index];
|
|
470
|
-
if (part.type === "tool-invocation" && part.toolCallId === toolPart.toolCallId) {
|
|
471
|
-
nextParts[index] = {
|
|
472
|
-
...part,
|
|
473
|
-
...toolPart
|
|
474
|
-
};
|
|
475
|
-
return nextParts;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
nextParts.push(toolPart);
|
|
479
|
-
return nextParts;
|
|
480
|
-
}
|
|
481
541
|
upsertMessage(message) {
|
|
482
542
|
const normalizedMessage = normalizeConversationMessage(message);
|
|
483
543
|
const messageIndex = this.messages.findIndex((item) => item.id === normalizedMessage.id);
|
|
@@ -513,15 +573,6 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
513
573
|
this.activeRun = null;
|
|
514
574
|
this.stateVersion += 1;
|
|
515
575
|
}
|
|
516
|
-
clearToolCallTrackingByMessageId(messageId) {
|
|
517
|
-
for (const [toolCallId, trackedMessageId] of this.toolCallMessageIdByCallId) {
|
|
518
|
-
if (trackedMessageId !== messageId) {
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
this.toolCallMessageIdByCallId.delete(toolCallId);
|
|
522
|
-
this.toolCallArgsRawByCallId.delete(toolCallId);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
576
|
notifyListeners() {
|
|
526
577
|
const snapshot = this.getSnapshot();
|
|
527
578
|
for (const listener of this.listeners) {
|
|
@@ -582,7 +633,7 @@ async function consume(events) {
|
|
|
582
633
|
|
|
583
634
|
// src/agent/agent-backend/agent-backend.ts
|
|
584
635
|
import {
|
|
585
|
-
NcpEventType as
|
|
636
|
+
NcpEventType as NcpEventType5
|
|
586
637
|
} from "@nextclaw/ncp";
|
|
587
638
|
|
|
588
639
|
// src/errors/ncp-error-exception.ts
|
|
@@ -604,9 +655,15 @@ var AgentLiveSessionRegistry = class {
|
|
|
604
655
|
this.createRuntime = createRuntime;
|
|
605
656
|
}
|
|
606
657
|
sessions = /* @__PURE__ */ new Map();
|
|
607
|
-
async ensureSession(sessionId) {
|
|
658
|
+
async ensureSession(sessionId, initialMetadata) {
|
|
608
659
|
const existing = this.sessions.get(sessionId);
|
|
609
660
|
if (existing) {
|
|
661
|
+
if (initialMetadata && Object.keys(initialMetadata).length > 0) {
|
|
662
|
+
existing.metadata = {
|
|
663
|
+
...existing.metadata,
|
|
664
|
+
...structuredClone(initialMetadata)
|
|
665
|
+
};
|
|
666
|
+
}
|
|
610
667
|
return existing;
|
|
611
668
|
}
|
|
612
669
|
const storedSession = await this.sessionStore.getSession(sessionId);
|
|
@@ -615,12 +672,27 @@ var AgentLiveSessionRegistry = class {
|
|
|
615
672
|
sessionId,
|
|
616
673
|
messages: cloneMessages(storedSession?.messages ?? [])
|
|
617
674
|
});
|
|
675
|
+
const sessionMetadata = {
|
|
676
|
+
...storedSession?.metadata ? structuredClone(storedSession.metadata) : {},
|
|
677
|
+
...initialMetadata ? structuredClone(initialMetadata) : {}
|
|
678
|
+
};
|
|
618
679
|
const session = {
|
|
619
680
|
sessionId,
|
|
620
681
|
stateManager,
|
|
621
|
-
|
|
682
|
+
metadata: sessionMetadata,
|
|
683
|
+
runtime: null,
|
|
622
684
|
activeExecution: null
|
|
623
685
|
};
|
|
686
|
+
session.runtime = this.createRuntime({
|
|
687
|
+
sessionId,
|
|
688
|
+
stateManager,
|
|
689
|
+
sessionMetadata,
|
|
690
|
+
setSessionMetadata: (nextMetadata) => {
|
|
691
|
+
session.metadata = {
|
|
692
|
+
...structuredClone(nextMetadata)
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
});
|
|
624
696
|
this.sessions.set(sessionId, session);
|
|
625
697
|
return session;
|
|
626
698
|
}
|
|
@@ -759,6 +831,78 @@ function createAsyncQueue() {
|
|
|
759
831
|
};
|
|
760
832
|
}
|
|
761
833
|
|
|
834
|
+
// src/agent/agent-backend/agent-backend-session-utils.ts
|
|
835
|
+
import { NcpEventType as NcpEventType4 } from "@nextclaw/ncp";
|
|
836
|
+
function readMessages(snapshot) {
|
|
837
|
+
const messages = snapshot.messages.map((message) => structuredClone(message));
|
|
838
|
+
if (snapshot.streamingMessage) {
|
|
839
|
+
messages.push(structuredClone(snapshot.streamingMessage));
|
|
840
|
+
}
|
|
841
|
+
return messages;
|
|
842
|
+
}
|
|
843
|
+
function toSessionSummary(session, liveSession) {
|
|
844
|
+
return {
|
|
845
|
+
sessionId: session.sessionId,
|
|
846
|
+
messageCount: session.messages.length,
|
|
847
|
+
updatedAt: session.updatedAt,
|
|
848
|
+
status: liveSession?.activeExecution ? "running" : "idle",
|
|
849
|
+
...session.metadata ? {
|
|
850
|
+
metadata: structuredClone({
|
|
851
|
+
...session.metadata,
|
|
852
|
+
...liveSession?.metadata ? liveSession.metadata : {}
|
|
853
|
+
})
|
|
854
|
+
} : liveSession?.metadata ? { metadata: structuredClone(liveSession.metadata) } : {}
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
function toLiveSessionSummary(session) {
|
|
858
|
+
const snapshot = session.stateManager.getSnapshot();
|
|
859
|
+
return {
|
|
860
|
+
sessionId: session.sessionId,
|
|
861
|
+
messageCount: readMessages(snapshot).length,
|
|
862
|
+
updatedAt: now(),
|
|
863
|
+
status: session.activeExecution ? "running" : "idle",
|
|
864
|
+
...Object.keys(session.metadata).length > 0 ? { metadata: structuredClone(session.metadata) } : session.activeExecution?.requestEnvelope.metadata ? { metadata: structuredClone(session.activeExecution.requestEnvelope.metadata) } : {}
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
function now() {
|
|
868
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
869
|
+
}
|
|
870
|
+
function isTerminalEvent(event) {
|
|
871
|
+
switch (event.type) {
|
|
872
|
+
case NcpEventType4.MessageAbort:
|
|
873
|
+
case NcpEventType4.RunFinished:
|
|
874
|
+
case NcpEventType4.RunError:
|
|
875
|
+
return true;
|
|
876
|
+
default:
|
|
877
|
+
return false;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// src/agent/agent-backend/agent-backend-session-persistence.ts
|
|
882
|
+
function buildUpdatedSessionRecord(params) {
|
|
883
|
+
const nextMetadata = params.patch.metadata === null ? {} : params.patch.metadata ? structuredClone(params.patch.metadata) : structuredClone(params.liveSession?.metadata ?? params.storedSession?.metadata ?? {});
|
|
884
|
+
if (params.liveSession) {
|
|
885
|
+
params.liveSession.metadata = structuredClone(nextMetadata);
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
sessionId: params.sessionId,
|
|
889
|
+
messages: params.liveSession ? readMessages(params.liveSession.stateManager.getSnapshot()) : params.storedSession?.messages.map((message) => structuredClone(message)) ?? [],
|
|
890
|
+
updatedAt: params.updatedAt,
|
|
891
|
+
metadata: nextMetadata
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
function buildPersistedLiveSessionRecord(params) {
|
|
895
|
+
return {
|
|
896
|
+
sessionId: params.sessionId,
|
|
897
|
+
messages: readMessages(params.session.stateManager.getSnapshot()),
|
|
898
|
+
updatedAt: params.updatedAt,
|
|
899
|
+
metadata: {
|
|
900
|
+
...params.session.metadata ? structuredClone(params.session.metadata) : {},
|
|
901
|
+
...params.session.activeExecution?.requestEnvelope.metadata ? structuredClone(params.session.activeExecution.requestEnvelope.metadata) : {}
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
|
|
762
906
|
// src/agent/agent-backend/event-publisher.ts
|
|
763
907
|
var EventPublisher = class {
|
|
764
908
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -850,7 +994,7 @@ var DefaultNcpAgentBackend = class {
|
|
|
850
994
|
return;
|
|
851
995
|
}
|
|
852
996
|
this.started = true;
|
|
853
|
-
this.publisher.publish({ type:
|
|
997
|
+
this.publisher.publish({ type: NcpEventType5.EndpointReady });
|
|
854
998
|
}
|
|
855
999
|
async stop() {
|
|
856
1000
|
if (!this.started) {
|
|
@@ -871,13 +1015,13 @@ var DefaultNcpAgentBackend = class {
|
|
|
871
1015
|
async emit(event) {
|
|
872
1016
|
await this.ensureStarted();
|
|
873
1017
|
switch (event.type) {
|
|
874
|
-
case
|
|
1018
|
+
case NcpEventType5.MessageRequest:
|
|
875
1019
|
await this.handleRequest(event.payload);
|
|
876
1020
|
return;
|
|
877
|
-
case
|
|
1021
|
+
case NcpEventType5.MessageStreamRequest:
|
|
878
1022
|
await this.streamToSubscribers(event.payload);
|
|
879
1023
|
return;
|
|
880
|
-
case
|
|
1024
|
+
case NcpEventType5.MessageAbort:
|
|
881
1025
|
await this.handleAbort(event.payload);
|
|
882
1026
|
return;
|
|
883
1027
|
default:
|
|
@@ -889,7 +1033,10 @@ var DefaultNcpAgentBackend = class {
|
|
|
889
1033
|
}
|
|
890
1034
|
async *send(envelope, options) {
|
|
891
1035
|
await this.ensureStarted();
|
|
892
|
-
const session = await this.sessionRegistry.ensureSession(
|
|
1036
|
+
const session = await this.sessionRegistry.ensureSession(
|
|
1037
|
+
envelope.sessionId,
|
|
1038
|
+
envelope.metadata
|
|
1039
|
+
);
|
|
893
1040
|
const execution = this.startSessionExecution(session, envelope, options?.signal);
|
|
894
1041
|
try {
|
|
895
1042
|
for await (const event of this.executor.executeRun(session, envelope, execution.controller)) {
|
|
@@ -960,22 +1107,27 @@ var DefaultNcpAgentBackend = class {
|
|
|
960
1107
|
}
|
|
961
1108
|
async listSessionMessages(sessionId) {
|
|
962
1109
|
const liveSession = this.sessionRegistry.getSession(sessionId);
|
|
963
|
-
if (liveSession)
|
|
964
|
-
return readMessages(liveSession.stateManager.getSnapshot());
|
|
965
|
-
}
|
|
1110
|
+
if (liveSession) return readMessages(liveSession.stateManager.getSnapshot());
|
|
966
1111
|
const session = await this.sessionStore.getSession(sessionId);
|
|
967
1112
|
return session ? session.messages.map((message) => structuredClone(message)) : [];
|
|
968
1113
|
}
|
|
969
1114
|
async getSession(sessionId) {
|
|
970
1115
|
const liveSession = this.sessionRegistry.getSession(sessionId);
|
|
971
1116
|
const storedSession = await this.sessionStore.getSession(sessionId);
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1117
|
+
return storedSession ? toSessionSummary(storedSession, liveSession) : liveSession ? toLiveSessionSummary(liveSession) : null;
|
|
1118
|
+
}
|
|
1119
|
+
async updateSession(sessionId, patch) {
|
|
1120
|
+
const liveSession = this.sessionRegistry.getSession(sessionId);
|
|
1121
|
+
const storedSession = await this.sessionStore.getSession(sessionId);
|
|
1122
|
+
if (!liveSession && !storedSession) return null;
|
|
1123
|
+
await this.sessionStore.saveSession(buildUpdatedSessionRecord({
|
|
1124
|
+
sessionId,
|
|
1125
|
+
patch,
|
|
1126
|
+
liveSession,
|
|
1127
|
+
storedSession,
|
|
1128
|
+
updatedAt: now()
|
|
1129
|
+
}));
|
|
1130
|
+
return this.getSession(sessionId);
|
|
979
1131
|
}
|
|
980
1132
|
async deleteSession(sessionId) {
|
|
981
1133
|
const liveSession = this.sessionRegistry.deleteSession(sessionId);
|
|
@@ -1060,7 +1212,7 @@ var DefaultNcpAgentBackend = class {
|
|
|
1060
1212
|
}
|
|
1061
1213
|
async createAbortEvent(sessionId, messageId) {
|
|
1062
1214
|
const abortEvent = {
|
|
1063
|
-
type:
|
|
1215
|
+
type: NcpEventType5.MessageAbort,
|
|
1064
1216
|
payload: {
|
|
1065
1217
|
sessionId,
|
|
1066
1218
|
...messageId ? { messageId } : {}
|
|
@@ -1075,57 +1227,14 @@ var DefaultNcpAgentBackend = class {
|
|
|
1075
1227
|
}
|
|
1076
1228
|
async persistSession(sessionId) {
|
|
1077
1229
|
const session = this.sessionRegistry.getSession(sessionId);
|
|
1078
|
-
if (!session)
|
|
1079
|
-
|
|
1080
|
-
}
|
|
1081
|
-
const snapshot = session.stateManager.getSnapshot();
|
|
1082
|
-
await this.sessionStore.saveSession({
|
|
1230
|
+
if (!session) return;
|
|
1231
|
+
await this.sessionStore.saveSession(buildPersistedLiveSessionRecord({
|
|
1083
1232
|
sessionId,
|
|
1084
|
-
|
|
1085
|
-
updatedAt: now()
|
|
1086
|
-
|
|
1087
|
-
});
|
|
1233
|
+
session,
|
|
1234
|
+
updatedAt: now()
|
|
1235
|
+
}));
|
|
1088
1236
|
}
|
|
1089
1237
|
};
|
|
1090
|
-
function readMessages(snapshot) {
|
|
1091
|
-
const messages = snapshot.messages.map((message) => structuredClone(message));
|
|
1092
|
-
if (snapshot.streamingMessage) {
|
|
1093
|
-
messages.push(structuredClone(snapshot.streamingMessage));
|
|
1094
|
-
}
|
|
1095
|
-
return messages;
|
|
1096
|
-
}
|
|
1097
|
-
function toSessionSummary(session, liveSession) {
|
|
1098
|
-
return {
|
|
1099
|
-
sessionId: session.sessionId,
|
|
1100
|
-
messageCount: session.messages.length,
|
|
1101
|
-
updatedAt: session.updatedAt,
|
|
1102
|
-
status: liveSession?.activeExecution ? "running" : "idle",
|
|
1103
|
-
...session.metadata ? { metadata: structuredClone(session.metadata) } : {}
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
function toLiveSessionSummary(session) {
|
|
1107
|
-
const snapshot = session.stateManager.getSnapshot();
|
|
1108
|
-
return {
|
|
1109
|
-
sessionId: session.sessionId,
|
|
1110
|
-
messageCount: readMessages(snapshot).length,
|
|
1111
|
-
updatedAt: now(),
|
|
1112
|
-
status: session.activeExecution ? "running" : "idle",
|
|
1113
|
-
...session.activeExecution?.requestEnvelope.metadata ? { metadata: structuredClone(session.activeExecution.requestEnvelope.metadata) } : {}
|
|
1114
|
-
};
|
|
1115
|
-
}
|
|
1116
|
-
function now() {
|
|
1117
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1118
|
-
}
|
|
1119
|
-
function isTerminalEvent(event) {
|
|
1120
|
-
switch (event.type) {
|
|
1121
|
-
case NcpEventType4.MessageAbort:
|
|
1122
|
-
case NcpEventType4.RunFinished:
|
|
1123
|
-
case NcpEventType4.RunError:
|
|
1124
|
-
return true;
|
|
1125
|
-
default:
|
|
1126
|
-
return false;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
1238
|
|
|
1130
1239
|
// src/agent/agent-backend/in-memory-agent-session-store.ts
|
|
1131
1240
|
var InMemoryAgentSessionStore = class {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Toolkit implementations built on top of the NextClaw Communication Protocol.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@nextclaw/ncp": "0.3.
|
|
18
|
+
"@nextclaw/ncp": "0.3.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^20.17.6",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"tsup": "^8.3.5",
|
|
24
24
|
"typescript": "^5.6.3",
|
|
25
25
|
"vitest": "^2.1.2",
|
|
26
|
-
"@nextclaw/ncp-agent-runtime": "0.2.
|
|
26
|
+
"@nextclaw/ncp-agent-runtime": "0.2.1"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "tsup src/index.ts --format esm --dts --out-dir dist",
|