shennian 0.2.75 → 0.2.76
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/scripts/wechat-rpa-confirmation.mjs +97 -0
- package/dist/scripts/wechat-rpa-download-candidates.mjs +84 -0
- package/dist/scripts/wechat-rpa-win-visual.mjs +668 -0
- package/dist/scripts/wechat-rpa-win.mjs +119 -0
- package/dist/src/agents/command-spec.js +24 -2
- package/dist/src/agents/external-channel-instructions.js +2 -0
- package/dist/src/channels/base.d.ts +1 -0
- package/dist/src/channels/runtime.d.ts +9 -2
- package/dist/src/channels/runtime.js +56 -6
- package/dist/src/channels/secret-registry.d.ts +1 -1
- package/dist/src/channels/wechat-rpa/macos-flow.d.ts +5 -0
- package/dist/src/channels/wechat-rpa/macos-flow.js +50 -2
- package/dist/src/channels/wechat-rpa/windows-visual-flow.d.ts +36 -0
- package/dist/src/channels/wechat-rpa/windows-visual-flow.js +182 -0
- package/dist/src/channels/wechat-rpa.d.ts +13 -16
- package/dist/src/channels/wechat-rpa.js +149 -14
- package/dist/src/commands/external.js +10 -1
- package/dist/src/commands/manager.js +18 -0
- package/dist/src/manager/runtime.js +23 -6
- package/dist/src/session/handlers/chat.js +12 -7
- package/dist/src/session/queue.js +2 -0
- package/dist/src/session/types.d.ts +1 -0
- package/package.json +10 -9
|
@@ -12,6 +12,7 @@ import { ChannelRuntime } from '../channels/runtime.js';
|
|
|
12
12
|
import { splitExternalReplyText } from '../channels/reply-split.js';
|
|
13
13
|
import { resolveShennianPath } from '../config/index.js';
|
|
14
14
|
import { buildExternalChannelInstructions } from '../agents/external-channel-instructions.js';
|
|
15
|
+
const MAX_MANAGER_IPC_BODY_BYTES = Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES || 2 * 1024 * 1024);
|
|
15
16
|
let singleton = null;
|
|
16
17
|
export function setManagerRuntimeService(service) {
|
|
17
18
|
singleton = service;
|
|
@@ -71,18 +72,19 @@ function parseExternalReplyAttachment(value) {
|
|
|
71
72
|
const localPath = String(record.localPath || '');
|
|
72
73
|
const url = String(record.url || '');
|
|
73
74
|
const size = Number(record.size || 0);
|
|
75
|
+
if (dataBase64)
|
|
76
|
+
throw new Error('Manager IPC external attachments must use localPath or url; dataBase64 is not accepted');
|
|
74
77
|
if (kind !== 'image' && kind !== 'video' && kind !== 'file')
|
|
75
78
|
return undefined;
|
|
76
79
|
if (!name || !mimeType || !Number.isFinite(size) || size < 0)
|
|
77
80
|
return undefined;
|
|
78
|
-
if (!
|
|
81
|
+
if (!localPath && !url)
|
|
79
82
|
return undefined;
|
|
80
83
|
return {
|
|
81
84
|
kind,
|
|
82
85
|
name,
|
|
83
86
|
mimeType,
|
|
84
87
|
size,
|
|
85
|
-
...(dataBase64 ? { dataBase64 } : {}),
|
|
86
88
|
...(localPath ? { localPath } : {}),
|
|
87
89
|
...(url ? { url } : {}),
|
|
88
90
|
};
|
|
@@ -147,8 +149,15 @@ function compactWorkerTranscript(rawMessages, limit) {
|
|
|
147
149
|
}
|
|
148
150
|
async function readJson(req) {
|
|
149
151
|
const chunks = [];
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
let total = 0;
|
|
153
|
+
for await (const chunk of req) {
|
|
154
|
+
const buffer = Buffer.from(chunk);
|
|
155
|
+
total += buffer.byteLength;
|
|
156
|
+
if (Number.isFinite(MAX_MANAGER_IPC_BODY_BYTES) && MAX_MANAGER_IPC_BODY_BYTES > 0 && total > MAX_MANAGER_IPC_BODY_BYTES) {
|
|
157
|
+
throw new Error(`Manager IPC request body is too large. Max: ${MAX_MANAGER_IPC_BODY_BYTES} bytes.`);
|
|
158
|
+
}
|
|
159
|
+
chunks.push(buffer);
|
|
160
|
+
}
|
|
152
161
|
const raw = Buffer.concat(chunks).toString('utf-8');
|
|
153
162
|
return raw ? JSON.parse(raw) : {};
|
|
154
163
|
}
|
|
@@ -668,6 +677,12 @@ export class ManagerRuntimeService {
|
|
|
668
677
|
json(res, 200, { ok: true, channel });
|
|
669
678
|
return;
|
|
670
679
|
}
|
|
680
|
+
if (url.pathname === '/wechat-rpa/channel/sync') {
|
|
681
|
+
const { channel, messages } = await this.channelRuntime.syncManagerWeChatRpaChannel(managerSessionId);
|
|
682
|
+
this.broadcastManagerChannelStatus(managerSessionId);
|
|
683
|
+
json(res, 200, { ok: true, channel, messages });
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
671
686
|
json(res, 404, { ok: false, error: `Unknown manager IPC path: ${url.pathname}` });
|
|
672
687
|
}
|
|
673
688
|
catch (err) {
|
|
@@ -757,7 +772,8 @@ ${message || worker.summary || '(无可见摘要)'}
|
|
|
757
772
|
const modelId = config?.modelId || manager?.modelId || '';
|
|
758
773
|
const attachmentInputs = externalAttachmentsForAgent(event.attachments);
|
|
759
774
|
const attachmentSummary = externalAttachmentSummary(event.attachments, event.text);
|
|
760
|
-
const
|
|
775
|
+
const visibleReplyTarget = event.replyTarget ? `回复目标:${event.replyTarget}` : '';
|
|
776
|
+
const visibleBody = [event.text, attachmentSummary, visibleReplyTarget].filter(Boolean).join('\n');
|
|
761
777
|
const visibleMessage = visibleBody
|
|
762
778
|
? `外部消息 / ${event.sender.name || event.sender.id}\n${visibleBody}`
|
|
763
779
|
: `外部消息 / ${event.sender.name || event.sender.id}`;
|
|
@@ -794,6 +810,7 @@ ${message || worker.summary || '(无可见摘要)'}
|
|
|
794
810
|
origin: 'external',
|
|
795
811
|
attachments: input.attachments,
|
|
796
812
|
externalChannel: input.externalChannel ?? null,
|
|
813
|
+
replyTarget: input.replyTarget,
|
|
797
814
|
},
|
|
798
815
|
});
|
|
799
816
|
}
|
|
@@ -879,7 +896,7 @@ function parseWeChatRpaGroups(value) {
|
|
|
879
896
|
.filter((item) => item.name);
|
|
880
897
|
}
|
|
881
898
|
function parseWeChatRpaSource(value) {
|
|
882
|
-
return value === 'macos-flow' || value === 'macos-probe' || value === 'fixture-jsonl' ? value : undefined;
|
|
899
|
+
return value === 'macos-flow' || value === 'macos-probe' || value === 'windows-visual-flow' || value === 'fixture-jsonl' ? value : undefined;
|
|
883
900
|
}
|
|
884
901
|
function externalAttachmentsForAgent(attachments) {
|
|
885
902
|
const result = attachments
|
|
@@ -142,7 +142,7 @@ function externalChannelEnabled(channel) {
|
|
|
142
142
|
function managedProviderEnv(agentType) {
|
|
143
143
|
return buildManagedAgentEnv(agentType);
|
|
144
144
|
}
|
|
145
|
-
function externalChannelEnv(sessionId, channel) {
|
|
145
|
+
function externalChannelEnv(sessionId, channel, replyTarget) {
|
|
146
146
|
if (!externalChannelEnabled(channel))
|
|
147
147
|
return {};
|
|
148
148
|
const service = getManagerRuntimeService();
|
|
@@ -151,15 +151,16 @@ function externalChannelEnv(sessionId, channel) {
|
|
|
151
151
|
...injected,
|
|
152
152
|
SHENNIAN_EXTERNAL_SESSION_ID: sessionId,
|
|
153
153
|
SHENNIAN_MANAGER_SESSION_ID: sessionId,
|
|
154
|
+
...(replyTarget?.trim() ? { SHENNIAN_EXTERNAL_REPLY_TARGET: replyTarget.trim() } : {}),
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
|
-
function configureAdapterForSession(adapter, sessionId, agentType, channel) {
|
|
157
|
+
function configureAdapterForSession(adapter, sessionId, agentType, channel, replyTarget) {
|
|
157
158
|
adapter.configure?.({
|
|
158
159
|
sessionId,
|
|
159
160
|
externalChannel: channel ?? null,
|
|
160
161
|
env: {
|
|
161
162
|
...managedProviderEnv(agentType),
|
|
162
|
-
...externalChannelEnv(sessionId, channel),
|
|
163
|
+
...externalChannelEnv(sessionId, channel, replyTarget),
|
|
163
164
|
},
|
|
164
165
|
});
|
|
165
166
|
}
|
|
@@ -357,12 +358,12 @@ async function disposeSession(session) {
|
|
|
357
358
|
session.adapter.removeAllListeners();
|
|
358
359
|
await session.adapter.stop().catch(() => { });
|
|
359
360
|
}
|
|
360
|
-
async function createActiveSession(runtime, sessionId, agentType, resolvedWorkDir, incomingAgentSid, externalChannel) {
|
|
361
|
+
async function createActiveSession(runtime, sessionId, agentType, resolvedWorkDir, incomingAgentSid, externalChannel, externalReplyTarget) {
|
|
361
362
|
runtime.evictIdleSessions();
|
|
362
363
|
const adapter = createAgent(agentType);
|
|
363
364
|
if (!adapter)
|
|
364
365
|
throw new Error(`Unsupported agent: ${agentType}`);
|
|
365
|
-
configureAdapterForSession(adapter, sessionId, agentType, externalChannel);
|
|
366
|
+
configureAdapterForSession(adapter, sessionId, agentType, externalChannel, externalReplyTarget);
|
|
366
367
|
await adapter.start(sessionId, resolvedWorkDir, incomingAgentSid);
|
|
367
368
|
const session = {
|
|
368
369
|
adapter,
|
|
@@ -374,9 +375,10 @@ async function createActiveSession(runtime, sessionId, agentType, resolvedWorkDi
|
|
|
374
375
|
nextEventSeq: 0,
|
|
375
376
|
pendingTextEvent: null,
|
|
376
377
|
externalChannel: externalChannel ?? null,
|
|
378
|
+
externalReplyTarget: externalReplyTarget ?? null,
|
|
377
379
|
externalChannelEnv: {
|
|
378
380
|
...managedProviderEnv(agentType),
|
|
379
|
-
...externalChannelEnv(sessionId, externalChannel),
|
|
381
|
+
...externalChannelEnv(sessionId, externalChannel, externalReplyTarget),
|
|
380
382
|
},
|
|
381
383
|
};
|
|
382
384
|
runtime.sessions.set(sessionId, session);
|
|
@@ -412,6 +414,9 @@ export async function handleChatSend(runtime, req) {
|
|
|
412
414
|
const replyId = responseId || req.id;
|
|
413
415
|
mergeProjectedSessions(sessionListProjection);
|
|
414
416
|
const incomingExternalChannel = normalizeExternalChannel(req.params.externalChannel);
|
|
417
|
+
const incomingReplyTarget = typeof req.params.replyTarget === 'string'
|
|
418
|
+
? req.params.replyTarget.trim()
|
|
419
|
+
: '';
|
|
415
420
|
if (!sessionId || !text) {
|
|
416
421
|
runtime.processedReqIds.delete(req.id);
|
|
417
422
|
runtime.client.sendRes({ type: 'res', id: replyId, ok: false, error: 'sessionId and text are required' });
|
|
@@ -467,7 +472,7 @@ export async function handleChatSend(runtime, req) {
|
|
|
467
472
|
}
|
|
468
473
|
if (!session) {
|
|
469
474
|
try {
|
|
470
|
-
session = await createActiveSession(runtime, sessionId, requestedAgentType, resolvedWorkDir, incomingAgentSid, incomingExternalChannel);
|
|
475
|
+
session = await createActiveSession(runtime, sessionId, requestedAgentType, resolvedWorkDir, incomingAgentSid, incomingExternalChannel, incomingReplyTarget);
|
|
471
476
|
}
|
|
472
477
|
catch (err) {
|
|
473
478
|
const message = err instanceof Error && err.message.startsWith('Unsupported agent:')
|
|
@@ -63,6 +63,7 @@ function queueMessageFromParams(params) {
|
|
|
63
63
|
clientMessageId: params.clientMessageId ?? null,
|
|
64
64
|
attachments: normalizeAttachments(params.attachments),
|
|
65
65
|
externalChannel: params.externalChannel ?? null,
|
|
66
|
+
replyTarget: params.replyTarget ?? null,
|
|
66
67
|
origin: params.origin,
|
|
67
68
|
createdAt: timestamp,
|
|
68
69
|
updatedAt: timestamp,
|
|
@@ -301,6 +302,7 @@ export class ChatQueueManager {
|
|
|
301
302
|
clientMessageId: message.clientMessageId ?? message.id,
|
|
302
303
|
attachments: message.attachments,
|
|
303
304
|
externalChannel: message.externalChannel,
|
|
305
|
+
replyTarget: message.replyTarget,
|
|
304
306
|
waitForDispatch: true,
|
|
305
307
|
},
|
|
306
308
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shennian",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.76",
|
|
4
4
|
"description": "Shennian — AI Agent Control Plane CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,14 +33,20 @@
|
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=18"
|
|
35
35
|
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc && node scripts/copy-wechat-rpa-assets.mjs && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
38
|
+
"build:publish": "node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json && node scripts/copy-wechat-rpa-assets.mjs && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
39
|
+
"dev": "tsc --watch",
|
|
40
|
+
"prepublishOnly": "pnpm build:publish"
|
|
41
|
+
},
|
|
36
42
|
"dependencies": {
|
|
37
43
|
"@mariozechner/pi-agent-core": "^0.64.0",
|
|
38
44
|
"@sinclair/typebox": "^0.34.49",
|
|
45
|
+
"@shennian/wire": "workspace:*",
|
|
39
46
|
"chalk": "^5.4.1",
|
|
40
47
|
"commander": "^13.1.0",
|
|
41
48
|
"qrcode-terminal": "^0.12.0",
|
|
42
|
-
"ws": "^8.18.1"
|
|
43
|
-
"@shennian/wire": "0.1.5"
|
|
49
|
+
"ws": "^8.18.1"
|
|
44
50
|
},
|
|
45
51
|
"devDependencies": {
|
|
46
52
|
"@types/node": "^20",
|
|
@@ -48,10 +54,5 @@
|
|
|
48
54
|
"@types/ws": "^8.18.1",
|
|
49
55
|
"tsx": "^4.19.4",
|
|
50
56
|
"typescript": "^5.9.3"
|
|
51
|
-
},
|
|
52
|
-
"scripts": {
|
|
53
|
-
"build": "tsc && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
54
|
-
"build:publish": "node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
55
|
-
"dev": "tsc --watch"
|
|
56
57
|
}
|
|
57
|
-
}
|
|
58
|
+
}
|