@nextclaw/ncp-toolkit 0.5.12 → 0.5.14
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 +24 -8
- package/dist/index.js +181 -66
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ declare class EventPublisher {
|
|
|
72
72
|
close(): void;
|
|
73
73
|
}
|
|
74
74
|
//#endregion
|
|
75
|
-
//#region src/agent/agent-backend/agent-backend
|
|
75
|
+
//#region src/agent/agent-backend/agent-backend.types.d.ts
|
|
76
76
|
type RuntimeFactoryParams = {
|
|
77
77
|
sessionId: string;
|
|
78
78
|
agentId?: string;
|
|
@@ -87,6 +87,14 @@ type AgentSessionRecord = {
|
|
|
87
87
|
sessionId: string;
|
|
88
88
|
agentId?: string;
|
|
89
89
|
messages: NcpMessage[];
|
|
90
|
+
createdAt?: string;
|
|
91
|
+
updatedAt: string;
|
|
92
|
+
metadata?: Record<string, unknown>;
|
|
93
|
+
};
|
|
94
|
+
type AgentSessionEventRecord = {
|
|
95
|
+
sessionId: string;
|
|
96
|
+
agentId?: string;
|
|
97
|
+
createdAt?: string;
|
|
90
98
|
updatedAt: string;
|
|
91
99
|
metadata?: Record<string, unknown>;
|
|
92
100
|
};
|
|
@@ -99,6 +107,7 @@ type LiveSessionExecution = {
|
|
|
99
107
|
type LiveSessionState = {
|
|
100
108
|
sessionId: string;
|
|
101
109
|
agentId?: string;
|
|
110
|
+
createdAt: string;
|
|
102
111
|
runtime: NcpAgentRuntime;
|
|
103
112
|
stateManager: NcpAgentConversationStateManager;
|
|
104
113
|
metadata: Record<string, unknown>;
|
|
@@ -108,19 +117,27 @@ type LiveSessionState = {
|
|
|
108
117
|
interface AgentSessionStore {
|
|
109
118
|
getSession(sessionId: string): Promise<AgentSessionRecord | null>;
|
|
110
119
|
listSessions(): Promise<AgentSessionRecord[]>;
|
|
120
|
+
getSessionSummary?(sessionId: string): Promise<NcpSessionSummary | null>;
|
|
121
|
+
listSessionSummaries?(): Promise<NcpSessionSummary[]>;
|
|
122
|
+
listSessionMessages?(sessionId: string): Promise<NcpMessage[]>;
|
|
123
|
+
appendSessionEvent?(params: {
|
|
124
|
+
session: AgentSessionEventRecord;
|
|
125
|
+
event: NcpEndpointEvent;
|
|
126
|
+
updatedAt: string;
|
|
127
|
+
}): Promise<void>;
|
|
111
128
|
saveSession(session: AgentSessionRecord): Promise<void>;
|
|
112
129
|
replaceSession(session: AgentSessionRecord): Promise<void>;
|
|
113
130
|
deleteSession(sessionId: string): Promise<AgentSessionRecord | null>;
|
|
114
131
|
}
|
|
115
132
|
//#endregion
|
|
116
|
-
//#region src/agent/agent-backend/agent-backend-session
|
|
133
|
+
//#region src/agent/agent-backend/agent-backend-session.utils.d.ts
|
|
117
134
|
type SessionContextWindowResolver = (params: {
|
|
118
135
|
messages: readonly NcpMessage[];
|
|
119
136
|
metadata: Record<string, unknown>;
|
|
120
137
|
sessionId: string;
|
|
121
138
|
}) => Record<string, unknown> | null;
|
|
122
139
|
//#endregion
|
|
123
|
-
//#region src/agent/agent-backend/agent-backend.d.ts
|
|
140
|
+
//#region src/agent/agent-backend/agent-backend.service.d.ts
|
|
124
141
|
type DefaultNcpAgentBackendConfig = {
|
|
125
142
|
createRuntime: CreateRuntimeFn;
|
|
126
143
|
sessionStore: AgentSessionStore;
|
|
@@ -169,16 +186,15 @@ declare class DefaultNcpAgentBackend implements NcpAgentServerEndpoint, NcpSessi
|
|
|
169
186
|
private startSessionExecution;
|
|
170
187
|
private finishSessionExecution;
|
|
171
188
|
private handleAbort;
|
|
172
|
-
private persistSession;
|
|
173
189
|
}
|
|
174
190
|
//#endregion
|
|
175
|
-
//#region src/agent/agent-backend/agent-run-executor.d.ts
|
|
191
|
+
//#region src/agent/agent-backend/agent-run-executor.service.d.ts
|
|
176
192
|
declare class AgentRunExecutor {
|
|
177
|
-
executeRun(session: LiveSessionState, envelope: NcpRequestEnvelope, controller: AbortController)
|
|
193
|
+
executeRun: (session: LiveSessionState, envelope: NcpRequestEnvelope, controller: AbortController) => AsyncGenerator<NcpEndpointEvent>;
|
|
178
194
|
private publishFailure;
|
|
179
195
|
}
|
|
180
196
|
//#endregion
|
|
181
|
-
//#region src/agent/agent-backend/in-memory-agent-session
|
|
197
|
+
//#region src/agent/agent-backend/in-memory-agent-session.store.d.ts
|
|
182
198
|
declare class InMemoryAgentSessionStore implements AgentSessionStore {
|
|
183
199
|
private readonly sessions;
|
|
184
200
|
getSession: (sessionId: string) => Promise<AgentSessionRecord | null>;
|
|
@@ -224,4 +240,4 @@ declare class NcpReplyConsumer {
|
|
|
224
240
|
consume: (input: NcpReplyInput) => Promise<void>;
|
|
225
241
|
}
|
|
226
242
|
//#endregion
|
|
227
|
-
export { AgentRunExecutor, type AgentSessionRecord, type AgentSessionStore, Chat, ChatTarget, type CreateRuntimeFn, DefaultNcpAgentBackend, type DefaultNcpAgentBackendConfig, DefaultNcpAgentConversationStateManager, EventPublisher, InMemoryAgentSessionStore, type LiveSessionExecution, type LiveSessionState, NcpErrorException, NcpEventStream, NcpReplyConsumer, NcpReplyInput, type RuntimeFactoryParams, createAgentClientFromServer };
|
|
243
|
+
export { AgentRunExecutor, type AgentSessionEventRecord, type AgentSessionRecord, type AgentSessionStore, Chat, ChatTarget, type CreateRuntimeFn, DefaultNcpAgentBackend, type DefaultNcpAgentBackendConfig, DefaultNcpAgentConversationStateManager, EventPublisher, InMemoryAgentSessionStore, type LiveSessionExecution, type LiveSessionState, NcpErrorException, NcpEventStream, NcpReplyConsumer, NcpReplyInput, type RuntimeFactoryParams, createAgentClientFromServer };
|
package/dist/index.js
CHANGED
|
@@ -574,6 +574,9 @@ var DefaultNcpAgentConversationStateManager = class {
|
|
|
574
574
|
};
|
|
575
575
|
//#endregion
|
|
576
576
|
//#region src/agent/agent-client-from-server.ts
|
|
577
|
+
function assertMaterializedEnvelope(envelope) {
|
|
578
|
+
if (!envelope.sessionId?.trim() || !envelope.message.sessionId?.trim()) throw new Error("NCP request envelope must be materialized before server dispatch.");
|
|
579
|
+
}
|
|
577
580
|
/**
|
|
578
581
|
* Creates an NcpAgentClientEndpoint that forwards to an in-process NcpAgentServerEndpoint.
|
|
579
582
|
* Use when the agent runs in-process and you need to pass a client endpoint to the HTTP server.
|
|
@@ -592,6 +595,7 @@ function createAgentClientFromServer(server) {
|
|
|
592
595
|
async emit(event) {
|
|
593
596
|
switch (event.type) {
|
|
594
597
|
case NcpEventType.MessageRequest:
|
|
598
|
+
assertMaterializedEnvelope(event.payload);
|
|
595
599
|
await consume(server.send(event.payload));
|
|
596
600
|
return;
|
|
597
601
|
case NcpEventType.MessageStreamRequest:
|
|
@@ -607,6 +611,7 @@ function createAgentClientFromServer(server) {
|
|
|
607
611
|
return server.subscribe(listener);
|
|
608
612
|
},
|
|
609
613
|
async send(envelope) {
|
|
614
|
+
assertMaterializedEnvelope(envelope);
|
|
610
615
|
await consume(server.send(envelope));
|
|
611
616
|
},
|
|
612
617
|
async stream(payload) {
|
|
@@ -656,7 +661,7 @@ var EventPublisher = class {
|
|
|
656
661
|
}
|
|
657
662
|
};
|
|
658
663
|
//#endregion
|
|
659
|
-
//#region src/agent/agent-backend/agent-live-session-registry.ts
|
|
664
|
+
//#region src/agent/agent-backend/agent-live-session-registry.service.ts
|
|
660
665
|
function readOptionalAgentId$2(value) {
|
|
661
666
|
if (typeof value !== "string") return;
|
|
662
667
|
const trimmed = value.trim().toLowerCase();
|
|
@@ -695,6 +700,7 @@ var AgentLiveSessionRegistry = class {
|
|
|
695
700
|
const session = {
|
|
696
701
|
sessionId,
|
|
697
702
|
...sessionAgentId ? { agentId: sessionAgentId } : {},
|
|
703
|
+
createdAt: storedSession?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
698
704
|
stateManager,
|
|
699
705
|
metadata: sessionMetadata,
|
|
700
706
|
runtime: null,
|
|
@@ -747,7 +753,7 @@ var NcpErrorException = class extends Error {
|
|
|
747
753
|
}
|
|
748
754
|
};
|
|
749
755
|
//#endregion
|
|
750
|
-
//#region src/agent/agent-backend/agent-backend-execution
|
|
756
|
+
//#region src/agent/agent-backend/agent-backend-execution.utils.ts
|
|
751
757
|
function startAgentBackendSessionExecution(params) {
|
|
752
758
|
const { session, envelope, signal, onStatusChanged } = params;
|
|
753
759
|
if (session.activeExecution && !session.activeExecution.closed) throw new NcpErrorException("runtime-error", `Session ${session.sessionId} already has an active execution.`, { sessionId: session.sessionId });
|
|
@@ -775,22 +781,18 @@ function finishAgentBackendSessionExecution(params) {
|
|
|
775
781
|
status: "idle"
|
|
776
782
|
});
|
|
777
783
|
}
|
|
778
|
-
closeAgentBackendSessionExecution(execution);
|
|
779
|
-
}
|
|
780
|
-
function closeAgentBackendSessionExecution(execution) {
|
|
781
|
-
if (execution.closed) return;
|
|
782
|
-
execution.closed = true;
|
|
783
784
|
}
|
|
784
785
|
//#endregion
|
|
785
|
-
//#region src/agent/agent-backend/agent-run-executor.ts
|
|
786
|
+
//#region src/agent/agent-backend/agent-run-executor.service.ts
|
|
786
787
|
var AgentRunExecutor = class {
|
|
787
|
-
|
|
788
|
+
executeRun = (session, envelope, controller) => (async function* (self) {
|
|
788
789
|
if (!isHiddenNcpMessage(envelope.message)) {
|
|
789
790
|
const messageSent = {
|
|
790
791
|
type: NcpEventType.MessageSent,
|
|
791
792
|
payload: {
|
|
792
793
|
sessionId: envelope.sessionId,
|
|
793
794
|
message: structuredClone(envelope.message),
|
|
795
|
+
...envelope.correlationId ? { correlationId: envelope.correlationId } : {},
|
|
794
796
|
metadata: envelope.metadata
|
|
795
797
|
}
|
|
796
798
|
};
|
|
@@ -803,27 +805,39 @@ var AgentRunExecutor = class {
|
|
|
803
805
|
messages: [envelope.message],
|
|
804
806
|
correlationId: envelope.correlationId,
|
|
805
807
|
metadata: envelope.metadata
|
|
806
|
-
}, { signal: controller.signal })) yield
|
|
808
|
+
}, { signal: controller.signal })) yield normalizeRunEvent(event, envelope);
|
|
807
809
|
} catch (error) {
|
|
808
810
|
if (!controller.signal.aborted) {
|
|
809
|
-
const runErrorEvent = await
|
|
811
|
+
const runErrorEvent = await self.publishFailure(error, envelope, session);
|
|
810
812
|
yield structuredClone(runErrorEvent);
|
|
811
813
|
}
|
|
812
814
|
}
|
|
813
|
-
}
|
|
814
|
-
async
|
|
815
|
+
})(this);
|
|
816
|
+
publishFailure = async (error, envelope, session) => {
|
|
815
817
|
const message = error instanceof Error ? error.message : String(error);
|
|
816
818
|
const runErrorEvent = {
|
|
817
819
|
type: NcpEventType.RunError,
|
|
818
820
|
payload: {
|
|
819
821
|
sessionId: envelope.sessionId,
|
|
822
|
+
...envelope.correlationId ? { correlationId: envelope.correlationId } : {},
|
|
820
823
|
error: message
|
|
821
824
|
}
|
|
822
825
|
};
|
|
823
826
|
await session.stateManager.dispatch(runErrorEvent);
|
|
824
827
|
return runErrorEvent;
|
|
825
|
-
}
|
|
828
|
+
};
|
|
826
829
|
};
|
|
830
|
+
function normalizeRunEvent(event, envelope) {
|
|
831
|
+
if (!("payload" in event) || !event.payload || typeof event.payload !== "object") return structuredClone(event);
|
|
832
|
+
return structuredClone({
|
|
833
|
+
...event,
|
|
834
|
+
payload: {
|
|
835
|
+
...event.payload,
|
|
836
|
+
sessionId: "sessionId" in event.payload && typeof event.payload.sessionId === "string" ? event.payload.sessionId : envelope.sessionId,
|
|
837
|
+
...envelope.correlationId && (!("correlationId" in event.payload) || typeof event.payload.correlationId !== "string") ? { correlationId: envelope.correlationId } : {}
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}
|
|
827
841
|
//#endregion
|
|
828
842
|
//#region src/agent/agent-backend/async-queue.ts
|
|
829
843
|
function createAsyncQueue() {
|
|
@@ -874,7 +888,7 @@ function createAsyncQueue() {
|
|
|
874
888
|
};
|
|
875
889
|
}
|
|
876
890
|
//#endregion
|
|
877
|
-
//#region src/agent/agent-backend/agent-backend-session-realtime.ts
|
|
891
|
+
//#region src/agent/agent-backend/agent-backend-session-realtime.service.ts
|
|
878
892
|
function readEventSessionId(event) {
|
|
879
893
|
const payload = "payload" in event ? event.payload : null;
|
|
880
894
|
if (!payload || typeof payload !== "object") return null;
|
|
@@ -888,7 +902,7 @@ var AgentBackendSessionRealtime = class {
|
|
|
888
902
|
if (options.dispatchToStateManager) await session.stateManager.dispatch(event);
|
|
889
903
|
this.params.publishEndpointEvent(event);
|
|
890
904
|
session.publisher.publish(event);
|
|
891
|
-
if (options.persistSession !== false) await this.params.
|
|
905
|
+
if (options.persistSession !== false) await this.params.persistSessionEvent(session, event);
|
|
892
906
|
};
|
|
893
907
|
streamSessionEvents = (payloadOrParams, opts) => {
|
|
894
908
|
return (async function* (self) {
|
|
@@ -958,7 +972,7 @@ var AgentBackendSessionRealtime = class {
|
|
|
958
972
|
};
|
|
959
973
|
};
|
|
960
974
|
//#endregion
|
|
961
|
-
//#region src/agent/agent-backend/agent-backend-session
|
|
975
|
+
//#region src/agent/agent-backend/agent-backend-session.utils.ts
|
|
962
976
|
const AUTO_SESSION_LABEL_MAX_LENGTH = 64;
|
|
963
977
|
function readOptionalAgentId$1(value) {
|
|
964
978
|
if (typeof value !== "string") return;
|
|
@@ -970,6 +984,9 @@ function readMessages(snapshot) {
|
|
|
970
984
|
if (snapshot.streamingMessage) messages.push(structuredClone(snapshot.streamingMessage));
|
|
971
985
|
return messages;
|
|
972
986
|
}
|
|
987
|
+
function readSessionActivityAt(summary) {
|
|
988
|
+
return summary.lastMessageAt ?? summary.createdAt ?? summary.updatedAt;
|
|
989
|
+
}
|
|
973
990
|
function toSessionSummary(session, liveSession) {
|
|
974
991
|
const metadata = withAutoSessionLabel({
|
|
975
992
|
metadata: session.metadata ? structuredClone({
|
|
@@ -982,6 +999,7 @@ function toSessionSummary(session, liveSession) {
|
|
|
982
999
|
sessionId: session.sessionId,
|
|
983
1000
|
...readOptionalAgentId$1(session.agentId) ? { agentId: readOptionalAgentId$1(session.agentId) } : {},
|
|
984
1001
|
messageCount: session.messages.length,
|
|
1002
|
+
...session.createdAt ? { createdAt: session.createdAt } : {},
|
|
985
1003
|
updatedAt: session.updatedAt,
|
|
986
1004
|
...session.messages.length > 0 ? { lastMessageAt: session.messages[session.messages.length - 1]?.timestamp ?? session.updatedAt } : {},
|
|
987
1005
|
status: liveSession?.activeExecution ? "running" : "idle",
|
|
@@ -999,6 +1017,7 @@ function toLiveSessionSummary(session) {
|
|
|
999
1017
|
sessionId: session.sessionId,
|
|
1000
1018
|
...readOptionalAgentId$1(session.agentId) ? { agentId: readOptionalAgentId$1(session.agentId) } : {},
|
|
1001
1019
|
messageCount: messages.length,
|
|
1020
|
+
createdAt: session.createdAt,
|
|
1002
1021
|
updatedAt,
|
|
1003
1022
|
...messages.length > 0 ? { lastMessageAt: messages[messages.length - 1]?.timestamp ?? updatedAt } : {},
|
|
1004
1023
|
status: session.activeExecution ? "running" : "idle",
|
|
@@ -1020,6 +1039,36 @@ function toLiveSessionSummaryWithContextWindow(session, resolver) {
|
|
|
1020
1039
|
const messages = readMessages(session.stateManager.getSnapshot());
|
|
1021
1040
|
return withSessionContextWindow(toLiveSessionSummary(session), messages, resolver);
|
|
1022
1041
|
}
|
|
1042
|
+
async function listBackendSessionSummaries(params) {
|
|
1043
|
+
const { liveSessions, sessionStore } = params;
|
|
1044
|
+
const summaries = sessionStore.listSessionSummaries ? await sessionStore.listSessionSummaries() : (await sessionStore.listSessions()).map((session) => toSessionSummary(session, liveSessions.find((liveSession) => liveSession.sessionId === session.sessionId) ?? null));
|
|
1045
|
+
for (const liveSession of liveSessions) {
|
|
1046
|
+
const existingIndex = summaries.findIndex((session) => session.sessionId === liveSession.sessionId);
|
|
1047
|
+
if (existingIndex >= 0) {
|
|
1048
|
+
summaries[existingIndex] = {
|
|
1049
|
+
...summaries[existingIndex],
|
|
1050
|
+
status: liveSession.activeExecution ? "running" : "idle"
|
|
1051
|
+
};
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
summaries.push(toLiveSessionSummary(liveSession));
|
|
1055
|
+
}
|
|
1056
|
+
return summaries.sort((left, right) => readSessionActivityAt(right).localeCompare(readSessionActivityAt(left)));
|
|
1057
|
+
}
|
|
1058
|
+
async function listBackendSessionMessages(params) {
|
|
1059
|
+
const { liveSession, sessionId, sessionStore } = params;
|
|
1060
|
+
if (liveSession) return readMessages(liveSession.stateManager.getSnapshot());
|
|
1061
|
+
if (sessionStore.listSessionMessages) return sessionStore.listSessionMessages(sessionId);
|
|
1062
|
+
const session = await sessionStore.getSession(sessionId);
|
|
1063
|
+
return session ? session.messages.map((message) => structuredClone(message)) : [];
|
|
1064
|
+
}
|
|
1065
|
+
async function getBackendSessionSummary(params) {
|
|
1066
|
+
const { liveSession, resolveSessionContextWindow, sessionId, sessionStore } = params;
|
|
1067
|
+
if (!liveSession && sessionStore.getSessionSummary) return sessionStore.getSessionSummary(sessionId);
|
|
1068
|
+
const storedSession = await sessionStore.getSession(sessionId);
|
|
1069
|
+
const liveMessages = liveSession ? readMessages(liveSession.stateManager.getSnapshot()) : null;
|
|
1070
|
+
return storedSession ? withSessionContextWindow(toSessionSummary(storedSession, liveSession), liveMessages ?? storedSession.messages, resolveSessionContextWindow) : liveSession ? toLiveSessionSummaryWithContextWindow(liveSession, resolveSessionContextWindow) : null;
|
|
1071
|
+
}
|
|
1023
1072
|
function now() {
|
|
1024
1073
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1025
1074
|
}
|
|
@@ -1101,7 +1150,7 @@ function normalizeSendRunEvent(params) {
|
|
|
1101
1150
|
};
|
|
1102
1151
|
}
|
|
1103
1152
|
//#endregion
|
|
1104
|
-
//#region src/agent/agent-backend/agent-backend-session-persistence.ts
|
|
1153
|
+
//#region src/agent/agent-backend/agent-backend-session-persistence.utils.ts
|
|
1105
1154
|
function readOptionalAgentId(value) {
|
|
1106
1155
|
if (typeof value !== "string") return;
|
|
1107
1156
|
const trimmed = value.trim().toLowerCase();
|
|
@@ -1111,44 +1160,94 @@ function readAgentIdFromMetadata(metadata) {
|
|
|
1111
1160
|
return readOptionalAgentId(metadata?.agent_id) ?? readOptionalAgentId(metadata?.agentId);
|
|
1112
1161
|
}
|
|
1113
1162
|
function resolvePersistedAgentId(params) {
|
|
1114
|
-
|
|
1163
|
+
const { liveSession, storedSession } = params;
|
|
1164
|
+
return readOptionalAgentId(liveSession?.agentId) ?? readOptionalAgentId(storedSession?.agentId) ?? readAgentIdFromMetadata(liveSession?.metadata) ?? readAgentIdFromMetadata(storedSession?.metadata);
|
|
1115
1165
|
}
|
|
1116
1166
|
function buildUpdatedSessionRecord(params) {
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1167
|
+
const { liveSession, patch, sessionId, storedSession, updatedAt } = params;
|
|
1168
|
+
const nextMetadata = patch.metadata === null ? {} : patch.metadata ? structuredClone(patch.metadata) : structuredClone(liveSession?.metadata ?? storedSession?.metadata ?? {});
|
|
1169
|
+
if (liveSession) liveSession.metadata = structuredClone(nextMetadata);
|
|
1170
|
+
const agentId = resolvePersistedAgentId({
|
|
1171
|
+
liveSession,
|
|
1172
|
+
storedSession
|
|
1173
|
+
});
|
|
1119
1174
|
return {
|
|
1120
|
-
sessionId
|
|
1121
|
-
...
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
liveSession: params.liveSession,
|
|
1126
|
-
storedSession: params.storedSession
|
|
1127
|
-
}) } : {},
|
|
1128
|
-
messages: params.liveSession ? readMessages(params.liveSession.stateManager.getSnapshot()) : params.storedSession?.messages.map((message) => structuredClone(message)) ?? [],
|
|
1129
|
-
updatedAt: params.updatedAt,
|
|
1175
|
+
sessionId,
|
|
1176
|
+
...agentId ? { agentId } : {},
|
|
1177
|
+
messages: liveSession ? readMessages(liveSession.stateManager.getSnapshot()) : storedSession?.messages.map((message) => structuredClone(message)) ?? [],
|
|
1178
|
+
createdAt: storedSession?.createdAt ?? liveSession?.createdAt ?? updatedAt,
|
|
1179
|
+
updatedAt,
|
|
1130
1180
|
metadata: nextMetadata
|
|
1131
1181
|
};
|
|
1132
1182
|
}
|
|
1133
1183
|
function buildPersistedLiveSessionRecord(params) {
|
|
1134
|
-
const
|
|
1184
|
+
const { session, sessionId, updatedAt } = params;
|
|
1185
|
+
const messages = readMessages(session.stateManager.getSnapshot());
|
|
1135
1186
|
const metadata = withAutoSessionLabel({
|
|
1136
1187
|
metadata: {
|
|
1137
|
-
...
|
|
1138
|
-
...
|
|
1188
|
+
...session.metadata ? structuredClone(session.metadata) : {},
|
|
1189
|
+
...session.activeExecution?.requestEnvelope.metadata ? structuredClone(session.activeExecution.requestEnvelope.metadata) : {}
|
|
1139
1190
|
},
|
|
1140
1191
|
messages
|
|
1141
1192
|
});
|
|
1193
|
+
const agentId = readOptionalAgentId(session.agentId) ?? readAgentIdFromMetadata(session.metadata) ?? readAgentIdFromMetadata(session.activeExecution?.requestEnvelope.metadata);
|
|
1142
1194
|
return {
|
|
1143
|
-
sessionId
|
|
1144
|
-
...
|
|
1195
|
+
sessionId,
|
|
1196
|
+
...agentId ? { agentId } : {},
|
|
1145
1197
|
messages,
|
|
1146
|
-
|
|
1198
|
+
createdAt: session.createdAt,
|
|
1199
|
+
updatedAt,
|
|
1200
|
+
metadata
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
function buildLiveSessionEventRecord(params) {
|
|
1204
|
+
const { session, updatedAt } = params;
|
|
1205
|
+
const metadata = {
|
|
1206
|
+
...session.metadata ? structuredClone(session.metadata) : {},
|
|
1207
|
+
...session.activeExecution?.requestEnvelope.metadata ? structuredClone(session.activeExecution.requestEnvelope.metadata) : {}
|
|
1208
|
+
};
|
|
1209
|
+
const agentId = readOptionalAgentId(session.agentId) ?? readAgentIdFromMetadata(session.metadata) ?? readAgentIdFromMetadata(session.activeExecution?.requestEnvelope.metadata);
|
|
1210
|
+
return {
|
|
1211
|
+
sessionId: session.sessionId,
|
|
1212
|
+
...agentId ? { agentId } : {},
|
|
1213
|
+
createdAt: session.createdAt,
|
|
1214
|
+
updatedAt,
|
|
1147
1215
|
metadata
|
|
1148
1216
|
};
|
|
1149
1217
|
}
|
|
1218
|
+
function shouldPersistRunEndSnapshot(sessionStore) {
|
|
1219
|
+
return !sessionStore.appendSessionEvent;
|
|
1220
|
+
}
|
|
1221
|
+
async function persistLiveSession(params) {
|
|
1222
|
+
const { session, sessionId, sessionStore, updatedAt } = params;
|
|
1223
|
+
if (!session) return;
|
|
1224
|
+
await sessionStore.saveSession(buildPersistedLiveSessionRecord({
|
|
1225
|
+
sessionId,
|
|
1226
|
+
session,
|
|
1227
|
+
updatedAt
|
|
1228
|
+
}));
|
|
1229
|
+
}
|
|
1230
|
+
async function persistLiveSessionEvent(params) {
|
|
1231
|
+
const { event, session, sessionStore, updatedAt } = params;
|
|
1232
|
+
if (sessionStore.appendSessionEvent) {
|
|
1233
|
+
await sessionStore.appendSessionEvent({
|
|
1234
|
+
session: buildLiveSessionEventRecord({
|
|
1235
|
+
session,
|
|
1236
|
+
updatedAt
|
|
1237
|
+
}),
|
|
1238
|
+
event,
|
|
1239
|
+
updatedAt
|
|
1240
|
+
});
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
await sessionStore.saveSession(buildPersistedLiveSessionRecord({
|
|
1244
|
+
sessionId: session.sessionId,
|
|
1245
|
+
session,
|
|
1246
|
+
updatedAt
|
|
1247
|
+
}));
|
|
1248
|
+
}
|
|
1150
1249
|
//#endregion
|
|
1151
|
-
//#region src/agent/agent-backend/agent-backend.ts
|
|
1250
|
+
//#region src/agent/agent-backend/agent-backend.service.ts
|
|
1152
1251
|
const DEFAULT_SUPPORTED_PART_TYPES = [
|
|
1153
1252
|
"text",
|
|
1154
1253
|
"file",
|
|
@@ -1183,7 +1282,18 @@ var DefaultNcpAgentBackend = class {
|
|
|
1183
1282
|
sessionStore: this.sessionStore,
|
|
1184
1283
|
publishEndpointEvent: (event) => this.publisher.publish(event),
|
|
1185
1284
|
subscribeEndpointEvent: (listener) => this.publisher.subscribe(listener),
|
|
1186
|
-
persistSession: (sessionId) =>
|
|
1285
|
+
persistSession: (sessionId) => persistLiveSession({
|
|
1286
|
+
sessionStore: this.sessionStore,
|
|
1287
|
+
session: this.sessionRegistry.getSession(sessionId),
|
|
1288
|
+
sessionId,
|
|
1289
|
+
updatedAt: now()
|
|
1290
|
+
}),
|
|
1291
|
+
persistSessionEvent: (session, event) => persistLiveSessionEvent({
|
|
1292
|
+
sessionStore: this.sessionStore,
|
|
1293
|
+
session,
|
|
1294
|
+
event,
|
|
1295
|
+
updatedAt: now()
|
|
1296
|
+
}),
|
|
1187
1297
|
getSessionSummary: (sessionId) => this.getSession(sessionId)
|
|
1188
1298
|
});
|
|
1189
1299
|
this.manifest = {
|
|
@@ -1224,7 +1334,15 @@ var DefaultNcpAgentBackend = class {
|
|
|
1224
1334
|
await this.ensureStarted();
|
|
1225
1335
|
switch (event.type) {
|
|
1226
1336
|
case NcpEventType.MessageRequest:
|
|
1227
|
-
|
|
1337
|
+
if (!event.payload.sessionId) throw new Error("MessageRequest requires a sessionId before it reaches the agent backend.");
|
|
1338
|
+
for await (const emittedEvent of this.send({
|
|
1339
|
+
...event.payload,
|
|
1340
|
+
sessionId: event.payload.sessionId,
|
|
1341
|
+
message: {
|
|
1342
|
+
...event.payload.message,
|
|
1343
|
+
sessionId: event.payload.sessionId
|
|
1344
|
+
}
|
|
1345
|
+
}));
|
|
1228
1346
|
return;
|
|
1229
1347
|
case NcpEventType.MessageStreamRequest:
|
|
1230
1348
|
await this.ensureStarted();
|
|
@@ -1266,31 +1384,37 @@ var DefaultNcpAgentBackend = class {
|
|
|
1266
1384
|
}
|
|
1267
1385
|
} finally {
|
|
1268
1386
|
self.finishSessionExecution(session, execution);
|
|
1269
|
-
|
|
1387
|
+
if (shouldPersistRunEndSnapshot(self.sessionStore)) await persistLiveSession({
|
|
1388
|
+
sessionStore: self.sessionStore,
|
|
1389
|
+
session,
|
|
1390
|
+
sessionId: session.sessionId,
|
|
1391
|
+
updatedAt: now()
|
|
1392
|
+
});
|
|
1270
1393
|
}
|
|
1271
1394
|
})(this);
|
|
1272
1395
|
};
|
|
1273
1396
|
abort = async (payload) => this.handleAbort(payload);
|
|
1274
1397
|
stream = (payloadOrParams, opts) => this.sessionRealtime.streamSessionEvents(payloadOrParams, opts);
|
|
1275
1398
|
listSessions = async () => {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}
|
|
1281
|
-
return summaries.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
1399
|
+
return listBackendSessionSummaries({
|
|
1400
|
+
sessionStore: this.sessionStore,
|
|
1401
|
+
liveSessions: this.sessionRegistry.listSessions()
|
|
1402
|
+
});
|
|
1282
1403
|
};
|
|
1283
1404
|
listSessionMessages = async (sessionId) => {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1405
|
+
return listBackendSessionMessages({
|
|
1406
|
+
sessionStore: this.sessionStore,
|
|
1407
|
+
liveSession: this.sessionRegistry.getSession(sessionId),
|
|
1408
|
+
sessionId
|
|
1409
|
+
});
|
|
1288
1410
|
};
|
|
1289
1411
|
getSession = async (sessionId) => {
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1412
|
+
return getBackendSessionSummary({
|
|
1413
|
+
sessionStore: this.sessionStore,
|
|
1414
|
+
liveSession: this.sessionRegistry.getSession(sessionId),
|
|
1415
|
+
sessionId,
|
|
1416
|
+
resolveSessionContextWindow: this.resolveSessionContextWindow
|
|
1417
|
+
});
|
|
1294
1418
|
};
|
|
1295
1419
|
appendMessage = async (sessionId, message) => {
|
|
1296
1420
|
await this.ensureStarted();
|
|
@@ -1319,7 +1443,7 @@ var DefaultNcpAgentBackend = class {
|
|
|
1319
1443
|
if (execution) {
|
|
1320
1444
|
execution.abortHandled = true;
|
|
1321
1445
|
execution.controller.abort();
|
|
1322
|
-
|
|
1446
|
+
execution.closed = true;
|
|
1323
1447
|
}
|
|
1324
1448
|
liveSession?.publisher.close();
|
|
1325
1449
|
await this.sessionStore.deleteSession(sessionId);
|
|
@@ -1354,18 +1478,9 @@ var DefaultNcpAgentBackend = class {
|
|
|
1354
1478
|
await this.sessionRealtime.publishSessionEvent(session, abortEvent, { dispatchToStateManager: true });
|
|
1355
1479
|
this.finishSessionExecution(session, execution);
|
|
1356
1480
|
};
|
|
1357
|
-
persistSession = async (sessionId) => {
|
|
1358
|
-
const session = this.sessionRegistry.getSession(sessionId);
|
|
1359
|
-
if (!session) return;
|
|
1360
|
-
await this.sessionStore.saveSession(buildPersistedLiveSessionRecord({
|
|
1361
|
-
sessionId,
|
|
1362
|
-
session,
|
|
1363
|
-
updatedAt: now()
|
|
1364
|
-
}));
|
|
1365
|
-
};
|
|
1366
1481
|
};
|
|
1367
1482
|
//#endregion
|
|
1368
|
-
//#region src/agent/agent-backend/in-memory-agent-session
|
|
1483
|
+
//#region src/agent/agent-backend/in-memory-agent-session.store.ts
|
|
1369
1484
|
var InMemoryAgentSessionStore = class {
|
|
1370
1485
|
sessions = /* @__PURE__ */ new Map();
|
|
1371
1486
|
getSession = async (sessionId) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ncp-toolkit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Toolkit implementations built on top of the NextClaw Communication Protocol.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@nextclaw/ncp": "0.5.
|
|
18
|
+
"@nextclaw/ncp": "0.5.9"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^20.17.6",
|
|
22
22
|
"prettier": "^3.3.3",
|
|
23
23
|
"typescript": "^5.6.3",
|
|
24
24
|
"vitest": "^4.1.2",
|
|
25
|
-
"@nextclaw/ncp-agent-runtime": "0.3.
|
|
25
|
+
"@nextclaw/ncp-agent-runtime": "0.3.19"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsdown src/index.ts --dts --clean --target es2022 --no-fixedExtension",
|