happy-imou-cloud 2.0.9 → 2.0.11
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/BaseReasoningProcessor-5ACv9gKu.mjs +320 -0
- package/dist/BaseReasoningProcessor-COrRWyn0.cjs +323 -0
- package/dist/ProviderSelectionHandler-BljOLMQn.mjs +261 -0
- package/dist/ProviderSelectionHandler-DBGobhGZ.cjs +265 -0
- package/dist/{api-CnvyGas2.mjs → api-BcWf5v4i.mjs} +174 -46
- package/dist/{api-CUTdFiFP.cjs → api-Ye-rPX6s.cjs} +215 -87
- package/dist/{command-DLAJZsKX.cjs → command-BK93nizl.cjs} +6 -6
- package/dist/{command-BGA3qCKR.mjs → command-nOI80Mnm.mjs} +6 -6
- package/dist/{index-BpZL4RcT.mjs → index-DnsqY6I_.mjs} +871 -148
- package/dist/{index-D4OdFq68.cjs → index-J7QKJ8lc.cjs} +955 -228
- package/dist/index.cjs +8 -8
- package/dist/index.mjs +8 -8
- package/dist/lib.cjs +2 -3
- package/dist/lib.d.cts +2 -0
- package/dist/lib.d.mts +2 -0
- package/dist/lib.mjs +2 -3
- package/dist/{persistence-BPV3AmJL.mjs → persistence-BMa6cyw9.mjs} +2 -3
- package/dist/{persistence-CxvL0cwp.cjs → persistence-xK5CKhbn.cjs} +30 -31
- package/dist/registerKillSessionHandler-CH6yN0eG.cjs +1198 -0
- package/dist/registerKillSessionHandler-Dxwg4L4J.mjs +1179 -0
- package/dist/{runClaude-KwIVwFp1.cjs → runClaude-BMHlBny_.cjs} +904 -427
- package/dist/{runClaude-8inO7C5p.mjs → runClaude-cQ-UT0Ke.mjs} +883 -406
- package/dist/{runCodex-BQ-fN5E6.mjs → runCodex-AnJUPIhX.mjs} +160 -584
- package/dist/{runCodex-Ba8COxZe.cjs → runCodex-roOSOWWL.cjs} +163 -589
- package/dist/{runGemini-BE0FizuV.mjs → runGemini-BGo_0mzA.mjs} +142 -396
- package/dist/{runGemini-DtdLLX9o.cjs → runGemini-Cg6Zbqlz.cjs} +145 -399
- package/package.json +9 -8
- package/scripts/e2e/fake-codex-acp-agent.mjs +139 -0
- package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -0
- package/scripts/release-smoke.mjs +23 -6
- package/dist/names-C9iJODqA.mjs +0 -625
- package/dist/names-YEhZwVT0.cjs +0 -636
- package/dist/registerKillSessionHandler-C2O8b5wH.mjs +0 -454
- package/dist/registerKillSessionHandler-rqd7duc9.cjs +0 -459
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { p as publishSessionRegistration } from './index-DnsqY6I_.mjs';
|
|
2
|
+
import { s as startOfflineReconnection, c as configuration, i as isAuthenticationRequiredError, l as logger } from './api-BcWf5v4i.mjs';
|
|
3
|
+
import { c as createSessionMetadata } from './registerKillSessionHandler-Dxwg4L4J.mjs';
|
|
4
|
+
import { EventEmitter } from 'node:events';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
|
|
7
|
+
function createOfflineSessionStub(sessionTag) {
|
|
8
|
+
const emitter = new EventEmitter();
|
|
9
|
+
let metadata = null;
|
|
10
|
+
let agentState = null;
|
|
11
|
+
const stub = {
|
|
12
|
+
sessionId: `offline-${sessionTag}`,
|
|
13
|
+
sendCodexMessage: () => {
|
|
14
|
+
},
|
|
15
|
+
sendAgentMessage: () => {
|
|
16
|
+
},
|
|
17
|
+
sendClaudeSessionMessage: () => {
|
|
18
|
+
},
|
|
19
|
+
keepAlive: () => {
|
|
20
|
+
},
|
|
21
|
+
sendSessionEvent: () => {
|
|
22
|
+
},
|
|
23
|
+
sendSessionDeath: () => {
|
|
24
|
+
},
|
|
25
|
+
updateLifecycleState: () => {
|
|
26
|
+
},
|
|
27
|
+
requestControlTransfer: async () => {
|
|
28
|
+
},
|
|
29
|
+
flush: async () => {
|
|
30
|
+
},
|
|
31
|
+
close: async () => {
|
|
32
|
+
},
|
|
33
|
+
updateMetadata: (handler) => {
|
|
34
|
+
metadata = handler(metadata || {});
|
|
35
|
+
emitter.emit("metadata-updated", metadata);
|
|
36
|
+
},
|
|
37
|
+
updateAgentState: (handler) => {
|
|
38
|
+
agentState = handler(agentState || {});
|
|
39
|
+
emitter.emit("agent-state-updated", agentState);
|
|
40
|
+
},
|
|
41
|
+
getMetadataSnapshot: () => metadata,
|
|
42
|
+
getAgentStateSnapshot: () => agentState,
|
|
43
|
+
waitForMetadataUpdate: async () => metadata,
|
|
44
|
+
onUserMessage: () => {
|
|
45
|
+
},
|
|
46
|
+
rpcHandlerManager: {
|
|
47
|
+
registerHandler: () => {
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
on: emitter.on.bind(emitter),
|
|
51
|
+
once: emitter.once.bind(emitter),
|
|
52
|
+
off: emitter.off.bind(emitter),
|
|
53
|
+
emit: emitter.emit.bind(emitter)
|
|
54
|
+
};
|
|
55
|
+
return stub;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function setupOfflineReconnection(opts) {
|
|
59
|
+
const { api, sessionTag, metadata, state, response, onSessionSwap } = opts;
|
|
60
|
+
let session;
|
|
61
|
+
let reconnectionHandle = null;
|
|
62
|
+
if (!response) {
|
|
63
|
+
session = createOfflineSessionStub(sessionTag);
|
|
64
|
+
reconnectionHandle = startOfflineReconnection({
|
|
65
|
+
serverUrl: configuration.serverUrl,
|
|
66
|
+
onReconnected: async () => {
|
|
67
|
+
const resp = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
68
|
+
if (!resp) throw new Error("Server unavailable");
|
|
69
|
+
const realSession = api.sessionSyncClient(resp);
|
|
70
|
+
onSessionSwap(realSession);
|
|
71
|
+
return realSession;
|
|
72
|
+
},
|
|
73
|
+
onNotify: (msg) => {
|
|
74
|
+
console.log(msg);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return { session, reconnectionHandle, isOffline: true };
|
|
78
|
+
} else {
|
|
79
|
+
session = api.sessionSyncClient(response);
|
|
80
|
+
return { session, reconnectionHandle: null, isOffline: false };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function bootstrapManagedProviderSession(opts) {
|
|
85
|
+
const { state, metadata } = createSessionMetadata({
|
|
86
|
+
flavor: opts.flavor,
|
|
87
|
+
machineId: opts.machineId,
|
|
88
|
+
startedBy: opts.startedBy
|
|
89
|
+
});
|
|
90
|
+
let response = null;
|
|
91
|
+
try {
|
|
92
|
+
response = await opts.api.getOrCreateSession({
|
|
93
|
+
tag: opts.sessionTag,
|
|
94
|
+
metadata,
|
|
95
|
+
state
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (!isAuthenticationRequiredError(error)) {
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
logger.debug(opts.authFallbackLogMessage);
|
|
102
|
+
}
|
|
103
|
+
const { session, reconnectionHandle } = setupOfflineReconnection({
|
|
104
|
+
api: opts.api,
|
|
105
|
+
sessionTag: opts.sessionTag,
|
|
106
|
+
metadata,
|
|
107
|
+
state,
|
|
108
|
+
response,
|
|
109
|
+
onSessionSwap: (newSession) => {
|
|
110
|
+
opts.onSessionSwap?.(newSession, metadata);
|
|
111
|
+
void publishSessionRegistration(newSession.sessionId, metadata);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
if (response) {
|
|
115
|
+
await publishSessionRegistration(response.id, metadata);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
state,
|
|
119
|
+
metadata,
|
|
120
|
+
response,
|
|
121
|
+
session,
|
|
122
|
+
reconnectionHandle
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class BaseReasoningProcessor {
|
|
127
|
+
accumulator = "";
|
|
128
|
+
inTitleCapture = false;
|
|
129
|
+
titleBuffer = "";
|
|
130
|
+
contentBuffer = "";
|
|
131
|
+
hasTitle = false;
|
|
132
|
+
currentCallId = null;
|
|
133
|
+
toolCallStarted = false;
|
|
134
|
+
currentTitle = null;
|
|
135
|
+
onMessage = null;
|
|
136
|
+
constructor(onMessage) {
|
|
137
|
+
this.onMessage = onMessage || null;
|
|
138
|
+
this.reset();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Set the message callback for sending messages directly.
|
|
142
|
+
*/
|
|
143
|
+
setMessageCallback(callback) {
|
|
144
|
+
this.onMessage = callback;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Process a reasoning section break - indicates a new reasoning section is starting.
|
|
148
|
+
*/
|
|
149
|
+
handleSectionBreak() {
|
|
150
|
+
this.finishCurrentToolCall("canceled");
|
|
151
|
+
this.resetState();
|
|
152
|
+
logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Process a reasoning delta/chunk and accumulate content.
|
|
156
|
+
*/
|
|
157
|
+
processInput(input) {
|
|
158
|
+
this.accumulator += input;
|
|
159
|
+
if (!this.inTitleCapture && !this.hasTitle && !this.contentBuffer) {
|
|
160
|
+
if (this.accumulator.startsWith("**")) {
|
|
161
|
+
this.inTitleCapture = true;
|
|
162
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
163
|
+
logger.debug(`${this.getLogPrefix()} Started title capture`);
|
|
164
|
+
} else if (this.accumulator.length > 0) {
|
|
165
|
+
this.contentBuffer = this.accumulator;
|
|
166
|
+
}
|
|
167
|
+
} else if (this.inTitleCapture) {
|
|
168
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
169
|
+
const titleEndIndex = this.titleBuffer.indexOf("**");
|
|
170
|
+
if (titleEndIndex !== -1) {
|
|
171
|
+
const title = this.titleBuffer.substring(0, titleEndIndex);
|
|
172
|
+
const afterTitle = this.titleBuffer.substring(titleEndIndex + 2);
|
|
173
|
+
this.hasTitle = true;
|
|
174
|
+
this.inTitleCapture = false;
|
|
175
|
+
this.currentTitle = title;
|
|
176
|
+
this.contentBuffer = afterTitle;
|
|
177
|
+
this.currentCallId = randomUUID();
|
|
178
|
+
logger.debug(`${this.getLogPrefix()} Title captured: "${title}"`);
|
|
179
|
+
this.sendToolCallStart(title);
|
|
180
|
+
}
|
|
181
|
+
} else if (this.hasTitle) {
|
|
182
|
+
const titleStartIndex = this.accumulator.indexOf("**");
|
|
183
|
+
if (titleStartIndex !== -1) {
|
|
184
|
+
this.contentBuffer = this.accumulator.substring(
|
|
185
|
+
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
this.contentBuffer = this.accumulator;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Send the tool call start message.
|
|
194
|
+
*/
|
|
195
|
+
sendToolCallStart(title) {
|
|
196
|
+
if (!this.currentCallId || this.toolCallStarted) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const toolCall = {
|
|
200
|
+
type: "tool-call",
|
|
201
|
+
name: this.getToolName(),
|
|
202
|
+
callId: this.currentCallId,
|
|
203
|
+
input: {
|
|
204
|
+
title
|
|
205
|
+
},
|
|
206
|
+
id: randomUUID()
|
|
207
|
+
};
|
|
208
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call start for: "${title}"`);
|
|
209
|
+
this.onMessage?.(toolCall);
|
|
210
|
+
this.toolCallStarted = true;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Complete the reasoning section.
|
|
214
|
+
* Returns true if reasoning was completed, false if there was nothing to complete.
|
|
215
|
+
*/
|
|
216
|
+
completeReasoning(fullText) {
|
|
217
|
+
const text = fullText ?? this.accumulator;
|
|
218
|
+
if (!text.trim() && !this.toolCallStarted) {
|
|
219
|
+
logger.debug(`${this.getLogPrefix()} Complete called but no content accumulated, skipping`);
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
let title;
|
|
223
|
+
let content = text;
|
|
224
|
+
if (text.startsWith("**")) {
|
|
225
|
+
const titleEndIndex = text.indexOf("**", 2);
|
|
226
|
+
if (titleEndIndex !== -1) {
|
|
227
|
+
title = text.substring(2, titleEndIndex);
|
|
228
|
+
content = text.substring(titleEndIndex + 2).trim();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
logger.debug(`${this.getLogPrefix()} Complete reasoning - Title: "${title}", Has content: ${content.length > 0}`);
|
|
232
|
+
if (title && !this.toolCallStarted) {
|
|
233
|
+
this.currentCallId = this.currentCallId || randomUUID();
|
|
234
|
+
this.sendToolCallStart(title);
|
|
235
|
+
}
|
|
236
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
237
|
+
const toolResult = {
|
|
238
|
+
type: "tool-call-result",
|
|
239
|
+
callId: this.currentCallId,
|
|
240
|
+
output: {
|
|
241
|
+
content,
|
|
242
|
+
status: "completed"
|
|
243
|
+
},
|
|
244
|
+
id: randomUUID()
|
|
245
|
+
};
|
|
246
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
247
|
+
this.onMessage?.(toolResult);
|
|
248
|
+
} else if (content.trim()) {
|
|
249
|
+
const reasoningMessage = {
|
|
250
|
+
type: "reasoning",
|
|
251
|
+
message: content,
|
|
252
|
+
id: randomUUID()
|
|
253
|
+
};
|
|
254
|
+
logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
255
|
+
this.onMessage?.(reasoningMessage);
|
|
256
|
+
}
|
|
257
|
+
this.resetState();
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Abort the current reasoning section.
|
|
262
|
+
*/
|
|
263
|
+
abort() {
|
|
264
|
+
logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
265
|
+
this.finishCurrentToolCall("canceled");
|
|
266
|
+
this.resetState();
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Reset the processor state.
|
|
270
|
+
*/
|
|
271
|
+
reset() {
|
|
272
|
+
this.finishCurrentToolCall("canceled");
|
|
273
|
+
this.resetState();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Finish current tool call if one is in progress.
|
|
277
|
+
*/
|
|
278
|
+
finishCurrentToolCall(status) {
|
|
279
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
280
|
+
const toolResult = {
|
|
281
|
+
type: "tool-call-result",
|
|
282
|
+
callId: this.currentCallId,
|
|
283
|
+
output: {
|
|
284
|
+
content: this.contentBuffer || "",
|
|
285
|
+
status
|
|
286
|
+
},
|
|
287
|
+
id: randomUUID()
|
|
288
|
+
};
|
|
289
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
290
|
+
this.onMessage?.(toolResult);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Reset internal state.
|
|
295
|
+
*/
|
|
296
|
+
resetState() {
|
|
297
|
+
this.accumulator = "";
|
|
298
|
+
this.inTitleCapture = false;
|
|
299
|
+
this.titleBuffer = "";
|
|
300
|
+
this.contentBuffer = "";
|
|
301
|
+
this.hasTitle = false;
|
|
302
|
+
this.currentCallId = null;
|
|
303
|
+
this.toolCallStarted = false;
|
|
304
|
+
this.currentTitle = null;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get the current call ID for tool result matching.
|
|
308
|
+
*/
|
|
309
|
+
getCurrentCallId() {
|
|
310
|
+
return this.currentCallId;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Check if a tool call has been started.
|
|
314
|
+
*/
|
|
315
|
+
hasStartedToolCall() {
|
|
316
|
+
return this.toolCallStarted;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export { BaseReasoningProcessor as B, bootstrapManagedProviderSession as b };
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-J7QKJ8lc.cjs');
|
|
4
|
+
var api = require('./api-Ye-rPX6s.cjs');
|
|
5
|
+
var registerKillSessionHandler = require('./registerKillSessionHandler-CH6yN0eG.cjs');
|
|
6
|
+
var node_events = require('node:events');
|
|
7
|
+
var node_crypto = require('node:crypto');
|
|
8
|
+
|
|
9
|
+
function createOfflineSessionStub(sessionTag) {
|
|
10
|
+
const emitter = new node_events.EventEmitter();
|
|
11
|
+
let metadata = null;
|
|
12
|
+
let agentState = null;
|
|
13
|
+
const stub = {
|
|
14
|
+
sessionId: `offline-${sessionTag}`,
|
|
15
|
+
sendCodexMessage: () => {
|
|
16
|
+
},
|
|
17
|
+
sendAgentMessage: () => {
|
|
18
|
+
},
|
|
19
|
+
sendClaudeSessionMessage: () => {
|
|
20
|
+
},
|
|
21
|
+
keepAlive: () => {
|
|
22
|
+
},
|
|
23
|
+
sendSessionEvent: () => {
|
|
24
|
+
},
|
|
25
|
+
sendSessionDeath: () => {
|
|
26
|
+
},
|
|
27
|
+
updateLifecycleState: () => {
|
|
28
|
+
},
|
|
29
|
+
requestControlTransfer: async () => {
|
|
30
|
+
},
|
|
31
|
+
flush: async () => {
|
|
32
|
+
},
|
|
33
|
+
close: async () => {
|
|
34
|
+
},
|
|
35
|
+
updateMetadata: (handler) => {
|
|
36
|
+
metadata = handler(metadata || {});
|
|
37
|
+
emitter.emit("metadata-updated", metadata);
|
|
38
|
+
},
|
|
39
|
+
updateAgentState: (handler) => {
|
|
40
|
+
agentState = handler(agentState || {});
|
|
41
|
+
emitter.emit("agent-state-updated", agentState);
|
|
42
|
+
},
|
|
43
|
+
getMetadataSnapshot: () => metadata,
|
|
44
|
+
getAgentStateSnapshot: () => agentState,
|
|
45
|
+
waitForMetadataUpdate: async () => metadata,
|
|
46
|
+
onUserMessage: () => {
|
|
47
|
+
},
|
|
48
|
+
rpcHandlerManager: {
|
|
49
|
+
registerHandler: () => {
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
on: emitter.on.bind(emitter),
|
|
53
|
+
once: emitter.once.bind(emitter),
|
|
54
|
+
off: emitter.off.bind(emitter),
|
|
55
|
+
emit: emitter.emit.bind(emitter)
|
|
56
|
+
};
|
|
57
|
+
return stub;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function setupOfflineReconnection(opts) {
|
|
61
|
+
const { api: api$1, sessionTag, metadata, state, response, onSessionSwap } = opts;
|
|
62
|
+
let session;
|
|
63
|
+
let reconnectionHandle = null;
|
|
64
|
+
if (!response) {
|
|
65
|
+
session = createOfflineSessionStub(sessionTag);
|
|
66
|
+
reconnectionHandle = api.startOfflineReconnection({
|
|
67
|
+
serverUrl: api.configuration.serverUrl,
|
|
68
|
+
onReconnected: async () => {
|
|
69
|
+
const resp = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
70
|
+
if (!resp) throw new Error("Server unavailable");
|
|
71
|
+
const realSession = api$1.sessionSyncClient(resp);
|
|
72
|
+
onSessionSwap(realSession);
|
|
73
|
+
return realSession;
|
|
74
|
+
},
|
|
75
|
+
onNotify: (msg) => {
|
|
76
|
+
console.log(msg);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return { session, reconnectionHandle, isOffline: true };
|
|
80
|
+
} else {
|
|
81
|
+
session = api$1.sessionSyncClient(response);
|
|
82
|
+
return { session, reconnectionHandle: null, isOffline: false };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function bootstrapManagedProviderSession(opts) {
|
|
87
|
+
const { state, metadata } = registerKillSessionHandler.createSessionMetadata({
|
|
88
|
+
flavor: opts.flavor,
|
|
89
|
+
machineId: opts.machineId,
|
|
90
|
+
startedBy: opts.startedBy
|
|
91
|
+
});
|
|
92
|
+
let response = null;
|
|
93
|
+
try {
|
|
94
|
+
response = await opts.api.getOrCreateSession({
|
|
95
|
+
tag: opts.sessionTag,
|
|
96
|
+
metadata,
|
|
97
|
+
state
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (!api.isAuthenticationRequiredError(error)) {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
api.logger.debug(opts.authFallbackLogMessage);
|
|
104
|
+
}
|
|
105
|
+
const { session, reconnectionHandle } = setupOfflineReconnection({
|
|
106
|
+
api: opts.api,
|
|
107
|
+
sessionTag: opts.sessionTag,
|
|
108
|
+
metadata,
|
|
109
|
+
state,
|
|
110
|
+
response,
|
|
111
|
+
onSessionSwap: (newSession) => {
|
|
112
|
+
opts.onSessionSwap?.(newSession, metadata);
|
|
113
|
+
void index.publishSessionRegistration(newSession.sessionId, metadata);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
if (response) {
|
|
117
|
+
await index.publishSessionRegistration(response.id, metadata);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
state,
|
|
121
|
+
metadata,
|
|
122
|
+
response,
|
|
123
|
+
session,
|
|
124
|
+
reconnectionHandle
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class BaseReasoningProcessor {
|
|
129
|
+
accumulator = "";
|
|
130
|
+
inTitleCapture = false;
|
|
131
|
+
titleBuffer = "";
|
|
132
|
+
contentBuffer = "";
|
|
133
|
+
hasTitle = false;
|
|
134
|
+
currentCallId = null;
|
|
135
|
+
toolCallStarted = false;
|
|
136
|
+
currentTitle = null;
|
|
137
|
+
onMessage = null;
|
|
138
|
+
constructor(onMessage) {
|
|
139
|
+
this.onMessage = onMessage || null;
|
|
140
|
+
this.reset();
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set the message callback for sending messages directly.
|
|
144
|
+
*/
|
|
145
|
+
setMessageCallback(callback) {
|
|
146
|
+
this.onMessage = callback;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Process a reasoning section break - indicates a new reasoning section is starting.
|
|
150
|
+
*/
|
|
151
|
+
handleSectionBreak() {
|
|
152
|
+
this.finishCurrentToolCall("canceled");
|
|
153
|
+
this.resetState();
|
|
154
|
+
api.logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Process a reasoning delta/chunk and accumulate content.
|
|
158
|
+
*/
|
|
159
|
+
processInput(input) {
|
|
160
|
+
this.accumulator += input;
|
|
161
|
+
if (!this.inTitleCapture && !this.hasTitle && !this.contentBuffer) {
|
|
162
|
+
if (this.accumulator.startsWith("**")) {
|
|
163
|
+
this.inTitleCapture = true;
|
|
164
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
165
|
+
api.logger.debug(`${this.getLogPrefix()} Started title capture`);
|
|
166
|
+
} else if (this.accumulator.length > 0) {
|
|
167
|
+
this.contentBuffer = this.accumulator;
|
|
168
|
+
}
|
|
169
|
+
} else if (this.inTitleCapture) {
|
|
170
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
171
|
+
const titleEndIndex = this.titleBuffer.indexOf("**");
|
|
172
|
+
if (titleEndIndex !== -1) {
|
|
173
|
+
const title = this.titleBuffer.substring(0, titleEndIndex);
|
|
174
|
+
const afterTitle = this.titleBuffer.substring(titleEndIndex + 2);
|
|
175
|
+
this.hasTitle = true;
|
|
176
|
+
this.inTitleCapture = false;
|
|
177
|
+
this.currentTitle = title;
|
|
178
|
+
this.contentBuffer = afterTitle;
|
|
179
|
+
this.currentCallId = node_crypto.randomUUID();
|
|
180
|
+
api.logger.debug(`${this.getLogPrefix()} Title captured: "${title}"`);
|
|
181
|
+
this.sendToolCallStart(title);
|
|
182
|
+
}
|
|
183
|
+
} else if (this.hasTitle) {
|
|
184
|
+
const titleStartIndex = this.accumulator.indexOf("**");
|
|
185
|
+
if (titleStartIndex !== -1) {
|
|
186
|
+
this.contentBuffer = this.accumulator.substring(
|
|
187
|
+
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
this.contentBuffer = this.accumulator;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Send the tool call start message.
|
|
196
|
+
*/
|
|
197
|
+
sendToolCallStart(title) {
|
|
198
|
+
if (!this.currentCallId || this.toolCallStarted) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const toolCall = {
|
|
202
|
+
type: "tool-call",
|
|
203
|
+
name: this.getToolName(),
|
|
204
|
+
callId: this.currentCallId,
|
|
205
|
+
input: {
|
|
206
|
+
title
|
|
207
|
+
},
|
|
208
|
+
id: node_crypto.randomUUID()
|
|
209
|
+
};
|
|
210
|
+
api.logger.debug(`${this.getLogPrefix()} Sending tool call start for: "${title}"`);
|
|
211
|
+
this.onMessage?.(toolCall);
|
|
212
|
+
this.toolCallStarted = true;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Complete the reasoning section.
|
|
216
|
+
* Returns true if reasoning was completed, false if there was nothing to complete.
|
|
217
|
+
*/
|
|
218
|
+
completeReasoning(fullText) {
|
|
219
|
+
const text = fullText ?? this.accumulator;
|
|
220
|
+
if (!text.trim() && !this.toolCallStarted) {
|
|
221
|
+
api.logger.debug(`${this.getLogPrefix()} Complete called but no content accumulated, skipping`);
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
let title;
|
|
225
|
+
let content = text;
|
|
226
|
+
if (text.startsWith("**")) {
|
|
227
|
+
const titleEndIndex = text.indexOf("**", 2);
|
|
228
|
+
if (titleEndIndex !== -1) {
|
|
229
|
+
title = text.substring(2, titleEndIndex);
|
|
230
|
+
content = text.substring(titleEndIndex + 2).trim();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
api.logger.debug(`${this.getLogPrefix()} Complete reasoning - Title: "${title}", Has content: ${content.length > 0}`);
|
|
234
|
+
if (title && !this.toolCallStarted) {
|
|
235
|
+
this.currentCallId = this.currentCallId || node_crypto.randomUUID();
|
|
236
|
+
this.sendToolCallStart(title);
|
|
237
|
+
}
|
|
238
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
239
|
+
const toolResult = {
|
|
240
|
+
type: "tool-call-result",
|
|
241
|
+
callId: this.currentCallId,
|
|
242
|
+
output: {
|
|
243
|
+
content,
|
|
244
|
+
status: "completed"
|
|
245
|
+
},
|
|
246
|
+
id: node_crypto.randomUUID()
|
|
247
|
+
};
|
|
248
|
+
api.logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
249
|
+
this.onMessage?.(toolResult);
|
|
250
|
+
} else if (content.trim()) {
|
|
251
|
+
const reasoningMessage = {
|
|
252
|
+
type: "reasoning",
|
|
253
|
+
message: content,
|
|
254
|
+
id: node_crypto.randomUUID()
|
|
255
|
+
};
|
|
256
|
+
api.logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
257
|
+
this.onMessage?.(reasoningMessage);
|
|
258
|
+
}
|
|
259
|
+
this.resetState();
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Abort the current reasoning section.
|
|
264
|
+
*/
|
|
265
|
+
abort() {
|
|
266
|
+
api.logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
267
|
+
this.finishCurrentToolCall("canceled");
|
|
268
|
+
this.resetState();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Reset the processor state.
|
|
272
|
+
*/
|
|
273
|
+
reset() {
|
|
274
|
+
this.finishCurrentToolCall("canceled");
|
|
275
|
+
this.resetState();
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Finish current tool call if one is in progress.
|
|
279
|
+
*/
|
|
280
|
+
finishCurrentToolCall(status) {
|
|
281
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
282
|
+
const toolResult = {
|
|
283
|
+
type: "tool-call-result",
|
|
284
|
+
callId: this.currentCallId,
|
|
285
|
+
output: {
|
|
286
|
+
content: this.contentBuffer || "",
|
|
287
|
+
status
|
|
288
|
+
},
|
|
289
|
+
id: node_crypto.randomUUID()
|
|
290
|
+
};
|
|
291
|
+
api.logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
292
|
+
this.onMessage?.(toolResult);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Reset internal state.
|
|
297
|
+
*/
|
|
298
|
+
resetState() {
|
|
299
|
+
this.accumulator = "";
|
|
300
|
+
this.inTitleCapture = false;
|
|
301
|
+
this.titleBuffer = "";
|
|
302
|
+
this.contentBuffer = "";
|
|
303
|
+
this.hasTitle = false;
|
|
304
|
+
this.currentCallId = null;
|
|
305
|
+
this.toolCallStarted = false;
|
|
306
|
+
this.currentTitle = null;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get the current call ID for tool result matching.
|
|
310
|
+
*/
|
|
311
|
+
getCurrentCallId() {
|
|
312
|
+
return this.currentCallId;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Check if a tool call has been started.
|
|
316
|
+
*/
|
|
317
|
+
hasStartedToolCall() {
|
|
318
|
+
return this.toolCallStarted;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
exports.BaseReasoningProcessor = BaseReasoningProcessor;
|
|
323
|
+
exports.bootstrapManagedProviderSession = bootstrapManagedProviderSession;
|