shennian 0.2.86 → 0.2.88
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/src/agents/adapter.d.ts +2 -1
- package/dist/src/agents/codex-utils.d.ts +5 -0
- package/dist/src/agents/codex-utils.js +5 -0
- package/dist/src/agents/codex.js +2 -2
- package/dist/src/agents/model-registry/discovery.js +2 -1
- package/dist/src/channels/base.d.ts +1 -13
- package/dist/src/channels/runtime.d.ts +0 -3
- package/dist/src/channels/runtime.js +1 -5
- package/dist/src/channels/secret-registry.d.ts +0 -4
- package/dist/src/channels/wechat-rpa/macos-flow.d.ts +0 -28
- package/dist/src/channels/wechat-rpa/macos-flow.js +1 -134
- package/dist/src/channels/wechat-rpa.js +27 -55
- package/dist/src/commands/daemon.js +1 -0
- package/dist/src/commands/manager.d.ts +1 -1
- package/dist/src/commands/manager.js +3 -10
- package/dist/src/index.js +2 -1
- package/dist/src/manager/runtime.js +0 -6
- package/dist/src/native-fusion/config.d.ts +1 -0
- package/dist/src/native-fusion/config.js +5 -0
- package/dist/src/session/handlers/chat.js +67 -4
- package/dist/src/session/manager.js +8 -0
- package/dist/src/session/types.d.ts +4 -1
- package/package.json +1 -1
- package/dist/scripts/wechat-rpa-win-visual.mjs +0 -1735
- package/dist/scripts/wechat-rpa-win.mjs +0 -352
- package/dist/src/channels/wechat-rpa/windows-visual-flow.d.ts +0 -40
- package/dist/src/channels/wechat-rpa/windows-visual-flow.js +0 -189
|
@@ -49,6 +49,18 @@ function buildRelayAgentPayload(event, sessionId, extra = {}) {
|
|
|
49
49
|
}
|
|
50
50
|
return { ...event, sessionId, ...extra };
|
|
51
51
|
}
|
|
52
|
+
const SESSION_ACTIVITY_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
53
|
+
function runPhaseFromAgentEvent(event) {
|
|
54
|
+
if (event.state === 'heartbeat')
|
|
55
|
+
return event.runPhase ?? null;
|
|
56
|
+
if (event.state === 'tool-call' || event.state === 'tool-result')
|
|
57
|
+
return 'tool_running';
|
|
58
|
+
if (event.state === 'delta')
|
|
59
|
+
return event.thinking ? 'thinking' : 'streaming_text';
|
|
60
|
+
if (event.state === 'init' || event.state === 'start')
|
|
61
|
+
return 'thinking';
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
52
64
|
function formatAgentSendFailure(agentType, err) {
|
|
53
65
|
const raw = err instanceof Error ? err.message : String(err);
|
|
54
66
|
if (agentType === 'pi' &&
|
|
@@ -132,8 +144,6 @@ function normalizeExternalChannel(value) {
|
|
|
132
144
|
noRestore: raw.noRestore === undefined || raw.noRestore === null ? null : Boolean(raw.noRestore),
|
|
133
145
|
downloadAttachments: raw.downloadAttachments === undefined || raw.downloadAttachments === null ? null : Boolean(raw.downloadAttachments),
|
|
134
146
|
downloadAttachmentsDir: typeof raw.downloadAttachmentsDir === 'string' ? raw.downloadAttachmentsDir : null,
|
|
135
|
-
cloudOcrUrl: typeof raw.cloudOcrUrl === 'string' ? raw.cloudOcrUrl : null,
|
|
136
|
-
cloudOcrMode: typeof raw.cloudOcrMode === 'string' ? raw.cloudOcrMode : null,
|
|
137
147
|
};
|
|
138
148
|
}
|
|
139
149
|
function externalChannelEnabled(channel) {
|
|
@@ -194,6 +204,38 @@ function bindAdapterEvents(runtime, sessionId, agentType, adapter) {
|
|
|
194
204
|
id: `agent-evt-${event.runId}-${event.seq}`,
|
|
195
205
|
});
|
|
196
206
|
}
|
|
207
|
+
function stopActivityHeartbeat(activeSession) {
|
|
208
|
+
if (!activeSession?.heartbeatTimer)
|
|
209
|
+
return;
|
|
210
|
+
clearInterval(activeSession.heartbeatTimer);
|
|
211
|
+
activeSession.heartbeatTimer = null;
|
|
212
|
+
}
|
|
213
|
+
function sendActivityHeartbeat(activeSession) {
|
|
214
|
+
if (!activeSession.currentRunId || !activeSession.currentRunPhase)
|
|
215
|
+
return;
|
|
216
|
+
const seq = activeSession.heartbeatSeq++;
|
|
217
|
+
runtime.client.sendAgentEvent({
|
|
218
|
+
type: 'event',
|
|
219
|
+
event: 'agent',
|
|
220
|
+
payload: {
|
|
221
|
+
state: 'heartbeat',
|
|
222
|
+
sessionId,
|
|
223
|
+
runId: activeSession.currentRunId,
|
|
224
|
+
seq,
|
|
225
|
+
runPhase: activeSession.currentRunPhase,
|
|
226
|
+
},
|
|
227
|
+
seq,
|
|
228
|
+
id: `agent-heartbeat-${activeSession.currentRunId}-${seq}-${Date.now()}`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function ensureActivityHeartbeat(activeSession) {
|
|
232
|
+
if (!activeSession || activeSession.heartbeatTimer)
|
|
233
|
+
return;
|
|
234
|
+
activeSession.heartbeatTimer = setInterval(() => {
|
|
235
|
+
sendActivityHeartbeat(activeSession);
|
|
236
|
+
}, SESSION_ACTIVITY_HEARTBEAT_INTERVAL_MS);
|
|
237
|
+
activeSession.heartbeatTimer.unref?.();
|
|
238
|
+
}
|
|
197
239
|
function flushTextBuffer(activeSession) {
|
|
198
240
|
const textBuffer = activeSession?.pendingTextEvent;
|
|
199
241
|
if (!activeSession || !textBuffer || !textBuffer.text)
|
|
@@ -209,9 +251,16 @@ function bindAdapterEvents(runtime, sessionId, agentType, adapter) {
|
|
|
209
251
|
}
|
|
210
252
|
adapter.on('agentEvent', (event) => {
|
|
211
253
|
const activeSession = runtime.sessions.get(sessionId);
|
|
254
|
+
const runPhase = runPhaseFromAgentEvent(event);
|
|
255
|
+
const isTerminalEvent = event.state === 'final' || event.state === 'error' || event.state === 'aborted';
|
|
212
256
|
if (activeSession) {
|
|
213
|
-
activeSession.currentRunId = event.runId;
|
|
214
257
|
activeSession.nextEventSeq = event.seq + 1;
|
|
258
|
+
if (!isTerminalEvent)
|
|
259
|
+
activeSession.currentRunId = event.runId;
|
|
260
|
+
if (!isTerminalEvent && runPhase) {
|
|
261
|
+
activeSession.currentRunPhase = runPhase;
|
|
262
|
+
ensureActivityHeartbeat(activeSession);
|
|
263
|
+
}
|
|
215
264
|
if (event.agentSessionId)
|
|
216
265
|
activeSession.agentSessionId = event.agentSessionId;
|
|
217
266
|
}
|
|
@@ -328,10 +377,12 @@ function bindAdapterEvents(runtime, sessionId, agentType, adapter) {
|
|
|
328
377
|
else if (event.state === 'tool-call' || event.state === 'tool-result' || event.state === 'approval-pending') {
|
|
329
378
|
flushTextBuffer(activeSession);
|
|
330
379
|
}
|
|
331
|
-
if (
|
|
380
|
+
if (isTerminalEvent &&
|
|
332
381
|
activeSession?.currentRunId === event.runId) {
|
|
333
382
|
activeSession.currentRunId = null;
|
|
383
|
+
activeSession.currentRunPhase = null;
|
|
334
384
|
activeSession.nextEventSeq = 0;
|
|
385
|
+
stopActivityHeartbeat(activeSession);
|
|
335
386
|
runtime.chatQueue?.noteTerminal(sessionId);
|
|
336
387
|
}
|
|
337
388
|
sendAgentEvent(event, extra);
|
|
@@ -355,6 +406,10 @@ function rememberProcessedReqId(runtime, reqId) {
|
|
|
355
406
|
}
|
|
356
407
|
}
|
|
357
408
|
async function disposeSession(session) {
|
|
409
|
+
if (session.heartbeatTimer) {
|
|
410
|
+
clearInterval(session.heartbeatTimer);
|
|
411
|
+
session.heartbeatTimer = null;
|
|
412
|
+
}
|
|
358
413
|
session.adapter.removeAllListeners();
|
|
359
414
|
await session.adapter.stop().catch(() => { });
|
|
360
415
|
}
|
|
@@ -372,7 +427,10 @@ async function createActiveSession(runtime, sessionId, agentType, resolvedWorkDi
|
|
|
372
427
|
agentSessionId: incomingAgentSid ?? null,
|
|
373
428
|
lastActiveAt: Date.now(),
|
|
374
429
|
currentRunId: null,
|
|
430
|
+
currentRunPhase: null,
|
|
375
431
|
nextEventSeq: 0,
|
|
432
|
+
heartbeatSeq: 0,
|
|
433
|
+
heartbeatTimer: null,
|
|
376
434
|
pendingTextEvent: null,
|
|
377
435
|
externalChannel: externalChannel ?? null,
|
|
378
436
|
externalReplyTarget: externalReplyTarget ?? null,
|
|
@@ -394,7 +452,12 @@ function emitSyntheticAbort(runtime, sessionId) {
|
|
|
394
452
|
runtime.runTextAcc.delete(`${sessionId}:${runId}`);
|
|
395
453
|
session.pendingTextEvent = null;
|
|
396
454
|
session.currentRunId = null;
|
|
455
|
+
session.currentRunPhase = null;
|
|
397
456
|
session.nextEventSeq = 0;
|
|
457
|
+
if (session.heartbeatTimer) {
|
|
458
|
+
clearInterval(session.heartbeatTimer);
|
|
459
|
+
session.heartbeatTimer = null;
|
|
460
|
+
}
|
|
398
461
|
runtime.client.sendAgentEvent({
|
|
399
462
|
type: 'event',
|
|
400
463
|
event: 'agent',
|
|
@@ -228,6 +228,10 @@ export class SessionManager {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
if (oldest) {
|
|
231
|
+
if (oldest.session.heartbeatTimer) {
|
|
232
|
+
clearInterval(oldest.session.heartbeatTimer);
|
|
233
|
+
oldest.session.heartbeatTimer = null;
|
|
234
|
+
}
|
|
231
235
|
oldest.session.adapter.removeAllListeners();
|
|
232
236
|
oldest.session.adapter.stop().catch(() => { });
|
|
233
237
|
this.sessions.delete(oldest.key);
|
|
@@ -242,6 +246,10 @@ export class SessionManager {
|
|
|
242
246
|
}
|
|
243
247
|
cleanup() {
|
|
244
248
|
for (const [, session] of this.sessions) {
|
|
249
|
+
if (session.heartbeatTimer) {
|
|
250
|
+
clearInterval(session.heartbeatTimer);
|
|
251
|
+
session.heartbeatTimer = null;
|
|
252
|
+
}
|
|
245
253
|
session.adapter.stop().catch(() => { });
|
|
246
254
|
}
|
|
247
255
|
this.sessions.clear();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentType, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
1
|
+
import type { AgentType, ExternalChannelSessionStatus, SessionRunPhase } from '@shennian/wire';
|
|
2
2
|
import type { AgentAdapter } from '../agents/adapter.js';
|
|
3
3
|
import type { CliRelayClient } from '../relay/client.js';
|
|
4
4
|
import type { NativeSessionFusionService } from '../native-fusion/service.js';
|
|
@@ -11,7 +11,10 @@ export type ActiveSession = {
|
|
|
11
11
|
agentSessionId: string | null;
|
|
12
12
|
lastActiveAt: number;
|
|
13
13
|
currentRunId: string | null;
|
|
14
|
+
currentRunPhase: SessionRunPhase | null;
|
|
14
15
|
nextEventSeq: number;
|
|
16
|
+
heartbeatSeq: number;
|
|
17
|
+
heartbeatTimer: ReturnType<typeof setInterval> | null;
|
|
15
18
|
pendingTextEvent: {
|
|
16
19
|
runId: string;
|
|
17
20
|
seq: number;
|