@nextclaw/ncp-toolkit 0.4.15 → 0.4.17
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 +10 -13
- package/dist/index.js +377 -369
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,6 @@ type AgentSessionRecord = {
|
|
|
82
82
|
};
|
|
83
83
|
type LiveSessionExecution = {
|
|
84
84
|
controller: AbortController;
|
|
85
|
-
publisher: EventPublisher;
|
|
86
85
|
requestEnvelope: NcpRequestEnvelope;
|
|
87
86
|
abortHandled: boolean;
|
|
88
87
|
closed: boolean;
|
|
@@ -92,12 +91,14 @@ type LiveSessionState = {
|
|
|
92
91
|
runtime: NcpAgentRuntime;
|
|
93
92
|
stateManager: NcpAgentConversationStateManager;
|
|
94
93
|
metadata: Record<string, unknown>;
|
|
94
|
+
publisher: EventPublisher;
|
|
95
95
|
activeExecution: LiveSessionExecution | null;
|
|
96
96
|
};
|
|
97
97
|
interface AgentSessionStore {
|
|
98
98
|
getSession(sessionId: string): Promise<AgentSessionRecord | null>;
|
|
99
99
|
listSessions(): Promise<AgentSessionRecord[]>;
|
|
100
100
|
saveSession(session: AgentSessionRecord): Promise<void>;
|
|
101
|
+
replaceSession(session: AgentSessionRecord): Promise<void>;
|
|
101
102
|
deleteSession(sessionId: string): Promise<AgentSessionRecord | null>;
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -123,12 +124,13 @@ declare class DefaultNcpAgentBackend implements NcpAgentServerEndpoint, NcpSessi
|
|
|
123
124
|
private readonly sessionRegistry;
|
|
124
125
|
private readonly executor;
|
|
125
126
|
private readonly publisher;
|
|
127
|
+
private readonly sessionRealtime;
|
|
126
128
|
private started;
|
|
127
129
|
constructor(config: DefaultNcpAgentBackendConfig);
|
|
128
130
|
start: () => Promise<void>;
|
|
129
131
|
stop: () => Promise<void>;
|
|
130
132
|
emit: (event: NcpEndpointEvent) => Promise<void>;
|
|
131
|
-
subscribe: (listener: (event: NcpEndpointEvent) => void) => () => void;
|
|
133
|
+
subscribe: (listener: (event: NcpEndpointEvent) => void) => (() => void);
|
|
132
134
|
send: (envelope: NcpRequestEnvelope, options?: NcpAgentRunSendOptions) => AsyncIterable<NcpEndpointEvent>;
|
|
133
135
|
abort: (payload: NcpMessageAbortPayload) => Promise<void>;
|
|
134
136
|
stream: (payloadOrParams: NcpStreamRequestPayload | {
|
|
@@ -145,28 +147,23 @@ declare class DefaultNcpAgentBackend implements NcpAgentServerEndpoint, NcpSessi
|
|
|
145
147
|
private ensureStarted;
|
|
146
148
|
private startSessionExecution;
|
|
147
149
|
private finishSessionExecution;
|
|
148
|
-
private
|
|
149
|
-
private publishLiveEvent;
|
|
150
|
-
private handleRequest;
|
|
151
|
-
private streamToSubscribers;
|
|
150
|
+
private publishEndpointEvent;
|
|
152
151
|
private handleAbort;
|
|
153
|
-
private createAbortEvent;
|
|
154
152
|
private persistSession;
|
|
155
153
|
}
|
|
156
154
|
|
|
157
155
|
declare class AgentRunExecutor {
|
|
158
|
-
private readonly persistSession;
|
|
159
|
-
constructor(persistSession: (sessionId: string) => Promise<void>);
|
|
160
156
|
executeRun(session: LiveSessionState, envelope: NcpRequestEnvelope, controller: AbortController): AsyncGenerator<NcpEndpointEvent>;
|
|
161
157
|
private publishFailure;
|
|
162
158
|
}
|
|
163
159
|
|
|
164
160
|
declare class InMemoryAgentSessionStore implements AgentSessionStore {
|
|
165
161
|
private readonly sessions;
|
|
166
|
-
getSession(sessionId: string)
|
|
167
|
-
listSessions()
|
|
168
|
-
saveSession(session: AgentSessionRecord)
|
|
169
|
-
|
|
162
|
+
getSession: (sessionId: string) => Promise<AgentSessionRecord | null>;
|
|
163
|
+
listSessions: () => Promise<AgentSessionRecord[]>;
|
|
164
|
+
saveSession: (session: AgentSessionRecord) => Promise<void>;
|
|
165
|
+
replaceSession: (session: AgentSessionRecord) => Promise<void>;
|
|
166
|
+
deleteSession: (sessionId: string) => Promise<AgentSessionRecord | null>;
|
|
170
167
|
}
|
|
171
168
|
|
|
172
169
|
/**
|
package/dist/index.js
CHANGED
|
@@ -702,18 +702,51 @@ async function consume(events) {
|
|
|
702
702
|
|
|
703
703
|
// src/agent/agent-backend/agent-backend.ts
|
|
704
704
|
import {
|
|
705
|
-
NcpEventType as
|
|
705
|
+
NcpEventType as NcpEventType6
|
|
706
706
|
} from "@nextclaw/ncp";
|
|
707
707
|
|
|
708
|
-
// src/
|
|
709
|
-
var
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
this.
|
|
715
|
-
|
|
716
|
-
|
|
708
|
+
// src/agent/agent-backend/event-publisher.ts
|
|
709
|
+
var EventPublisher = class {
|
|
710
|
+
listeners = /* @__PURE__ */ new Set();
|
|
711
|
+
closeListeners = /* @__PURE__ */ new Set();
|
|
712
|
+
closed = false;
|
|
713
|
+
subscribe(listener) {
|
|
714
|
+
if (this.closed) {
|
|
715
|
+
return () => void 0;
|
|
716
|
+
}
|
|
717
|
+
this.listeners.add(listener);
|
|
718
|
+
return () => {
|
|
719
|
+
this.listeners.delete(listener);
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
onClose(listener) {
|
|
723
|
+
if (this.closed) {
|
|
724
|
+
listener();
|
|
725
|
+
return () => void 0;
|
|
726
|
+
}
|
|
727
|
+
this.closeListeners.add(listener);
|
|
728
|
+
return () => {
|
|
729
|
+
this.closeListeners.delete(listener);
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
publish(event) {
|
|
733
|
+
if (this.closed) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
for (const listener of this.listeners) {
|
|
737
|
+
listener(structuredClone(event));
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
close() {
|
|
741
|
+
if (this.closed) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
this.closed = true;
|
|
745
|
+
this.listeners.clear();
|
|
746
|
+
for (const listener of this.closeListeners) {
|
|
747
|
+
listener();
|
|
748
|
+
}
|
|
749
|
+
this.closeListeners.clear();
|
|
717
750
|
}
|
|
718
751
|
};
|
|
719
752
|
|
|
@@ -750,6 +783,7 @@ var AgentLiveSessionRegistry = class {
|
|
|
750
783
|
stateManager,
|
|
751
784
|
metadata: sessionMetadata,
|
|
752
785
|
runtime: null,
|
|
786
|
+
publisher: new EventPublisher(),
|
|
753
787
|
activeExecution: null
|
|
754
788
|
};
|
|
755
789
|
session.runtime = this.createRuntime({
|
|
@@ -786,15 +820,65 @@ function cloneMessages(messages) {
|
|
|
786
820
|
return messages.map((message) => structuredClone(message));
|
|
787
821
|
}
|
|
788
822
|
|
|
823
|
+
// src/errors/ncp-error-exception.ts
|
|
824
|
+
var NcpErrorException = class extends Error {
|
|
825
|
+
code;
|
|
826
|
+
details;
|
|
827
|
+
constructor(code, message, details) {
|
|
828
|
+
super(message);
|
|
829
|
+
this.name = "NcpErrorException";
|
|
830
|
+
this.code = code;
|
|
831
|
+
this.details = details;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
// src/agent/agent-backend/agent-backend-execution-utils.ts
|
|
836
|
+
function startAgentBackendSessionExecution(params) {
|
|
837
|
+
const { session, envelope, signal, onStatusChanged } = params;
|
|
838
|
+
if (session.activeExecution && !session.activeExecution.closed) {
|
|
839
|
+
throw new NcpErrorException(
|
|
840
|
+
"runtime-error",
|
|
841
|
+
`Session ${session.sessionId} already has an active execution.`,
|
|
842
|
+
{ sessionId: session.sessionId }
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
const controller = new AbortController();
|
|
846
|
+
if (signal) {
|
|
847
|
+
signal.addEventListener("abort", () => controller.abort(), {
|
|
848
|
+
once: true
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
const execution = {
|
|
852
|
+
controller,
|
|
853
|
+
requestEnvelope: structuredClone(envelope),
|
|
854
|
+
abortHandled: false,
|
|
855
|
+
closed: false
|
|
856
|
+
};
|
|
857
|
+
session.activeExecution = execution;
|
|
858
|
+
onStatusChanged?.({ sessionKey: session.sessionId, status: "running" });
|
|
859
|
+
return execution;
|
|
860
|
+
}
|
|
861
|
+
function finishAgentBackendSessionExecution(params) {
|
|
862
|
+
const { session, execution, onStatusChanged } = params;
|
|
863
|
+
if (session.activeExecution === execution) {
|
|
864
|
+
session.activeExecution = null;
|
|
865
|
+
onStatusChanged?.({ sessionKey: session.sessionId, status: "idle" });
|
|
866
|
+
}
|
|
867
|
+
closeAgentBackendSessionExecution(execution);
|
|
868
|
+
}
|
|
869
|
+
function closeAgentBackendSessionExecution(execution) {
|
|
870
|
+
if (execution.closed) {
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
execution.closed = true;
|
|
874
|
+
}
|
|
875
|
+
|
|
789
876
|
// src/agent/agent-backend/agent-run-executor.ts
|
|
790
877
|
import {
|
|
791
878
|
isHiddenNcpMessage
|
|
792
879
|
} from "@nextclaw/ncp";
|
|
793
880
|
import { NcpEventType as NcpEventType3 } from "@nextclaw/ncp";
|
|
794
881
|
var AgentRunExecutor = class {
|
|
795
|
-
constructor(persistSession) {
|
|
796
|
-
this.persistSession = persistSession;
|
|
797
|
-
}
|
|
798
882
|
async *executeRun(session, envelope, controller) {
|
|
799
883
|
if (!isHiddenNcpMessage(envelope.message)) {
|
|
800
884
|
const messageSent = {
|
|
@@ -806,7 +890,6 @@ var AgentRunExecutor = class {
|
|
|
806
890
|
}
|
|
807
891
|
};
|
|
808
892
|
await session.stateManager.dispatch(messageSent);
|
|
809
|
-
await this.persistSession(envelope.sessionId);
|
|
810
893
|
yield structuredClone(messageSent);
|
|
811
894
|
}
|
|
812
895
|
try {
|
|
@@ -819,16 +902,17 @@ var AgentRunExecutor = class {
|
|
|
819
902
|
},
|
|
820
903
|
{ signal: controller.signal }
|
|
821
904
|
)) {
|
|
822
|
-
await this.persistSession(envelope.sessionId);
|
|
823
905
|
yield structuredClone(event);
|
|
824
906
|
}
|
|
825
907
|
} catch (error) {
|
|
826
908
|
if (!controller.signal.aborted) {
|
|
827
|
-
const runErrorEvent = await this.publishFailure(
|
|
909
|
+
const runErrorEvent = await this.publishFailure(
|
|
910
|
+
error,
|
|
911
|
+
envelope,
|
|
912
|
+
session
|
|
913
|
+
);
|
|
828
914
|
yield structuredClone(runErrorEvent);
|
|
829
915
|
}
|
|
830
|
-
} finally {
|
|
831
|
-
await this.persistSession(envelope.sessionId);
|
|
832
916
|
}
|
|
833
917
|
}
|
|
834
918
|
async publishFailure(error, envelope, session) {
|
|
@@ -841,13 +925,179 @@ var AgentRunExecutor = class {
|
|
|
841
925
|
}
|
|
842
926
|
};
|
|
843
927
|
await session.stateManager.dispatch(runErrorEvent);
|
|
844
|
-
await this.persistSession(envelope.sessionId);
|
|
845
928
|
return runErrorEvent;
|
|
846
929
|
}
|
|
847
930
|
};
|
|
848
931
|
|
|
849
|
-
// src/agent/agent-backend/agent-backend-session-
|
|
932
|
+
// src/agent/agent-backend/agent-backend-session-realtime.ts
|
|
850
933
|
import { NcpEventType as NcpEventType4 } from "@nextclaw/ncp";
|
|
934
|
+
|
|
935
|
+
// src/agent/agent-backend/async-queue.ts
|
|
936
|
+
function createAsyncQueue() {
|
|
937
|
+
const items = [];
|
|
938
|
+
let closed = false;
|
|
939
|
+
let pendingResolve = null;
|
|
940
|
+
const iterable = {
|
|
941
|
+
[Symbol.asyncIterator]() {
|
|
942
|
+
return {
|
|
943
|
+
next: () => {
|
|
944
|
+
if (items.length > 0) {
|
|
945
|
+
return Promise.resolve({
|
|
946
|
+
value: items.shift(),
|
|
947
|
+
done: false
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
if (closed) {
|
|
951
|
+
return Promise.resolve({
|
|
952
|
+
value: void 0,
|
|
953
|
+
done: true
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
return new Promise((resolve) => {
|
|
957
|
+
pendingResolve = resolve;
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
return {
|
|
964
|
+
push(item) {
|
|
965
|
+
if (closed) {
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
if (pendingResolve) {
|
|
969
|
+
const resolve = pendingResolve;
|
|
970
|
+
pendingResolve = null;
|
|
971
|
+
resolve({ value: item, done: false });
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
items.push(item);
|
|
975
|
+
},
|
|
976
|
+
close() {
|
|
977
|
+
if (closed) {
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
closed = true;
|
|
981
|
+
if (pendingResolve) {
|
|
982
|
+
const resolve = pendingResolve;
|
|
983
|
+
pendingResolve = null;
|
|
984
|
+
resolve({
|
|
985
|
+
value: void 0,
|
|
986
|
+
done: true
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
},
|
|
990
|
+
iterable
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// src/agent/agent-backend/agent-backend-session-realtime.ts
|
|
995
|
+
var AgentBackendSessionRealtime = class {
|
|
996
|
+
constructor(params) {
|
|
997
|
+
this.params = params;
|
|
998
|
+
}
|
|
999
|
+
publishSessionEvent = async (session, event, options = {}) => {
|
|
1000
|
+
if (options.dispatchToStateManager) {
|
|
1001
|
+
await session.stateManager.dispatch(event);
|
|
1002
|
+
}
|
|
1003
|
+
this.params.publishEndpointEvent(event);
|
|
1004
|
+
session.publisher.publish(event);
|
|
1005
|
+
if (options.persistSession !== false) {
|
|
1006
|
+
await this.params.persistSession(session.sessionId);
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
streamSessionEvents = (payloadOrParams, opts) => {
|
|
1010
|
+
return (async function* (self) {
|
|
1011
|
+
const payload = "payload" in payloadOrParams && "signal" in payloadOrParams ? payloadOrParams.payload : payloadOrParams;
|
|
1012
|
+
const signal = "payload" in payloadOrParams && "signal" in payloadOrParams ? payloadOrParams.signal : opts?.signal ?? new AbortController().signal;
|
|
1013
|
+
const session = await self.params.sessionRegistry.ensureSession(
|
|
1014
|
+
payload.sessionId
|
|
1015
|
+
);
|
|
1016
|
+
const queue = createAsyncQueue();
|
|
1017
|
+
const unsubscribe = session.publisher.subscribe((event) => {
|
|
1018
|
+
queue.push(event);
|
|
1019
|
+
});
|
|
1020
|
+
const unsubscribeClose = session.publisher.onClose(() => {
|
|
1021
|
+
queue.close();
|
|
1022
|
+
});
|
|
1023
|
+
const stop = () => {
|
|
1024
|
+
unsubscribe();
|
|
1025
|
+
unsubscribeClose();
|
|
1026
|
+
queue.close();
|
|
1027
|
+
signal.removeEventListener("abort", stop);
|
|
1028
|
+
};
|
|
1029
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
1030
|
+
try {
|
|
1031
|
+
for await (const event of queue.iterable) {
|
|
1032
|
+
if (signal.aborted) {
|
|
1033
|
+
break;
|
|
1034
|
+
}
|
|
1035
|
+
yield event;
|
|
1036
|
+
}
|
|
1037
|
+
} finally {
|
|
1038
|
+
stop();
|
|
1039
|
+
}
|
|
1040
|
+
})(this);
|
|
1041
|
+
};
|
|
1042
|
+
appendMessage = async (sessionId, message) => {
|
|
1043
|
+
const normalizedSessionId = sessionId.trim();
|
|
1044
|
+
if (!normalizedSessionId) {
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
let liveSession = this.params.sessionRegistry.getSession(normalizedSessionId);
|
|
1048
|
+
if (!liveSession) {
|
|
1049
|
+
const storedSession = await this.params.sessionStore.getSession(normalizedSessionId);
|
|
1050
|
+
if (!storedSession) {
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
liveSession = await this.params.sessionRegistry.ensureSession(normalizedSessionId);
|
|
1054
|
+
}
|
|
1055
|
+
const nextMessage = {
|
|
1056
|
+
...structuredClone(message),
|
|
1057
|
+
sessionId: normalizedSessionId
|
|
1058
|
+
};
|
|
1059
|
+
await this.publishSessionEvent(
|
|
1060
|
+
liveSession,
|
|
1061
|
+
{
|
|
1062
|
+
type: NcpEventType4.MessageSent,
|
|
1063
|
+
payload: {
|
|
1064
|
+
sessionId: normalizedSessionId,
|
|
1065
|
+
message: nextMessage
|
|
1066
|
+
}
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
dispatchToStateManager: true
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
return this.params.getSessionSummary(normalizedSessionId);
|
|
1073
|
+
};
|
|
1074
|
+
updateToolCallResult = async (sessionId, toolCallId, content) => {
|
|
1075
|
+
const normalizedSessionId = sessionId.trim();
|
|
1076
|
+
const normalizedToolCallId = toolCallId.trim();
|
|
1077
|
+
if (!normalizedSessionId || !normalizedToolCallId) {
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
const liveSession = await this.params.sessionRegistry.ensureSession(normalizedSessionId);
|
|
1081
|
+
await this.publishSessionEvent(
|
|
1082
|
+
liveSession,
|
|
1083
|
+
{
|
|
1084
|
+
type: NcpEventType4.MessageToolCallResult,
|
|
1085
|
+
payload: {
|
|
1086
|
+
sessionId: normalizedSessionId,
|
|
1087
|
+
toolCallId: normalizedToolCallId,
|
|
1088
|
+
content
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
dispatchToStateManager: true
|
|
1093
|
+
}
|
|
1094
|
+
);
|
|
1095
|
+
return this.params.getSessionSummary(normalizedSessionId);
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
|
|
1099
|
+
// src/agent/agent-backend/agent-backend-session-utils.ts
|
|
1100
|
+
import { NcpEventType as NcpEventType5 } from "@nextclaw/ncp";
|
|
851
1101
|
var AUTO_SESSION_LABEL_MAX_LENGTH = 64;
|
|
852
1102
|
function readMessages(snapshot) {
|
|
853
1103
|
const messages = snapshot.messages.map((message) => structuredClone(message));
|
|
@@ -934,16 +1184,6 @@ function withAutoSessionLabel(params) {
|
|
|
934
1184
|
label: nextLabel
|
|
935
1185
|
};
|
|
936
1186
|
}
|
|
937
|
-
function isTerminalEvent(event) {
|
|
938
|
-
switch (event.type) {
|
|
939
|
-
case NcpEventType4.MessageAbort:
|
|
940
|
-
case NcpEventType4.RunFinished:
|
|
941
|
-
case NcpEventType4.RunError:
|
|
942
|
-
return true;
|
|
943
|
-
default:
|
|
944
|
-
return false;
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
1187
|
|
|
948
1188
|
// src/agent/agent-backend/agent-backend-session-persistence.ts
|
|
949
1189
|
function buildUpdatedSessionRecord(params) {
|
|
@@ -975,222 +1215,19 @@ function buildPersistedLiveSessionRecord(params) {
|
|
|
975
1215
|
};
|
|
976
1216
|
}
|
|
977
1217
|
|
|
978
|
-
// src/agent/agent-backend/agent-backend-update-tool-call-result.ts
|
|
979
|
-
import { NcpEventType as NcpEventType5 } from "@nextclaw/ncp";
|
|
980
|
-
async function updateAgentBackendToolCallResult(params) {
|
|
981
|
-
const normalizedSessionId = params.sessionId.trim();
|
|
982
|
-
const normalizedToolCallId = params.toolCallId.trim();
|
|
983
|
-
if (!normalizedSessionId || !normalizedToolCallId) {
|
|
984
|
-
return null;
|
|
985
|
-
}
|
|
986
|
-
const liveSession = await params.sessionRegistry.ensureSession(normalizedSessionId);
|
|
987
|
-
const event = {
|
|
988
|
-
type: NcpEventType5.MessageToolCallResult,
|
|
989
|
-
payload: {
|
|
990
|
-
sessionId: normalizedSessionId,
|
|
991
|
-
toolCallId: normalizedToolCallId,
|
|
992
|
-
content: params.content
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
await liveSession.stateManager.dispatch(event);
|
|
996
|
-
params.publisher.publish(event);
|
|
997
|
-
if (liveSession.activeExecution && !liveSession.activeExecution.closed) {
|
|
998
|
-
liveSession.activeExecution.publisher.publish(event);
|
|
999
|
-
}
|
|
1000
|
-
await params.persistSession(normalizedSessionId);
|
|
1001
|
-
return params.getSession(normalizedSessionId);
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
// src/agent/agent-backend/agent-backend-append-message.ts
|
|
1005
|
-
import { NcpEventType as NcpEventType6 } from "@nextclaw/ncp";
|
|
1006
|
-
async function appendAgentBackendMessage(params) {
|
|
1007
|
-
const normalizedSessionId = params.sessionId.trim();
|
|
1008
|
-
if (!normalizedSessionId) {
|
|
1009
|
-
return null;
|
|
1010
|
-
}
|
|
1011
|
-
let liveSession = params.sessionRegistry.getSession(normalizedSessionId);
|
|
1012
|
-
if (!liveSession) {
|
|
1013
|
-
const storedSession = await params.sessionStore.getSession(normalizedSessionId);
|
|
1014
|
-
if (!storedSession) {
|
|
1015
|
-
return null;
|
|
1016
|
-
}
|
|
1017
|
-
liveSession = await params.sessionRegistry.ensureSession(normalizedSessionId);
|
|
1018
|
-
}
|
|
1019
|
-
const nextMessage = {
|
|
1020
|
-
...structuredClone(params.message),
|
|
1021
|
-
sessionId: normalizedSessionId
|
|
1022
|
-
};
|
|
1023
|
-
const event = {
|
|
1024
|
-
type: NcpEventType6.MessageSent,
|
|
1025
|
-
payload: {
|
|
1026
|
-
sessionId: normalizedSessionId,
|
|
1027
|
-
message: nextMessage
|
|
1028
|
-
}
|
|
1029
|
-
};
|
|
1030
|
-
await liveSession.stateManager.dispatch(event);
|
|
1031
|
-
params.publisher.publish(event);
|
|
1032
|
-
if (liveSession.activeExecution && !liveSession.activeExecution.closed) {
|
|
1033
|
-
liveSession.activeExecution.publisher.publish(event);
|
|
1034
|
-
}
|
|
1035
|
-
await params.persistSession(normalizedSessionId);
|
|
1036
|
-
return params.getSession(normalizedSessionId);
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// src/agent/agent-backend/agent-backend-stream.ts
|
|
1040
|
-
import { NcpEventType as NcpEventType7 } from "@nextclaw/ncp";
|
|
1041
|
-
|
|
1042
|
-
// src/agent/agent-backend/async-queue.ts
|
|
1043
|
-
function createAsyncQueue() {
|
|
1044
|
-
const items = [];
|
|
1045
|
-
let closed = false;
|
|
1046
|
-
let pendingResolve = null;
|
|
1047
|
-
const iterable = {
|
|
1048
|
-
[Symbol.asyncIterator]() {
|
|
1049
|
-
return {
|
|
1050
|
-
next: () => {
|
|
1051
|
-
if (items.length > 0) {
|
|
1052
|
-
return Promise.resolve({
|
|
1053
|
-
value: items.shift(),
|
|
1054
|
-
done: false
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
if (closed) {
|
|
1058
|
-
return Promise.resolve({
|
|
1059
|
-
value: void 0,
|
|
1060
|
-
done: true
|
|
1061
|
-
});
|
|
1062
|
-
}
|
|
1063
|
-
return new Promise((resolve) => {
|
|
1064
|
-
pendingResolve = resolve;
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
};
|
|
1070
|
-
return {
|
|
1071
|
-
push(item) {
|
|
1072
|
-
if (closed) {
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
if (pendingResolve) {
|
|
1076
|
-
const resolve = pendingResolve;
|
|
1077
|
-
pendingResolve = null;
|
|
1078
|
-
resolve({ value: item, done: false });
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
items.push(item);
|
|
1082
|
-
},
|
|
1083
|
-
close() {
|
|
1084
|
-
if (closed) {
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
closed = true;
|
|
1088
|
-
if (pendingResolve) {
|
|
1089
|
-
const resolve = pendingResolve;
|
|
1090
|
-
pendingResolve = null;
|
|
1091
|
-
resolve({
|
|
1092
|
-
value: void 0,
|
|
1093
|
-
done: true
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
},
|
|
1097
|
-
iterable
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
// src/agent/agent-backend/agent-backend-stream.ts
|
|
1102
|
-
async function* streamAgentBackendExecution(params) {
|
|
1103
|
-
const payload = "payload" in params.payloadOrParams && "signal" in params.payloadOrParams ? params.payloadOrParams.payload : params.payloadOrParams;
|
|
1104
|
-
const signal = "payload" in params.payloadOrParams && "signal" in params.payloadOrParams ? params.payloadOrParams.signal : params.opts?.signal ?? new AbortController().signal;
|
|
1105
|
-
const session = params.sessionRegistry.getSession(payload.sessionId);
|
|
1106
|
-
const execution = session?.activeExecution;
|
|
1107
|
-
if (!session || !execution || execution.closed) {
|
|
1108
|
-
if (session) {
|
|
1109
|
-
yield {
|
|
1110
|
-
type: NcpEventType7.RunFinished,
|
|
1111
|
-
payload: {
|
|
1112
|
-
sessionId: payload.sessionId
|
|
1113
|
-
}
|
|
1114
|
-
};
|
|
1115
|
-
}
|
|
1116
|
-
return;
|
|
1117
|
-
}
|
|
1118
|
-
const queue = createAsyncQueue();
|
|
1119
|
-
const unsubscribe = execution.publisher.subscribe((event) => {
|
|
1120
|
-
queue.push(event);
|
|
1121
|
-
});
|
|
1122
|
-
const unsubscribeClose = execution.publisher.onClose(() => {
|
|
1123
|
-
queue.close();
|
|
1124
|
-
});
|
|
1125
|
-
const stop = () => {
|
|
1126
|
-
unsubscribe();
|
|
1127
|
-
unsubscribeClose();
|
|
1128
|
-
queue.close();
|
|
1129
|
-
signal.removeEventListener("abort", stop);
|
|
1130
|
-
};
|
|
1131
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
1132
|
-
try {
|
|
1133
|
-
for await (const event of queue.iterable) {
|
|
1134
|
-
if (signal.aborted) {
|
|
1135
|
-
break;
|
|
1136
|
-
}
|
|
1137
|
-
yield event;
|
|
1138
|
-
if (isTerminalEvent(event)) {
|
|
1139
|
-
break;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
} finally {
|
|
1143
|
-
stop();
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
// src/agent/agent-backend/event-publisher.ts
|
|
1148
|
-
var EventPublisher = class {
|
|
1149
|
-
listeners = /* @__PURE__ */ new Set();
|
|
1150
|
-
closeListeners = /* @__PURE__ */ new Set();
|
|
1151
|
-
closed = false;
|
|
1152
|
-
subscribe(listener) {
|
|
1153
|
-
if (this.closed) {
|
|
1154
|
-
return () => void 0;
|
|
1155
|
-
}
|
|
1156
|
-
this.listeners.add(listener);
|
|
1157
|
-
return () => {
|
|
1158
|
-
this.listeners.delete(listener);
|
|
1159
|
-
};
|
|
1160
|
-
}
|
|
1161
|
-
onClose(listener) {
|
|
1162
|
-
if (this.closed) {
|
|
1163
|
-
listener();
|
|
1164
|
-
return () => void 0;
|
|
1165
|
-
}
|
|
1166
|
-
this.closeListeners.add(listener);
|
|
1167
|
-
return () => {
|
|
1168
|
-
this.closeListeners.delete(listener);
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
publish(event) {
|
|
1172
|
-
if (this.closed) {
|
|
1173
|
-
return;
|
|
1174
|
-
}
|
|
1175
|
-
for (const listener of this.listeners) {
|
|
1176
|
-
listener(structuredClone(event));
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
close() {
|
|
1180
|
-
if (this.closed) {
|
|
1181
|
-
return;
|
|
1182
|
-
}
|
|
1183
|
-
this.closed = true;
|
|
1184
|
-
this.listeners.clear();
|
|
1185
|
-
for (const listener of this.closeListeners) {
|
|
1186
|
-
listener();
|
|
1187
|
-
}
|
|
1188
|
-
this.closeListeners.clear();
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
|
|
1192
1218
|
// src/agent/agent-backend/agent-backend.ts
|
|
1193
|
-
var DEFAULT_SUPPORTED_PART_TYPES = [
|
|
1219
|
+
var DEFAULT_SUPPORTED_PART_TYPES = [
|
|
1220
|
+
"text",
|
|
1221
|
+
"file",
|
|
1222
|
+
"source",
|
|
1223
|
+
"step-start",
|
|
1224
|
+
"reasoning",
|
|
1225
|
+
"tool-invocation",
|
|
1226
|
+
"card",
|
|
1227
|
+
"rich-text",
|
|
1228
|
+
"action",
|
|
1229
|
+
"extension"
|
|
1230
|
+
];
|
|
1194
1231
|
var DefaultNcpAgentBackend = class {
|
|
1195
1232
|
manifest;
|
|
1196
1233
|
sessionStore;
|
|
@@ -1198,13 +1235,24 @@ var DefaultNcpAgentBackend = class {
|
|
|
1198
1235
|
sessionRegistry;
|
|
1199
1236
|
executor;
|
|
1200
1237
|
publisher;
|
|
1238
|
+
sessionRealtime;
|
|
1201
1239
|
started = false;
|
|
1202
1240
|
constructor(config) {
|
|
1203
1241
|
this.sessionStore = config.sessionStore;
|
|
1204
1242
|
this.onSessionRunStatusChanged = config.onSessionRunStatusChanged;
|
|
1205
|
-
this.sessionRegistry = new AgentLiveSessionRegistry(
|
|
1206
|
-
|
|
1243
|
+
this.sessionRegistry = new AgentLiveSessionRegistry(
|
|
1244
|
+
this.sessionStore,
|
|
1245
|
+
config.createRuntime
|
|
1246
|
+
);
|
|
1247
|
+
this.executor = new AgentRunExecutor();
|
|
1207
1248
|
this.publisher = new EventPublisher();
|
|
1249
|
+
this.sessionRealtime = new AgentBackendSessionRealtime({
|
|
1250
|
+
sessionRegistry: this.sessionRegistry,
|
|
1251
|
+
sessionStore: this.sessionStore,
|
|
1252
|
+
publishEndpointEvent: (event) => this.publishEndpointEvent(event),
|
|
1253
|
+
persistSession: (sessionId) => this.persistSession(sessionId),
|
|
1254
|
+
getSessionSummary: (sessionId) => this.getSession(sessionId)
|
|
1255
|
+
});
|
|
1208
1256
|
this.manifest = {
|
|
1209
1257
|
endpointKind: "agent",
|
|
1210
1258
|
endpointId: config.endpointId?.trim() || "ncp-agent-backend",
|
|
@@ -1223,7 +1271,7 @@ var DefaultNcpAgentBackend = class {
|
|
|
1223
1271
|
return;
|
|
1224
1272
|
}
|
|
1225
1273
|
this.started = true;
|
|
1226
|
-
this.publisher.publish({ type:
|
|
1274
|
+
this.publisher.publish({ type: NcpEventType6.EndpointReady });
|
|
1227
1275
|
};
|
|
1228
1276
|
stop = async () => {
|
|
1229
1277
|
if (!this.started) {
|
|
@@ -1233,24 +1281,28 @@ var DefaultNcpAgentBackend = class {
|
|
|
1233
1281
|
for (const session of this.sessionRegistry.listSessions()) {
|
|
1234
1282
|
const execution = session.activeExecution;
|
|
1235
1283
|
if (!execution) {
|
|
1284
|
+
session.publisher.close();
|
|
1236
1285
|
continue;
|
|
1237
1286
|
}
|
|
1238
1287
|
execution.abortHandled = true;
|
|
1239
1288
|
execution.controller.abort();
|
|
1240
1289
|
this.finishSessionExecution(session, execution);
|
|
1290
|
+
session.publisher.close();
|
|
1241
1291
|
}
|
|
1242
1292
|
this.sessionRegistry.clear();
|
|
1243
1293
|
};
|
|
1244
1294
|
emit = async (event) => {
|
|
1245
1295
|
await this.ensureStarted();
|
|
1246
1296
|
switch (event.type) {
|
|
1247
|
-
case
|
|
1248
|
-
await this.
|
|
1297
|
+
case NcpEventType6.MessageRequest:
|
|
1298
|
+
for await (const emittedEvent of this.send(event.payload)) {
|
|
1299
|
+
void emittedEvent;
|
|
1300
|
+
}
|
|
1249
1301
|
return;
|
|
1250
|
-
case
|
|
1251
|
-
await this.
|
|
1302
|
+
case NcpEventType6.MessageStreamRequest:
|
|
1303
|
+
await this.ensureStarted();
|
|
1252
1304
|
return;
|
|
1253
|
-
case
|
|
1305
|
+
case NcpEventType6.MessageAbort:
|
|
1254
1306
|
await this.handleAbort(event.payload);
|
|
1255
1307
|
return;
|
|
1256
1308
|
default:
|
|
@@ -1278,13 +1330,20 @@ var DefaultNcpAgentBackend = class {
|
|
|
1278
1330
|
envelope,
|
|
1279
1331
|
execution.controller
|
|
1280
1332
|
)) {
|
|
1281
|
-
self.
|
|
1333
|
+
await self.sessionRealtime.publishSessionEvent(session, event);
|
|
1282
1334
|
yield event;
|
|
1283
1335
|
}
|
|
1284
1336
|
if (execution.controller.signal.aborted && !execution.abortHandled) {
|
|
1285
|
-
const abortEvent =
|
|
1337
|
+
const abortEvent = {
|
|
1338
|
+
type: NcpEventType6.MessageAbort,
|
|
1339
|
+
payload: {
|
|
1340
|
+
sessionId: session.sessionId
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1286
1343
|
execution.abortHandled = true;
|
|
1287
|
-
self.
|
|
1344
|
+
await self.sessionRealtime.publishSessionEvent(session, abortEvent, {
|
|
1345
|
+
dispatchToStateManager: true
|
|
1346
|
+
});
|
|
1288
1347
|
yield abortEvent;
|
|
1289
1348
|
}
|
|
1290
1349
|
} finally {
|
|
@@ -1296,15 +1355,14 @@ var DefaultNcpAgentBackend = class {
|
|
|
1296
1355
|
abort = async (payload) => {
|
|
1297
1356
|
await this.handleAbort(payload);
|
|
1298
1357
|
};
|
|
1299
|
-
stream = (payloadOrParams, opts) =>
|
|
1300
|
-
payloadOrParams,
|
|
1301
|
-
opts,
|
|
1302
|
-
sessionRegistry: this.sessionRegistry
|
|
1303
|
-
});
|
|
1358
|
+
stream = (payloadOrParams, opts) => this.sessionRealtime.streamSessionEvents(payloadOrParams, opts);
|
|
1304
1359
|
listSessions = async () => {
|
|
1305
1360
|
const storedSessions = await this.sessionStore.listSessions();
|
|
1306
1361
|
const summaries = storedSessions.map(
|
|
1307
|
-
(session) => toSessionSummary(
|
|
1362
|
+
(session) => toSessionSummary(
|
|
1363
|
+
session,
|
|
1364
|
+
this.sessionRegistry.getSession(session.sessionId)
|
|
1365
|
+
)
|
|
1308
1366
|
);
|
|
1309
1367
|
for (const liveSession of this.sessionRegistry.listSessions()) {
|
|
1310
1368
|
if (summaries.some((session) => session.sessionId === liveSession.sessionId)) {
|
|
@@ -1312,11 +1370,14 @@ var DefaultNcpAgentBackend = class {
|
|
|
1312
1370
|
}
|
|
1313
1371
|
summaries.push(toLiveSessionSummary(liveSession));
|
|
1314
1372
|
}
|
|
1315
|
-
return summaries.sort(
|
|
1373
|
+
return summaries.sort(
|
|
1374
|
+
(left, right) => right.updatedAt.localeCompare(left.updatedAt)
|
|
1375
|
+
);
|
|
1316
1376
|
};
|
|
1317
1377
|
listSessionMessages = async (sessionId) => {
|
|
1318
1378
|
const liveSession = this.sessionRegistry.getSession(sessionId);
|
|
1319
|
-
if (liveSession)
|
|
1379
|
+
if (liveSession)
|
|
1380
|
+
return readMessages(liveSession.stateManager.getSnapshot());
|
|
1320
1381
|
const session = await this.sessionStore.getSession(sessionId);
|
|
1321
1382
|
return session ? session.messages.map((message) => structuredClone(message)) : [];
|
|
1322
1383
|
};
|
|
@@ -1327,39 +1388,29 @@ var DefaultNcpAgentBackend = class {
|
|
|
1327
1388
|
};
|
|
1328
1389
|
appendMessage = async (sessionId, message) => {
|
|
1329
1390
|
await this.ensureStarted();
|
|
1330
|
-
return
|
|
1331
|
-
sessionId,
|
|
1332
|
-
message,
|
|
1333
|
-
sessionRegistry: this.sessionRegistry,
|
|
1334
|
-
sessionStore: this.sessionStore,
|
|
1335
|
-
publisher: this.publisher,
|
|
1336
|
-
persistSession: async (nextSessionId) => this.persistSession(nextSessionId),
|
|
1337
|
-
getSession: async (nextSessionId) => this.getSession(nextSessionId)
|
|
1338
|
-
});
|
|
1391
|
+
return this.sessionRealtime.appendMessage(sessionId, message);
|
|
1339
1392
|
};
|
|
1340
1393
|
updateToolCallResult = async (sessionId, toolCallId, content) => {
|
|
1341
1394
|
await this.ensureStarted();
|
|
1342
|
-
return
|
|
1395
|
+
return this.sessionRealtime.updateToolCallResult(
|
|
1343
1396
|
sessionId,
|
|
1344
1397
|
toolCallId,
|
|
1345
|
-
content
|
|
1346
|
-
|
|
1347
|
-
publisher: this.publisher,
|
|
1348
|
-
persistSession: async (nextSessionId) => this.persistSession(nextSessionId),
|
|
1349
|
-
getSession: async (nextSessionId) => this.getSession(nextSessionId)
|
|
1350
|
-
});
|
|
1398
|
+
content
|
|
1399
|
+
);
|
|
1351
1400
|
};
|
|
1352
1401
|
updateSession = async (sessionId, patch) => {
|
|
1353
1402
|
const liveSession = this.sessionRegistry.getSession(sessionId);
|
|
1354
1403
|
const storedSession = await this.sessionStore.getSession(sessionId);
|
|
1355
1404
|
if (!liveSession && !storedSession) return null;
|
|
1356
|
-
await this.sessionStore.
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1405
|
+
await this.sessionStore.replaceSession(
|
|
1406
|
+
buildUpdatedSessionRecord({
|
|
1407
|
+
sessionId,
|
|
1408
|
+
patch,
|
|
1409
|
+
liveSession,
|
|
1410
|
+
storedSession,
|
|
1411
|
+
updatedAt: now()
|
|
1412
|
+
})
|
|
1413
|
+
);
|
|
1363
1414
|
return this.getSession(sessionId);
|
|
1364
1415
|
};
|
|
1365
1416
|
deleteSession = async (sessionId) => {
|
|
@@ -1368,8 +1419,9 @@ var DefaultNcpAgentBackend = class {
|
|
|
1368
1419
|
if (execution) {
|
|
1369
1420
|
execution.abortHandled = true;
|
|
1370
1421
|
execution.controller.abort();
|
|
1371
|
-
|
|
1422
|
+
closeAgentBackendSessionExecution(execution);
|
|
1372
1423
|
}
|
|
1424
|
+
liveSession?.publisher.close();
|
|
1373
1425
|
await this.sessionStore.deleteSession(sessionId);
|
|
1374
1426
|
};
|
|
1375
1427
|
ensureStarted = async () => {
|
|
@@ -1377,61 +1429,19 @@ var DefaultNcpAgentBackend = class {
|
|
|
1377
1429
|
await this.start();
|
|
1378
1430
|
}
|
|
1379
1431
|
};
|
|
1380
|
-
startSessionExecution = (session, envelope, signal) => {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
});
|
|
1393
|
-
}
|
|
1394
|
-
const execution = {
|
|
1395
|
-
controller,
|
|
1396
|
-
publisher: new EventPublisher(),
|
|
1397
|
-
requestEnvelope: structuredClone(envelope),
|
|
1398
|
-
abortHandled: false,
|
|
1399
|
-
closed: false
|
|
1400
|
-
};
|
|
1401
|
-
session.activeExecution = execution;
|
|
1402
|
-
this.onSessionRunStatusChanged?.({ sessionKey: session.sessionId, status: "running" });
|
|
1403
|
-
return execution;
|
|
1404
|
-
};
|
|
1405
|
-
finishSessionExecution = (session, execution) => {
|
|
1406
|
-
if (session.activeExecution === execution) {
|
|
1407
|
-
session.activeExecution = null;
|
|
1408
|
-
this.onSessionRunStatusChanged?.({ sessionKey: session.sessionId, status: "idle" });
|
|
1409
|
-
}
|
|
1410
|
-
this.closeExecution(execution);
|
|
1411
|
-
};
|
|
1412
|
-
closeExecution = (execution) => {
|
|
1413
|
-
if (execution.closed) {
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
execution.closed = true;
|
|
1417
|
-
execution.publisher.close();
|
|
1418
|
-
};
|
|
1419
|
-
publishLiveEvent = (execution, event) => {
|
|
1432
|
+
startSessionExecution = (session, envelope, signal) => startAgentBackendSessionExecution({
|
|
1433
|
+
session,
|
|
1434
|
+
envelope,
|
|
1435
|
+
signal,
|
|
1436
|
+
onStatusChanged: this.onSessionRunStatusChanged
|
|
1437
|
+
});
|
|
1438
|
+
finishSessionExecution = (session, execution) => finishAgentBackendSessionExecution({
|
|
1439
|
+
session,
|
|
1440
|
+
execution,
|
|
1441
|
+
onStatusChanged: this.onSessionRunStatusChanged
|
|
1442
|
+
});
|
|
1443
|
+
publishEndpointEvent = (event) => {
|
|
1420
1444
|
this.publisher.publish(event);
|
|
1421
|
-
if (!execution.closed) {
|
|
1422
|
-
execution.publisher.publish(event);
|
|
1423
|
-
}
|
|
1424
|
-
};
|
|
1425
|
-
handleRequest = async (envelope) => {
|
|
1426
|
-
for await (const event of this.send(envelope)) {
|
|
1427
|
-
void event;
|
|
1428
|
-
}
|
|
1429
|
-
};
|
|
1430
|
-
streamToSubscribers = async (payload) => {
|
|
1431
|
-
const signal = new AbortController().signal;
|
|
1432
|
-
for await (const event of this.stream({ payload, signal })) {
|
|
1433
|
-
void event;
|
|
1434
|
-
}
|
|
1435
1445
|
};
|
|
1436
1446
|
handleAbort = async (payload) => {
|
|
1437
1447
|
const session = this.sessionRegistry.getSession(payload.sessionId);
|
|
@@ -1441,57 +1451,55 @@ var DefaultNcpAgentBackend = class {
|
|
|
1441
1451
|
}
|
|
1442
1452
|
execution.abortHandled = true;
|
|
1443
1453
|
execution.controller.abort();
|
|
1444
|
-
const abortEvent = await this.createAbortEvent(payload.sessionId, payload.messageId);
|
|
1445
|
-
this.publishLiveEvent(execution, abortEvent);
|
|
1446
|
-
this.finishSessionExecution(session, execution);
|
|
1447
|
-
};
|
|
1448
|
-
createAbortEvent = async (sessionId, messageId) => {
|
|
1449
1454
|
const abortEvent = {
|
|
1450
|
-
type:
|
|
1455
|
+
type: NcpEventType6.MessageAbort,
|
|
1451
1456
|
payload: {
|
|
1452
|
-
sessionId,
|
|
1453
|
-
...messageId ? { messageId } : {}
|
|
1457
|
+
sessionId: payload.sessionId,
|
|
1458
|
+
...payload.messageId ? { messageId: payload.messageId } : {}
|
|
1454
1459
|
}
|
|
1455
1460
|
};
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
await this.persistSession(sessionId);
|
|
1461
|
-
return abortEvent;
|
|
1461
|
+
await this.sessionRealtime.publishSessionEvent(session, abortEvent, {
|
|
1462
|
+
dispatchToStateManager: true
|
|
1463
|
+
});
|
|
1464
|
+
this.finishSessionExecution(session, execution);
|
|
1462
1465
|
};
|
|
1463
1466
|
persistSession = async (sessionId) => {
|
|
1464
1467
|
const session = this.sessionRegistry.getSession(sessionId);
|
|
1465
1468
|
if (!session) return;
|
|
1466
|
-
await this.sessionStore.saveSession(
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1469
|
+
await this.sessionStore.saveSession(
|
|
1470
|
+
buildPersistedLiveSessionRecord({
|
|
1471
|
+
sessionId,
|
|
1472
|
+
session,
|
|
1473
|
+
updatedAt: now()
|
|
1474
|
+
})
|
|
1475
|
+
);
|
|
1471
1476
|
};
|
|
1472
1477
|
};
|
|
1473
1478
|
|
|
1474
1479
|
// src/agent/agent-backend/in-memory-agent-session-store.ts
|
|
1475
1480
|
var InMemoryAgentSessionStore = class {
|
|
1476
1481
|
sessions = /* @__PURE__ */ new Map();
|
|
1477
|
-
async
|
|
1482
|
+
getSession = async (sessionId) => {
|
|
1478
1483
|
const session = this.sessions.get(sessionId);
|
|
1479
1484
|
return session ? structuredClone(session) : null;
|
|
1480
|
-
}
|
|
1481
|
-
async
|
|
1485
|
+
};
|
|
1486
|
+
listSessions = async () => {
|
|
1482
1487
|
return [...this.sessions.values()].map((session) => structuredClone(session));
|
|
1483
|
-
}
|
|
1484
|
-
async
|
|
1488
|
+
};
|
|
1489
|
+
saveSession = async (session) => {
|
|
1485
1490
|
this.sessions.set(session.sessionId, structuredClone(session));
|
|
1486
|
-
}
|
|
1487
|
-
async
|
|
1491
|
+
};
|
|
1492
|
+
replaceSession = async (session) => {
|
|
1493
|
+
this.sessions.set(session.sessionId, structuredClone(session));
|
|
1494
|
+
};
|
|
1495
|
+
deleteSession = async (sessionId) => {
|
|
1488
1496
|
const session = this.sessions.get(sessionId);
|
|
1489
1497
|
if (!session) {
|
|
1490
1498
|
return null;
|
|
1491
1499
|
}
|
|
1492
1500
|
this.sessions.delete(sessionId);
|
|
1493
1501
|
return structuredClone(session);
|
|
1494
|
-
}
|
|
1502
|
+
};
|
|
1495
1503
|
};
|
|
1496
1504
|
export {
|
|
1497
1505
|
AgentRunExecutor,
|