@rezti/dsh-rez-wechat 0.1.19 → 0.1.21
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/README.md +1 -1
- package/lib/channel.js +1 -1
- package/lib/index.js +1 -1
- package/lib/web-shim-cli.js +5 -0
- package/lib/web-shim.d.ts +11 -2
- package/lib/web-shim.js +107 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ dsh plugin --profile web add @rezti/dsh-rez-suite
|
|
|
19
19
|
|
|
20
20
|
- 左侧工作区分组是 **微信**,不是 Ungrouped
|
|
21
21
|
- 连续消息延续同一会话
|
|
22
|
-
-
|
|
22
|
+
- 模型跟网页默认(官方默认 DeepSeek-V4-Flash;不要因为微信通道去切 Kimi)
|
|
23
23
|
- 网页归档后再从微信说话会自动回到侧栏(官方会藏空白会话,所以「重启对话」会先打一句招呼)
|
|
24
24
|
- 网页端选择题(Selection)会编成 `1. 2. 3.` 发到微信;回复数字或选项原文即可继续,不必在网页点选
|
|
25
25
|
- 思考过程不会发到微信;多段正文会保留换行
|
package/lib/channel.js
CHANGED
|
@@ -167,7 +167,7 @@ export class WeixinChannel {
|
|
|
167
167
|
if (this.runChild !== undefined && this.runChild.exitCode === null)
|
|
168
168
|
return;
|
|
169
169
|
this.phase = 'listening';
|
|
170
|
-
this.hint = '
|
|
170
|
+
this.hint = '微信通道已在后台听着。消息会进网页「微信」文件夹的同一会话,模型跟网页默认(DeepSeek-V4-Flash)。';
|
|
171
171
|
const child = spawn('npx', ['-y', 'dsh-wechat-bridge', 'run', '--data-dir', DATA_DIR], {
|
|
172
172
|
env: weixinRunEnv(),
|
|
173
173
|
stdio: ['ignore', 'pipe', 'pipe'],
|
package/lib/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export const name = 'rez-wechat';
|
|
|
7
7
|
export const inject = ['systemPrompt', 'webServer', 'rezSso'];
|
|
8
8
|
const GUIDANCE = [
|
|
9
9
|
'企业微信有两层,不要混:① 房间消息通道 = 官方 @wecom/aibot-node-sdk(设置页 BotID + Secret 长连接),同事在企微跟哪个 bot 说话就进哪个 Harness 房间(人事/财务/法务/设计/发布/电商/实验室/老板三室),并固定同一条网页会话;只有同事说「重启对话」才新开并把旧的归档。② 办公能力 = 官方 wecom-cli >=1.1(通讯录/在线文档/在线表格/智能表格/智能文档/待办/日程/会议/邮件/微盘/消息),本企业已开通,看 rez_status.wecomCli.modules,按房间 wecomcli-* 技能执行。不要因为状态页没有企微 MCP 就说没有企微能力,也不要说「超过 10 人只能用文档」。CLI 报未授权才说该模块未开通。密钥写在 ~/.dsh/wecom-channels.json,不要写进 compose。没有绑定任何 bot 且仍配置了 REZ_WECHAT_WEBHOOK 时,才兼容旧的 wecom-mcp 群发,不要引导去填群 Webhook。不要自写 WebSocket/HTTP 客户端。',
|
|
10
|
-
'个人微信是 QClaw 同款 ClawBot 通道:在 Rez
|
|
10
|
+
'个人微信是 QClaw 同款 ClawBot 通道:在 Rez 面板「微信」页扫码一次,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认(官方默认 DeepSeek-V4-Flash,不要因为微信去切 Kimi)。网页端归档了也能从微信自动恢复到侧栏(空白会话网页会藏起来,所以新开的会话会先打一句招呼再出现)。网页端出现选择题时会编成纯文本发到微信,回复数字或选项原文即可;思考过程不会转发。发「重启对话」会新开一条可见的网页会话并把旧的归档。通道断了点「重新连接」(已登录不必再扫码)。不要再跑 npx weixin-mcp login,也不要调用 mcp__weixin__*。网页端必须开着。工商查询请切到法务助理,避免串房间。',
|
|
11
11
|
'这是 ClawBot 客服会话,不是用个人微信号管好友/群。对外发消息必须先征得用户批准。',
|
|
12
12
|
].join('');
|
|
13
13
|
function isLoopbackRequest(request) {
|
package/lib/web-shim-cli.js
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* Executable stand-in for `dsh`. dsh-wechat-bridge spawns:
|
|
4
4
|
* $DSH_BRIDGE_DSH --profile headless <task>
|
|
5
5
|
* stdout is the WeChat reply; logs go to stderr.
|
|
6
|
+
*
|
|
7
|
+
* Must process.exit: native fetch keeps the event loop alive, and the bridge
|
|
8
|
+
* holds a per-chat lock until this child exits. Without an explicit exit the
|
|
9
|
+
* first WeChat turn can reply, then every follow-up waits forever.
|
|
6
10
|
*/
|
|
7
11
|
import { parseHeadlessArgv, runHeadlessViaWeb } from './web-shim.js';
|
|
8
12
|
const parsed = parseHeadlessArgv(process.argv.slice(1));
|
|
@@ -20,3 +24,4 @@ catch (error) {
|
|
|
20
24
|
process.stderr.write(`dsh-web-shim: ${message}\n`);
|
|
21
25
|
process.stdout.write(`${message}\n`);
|
|
22
26
|
}
|
|
27
|
+
process.exit(0);
|
package/lib/web-shim.d.ts
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Headless always mints a fresh Agent (DeepSeek default, Ungrouped cwd hash).
|
|
6
6
|
* Web RPC reuses one session under ~/.dsh/workspaces/微信 so the sidebar
|
|
7
|
-
* folder is named 微信, turns continue, and the model follows the web default
|
|
8
|
-
* (Kimi if that is what the user selected).
|
|
7
|
+
* folder is named 微信, turns continue, and the model follows the web default.
|
|
9
8
|
*/
|
|
10
9
|
export declare const WECHAT_WORKSPACE_NAME = "\u5FAE\u4FE1";
|
|
11
10
|
export declare const DEFAULT_WEB_URL = "http://127.0.0.1:3080";
|
|
@@ -75,6 +74,16 @@ export declare function ensureWechatInboxAgents(cwd: string): void;
|
|
|
75
74
|
export declare function sessionStorePath(env?: NodeJS.ProcessEnv, home?: string): string;
|
|
76
75
|
export declare function loadSessionStore(path: string): SessionStore;
|
|
77
76
|
export declare function saveSessionStore(path: string, store: SessionStore): void;
|
|
77
|
+
/** dsh 0.1.5+ wire endpoint is `namespace/method` (slash), not `namespace.method`. */
|
|
78
|
+
export declare function normalizeRpcEndpoint(method: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Typert gateway requires `{ args }` on the wire. Unary Remotes with one
|
|
81
|
+
* `request` parameter expect `{ args: { request: fields } }`; zero-arg Remotes
|
|
82
|
+
* expect `{ args: {} }`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function wrapRemoteArgs(params: Record<string, unknown>): {
|
|
85
|
+
args: Record<string, unknown>;
|
|
86
|
+
};
|
|
78
87
|
export declare function encodeClientRequest(method: string, payload: Record<string, unknown>, rpcId?: string): {
|
|
79
88
|
type: 'client-request';
|
|
80
89
|
rpcId: string;
|
package/lib/web-shim.js
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Headless always mints a fresh Agent (DeepSeek default, Ungrouped cwd hash).
|
|
6
6
|
* Web RPC reuses one session under ~/.dsh/workspaces/微信 so the sidebar
|
|
7
|
-
* folder is named 微信, turns continue, and the model follows the web default
|
|
8
|
-
* (Kimi if that is what the user selected).
|
|
7
|
+
* folder is named 微信, turns continue, and the model follows the web default.
|
|
9
8
|
*/
|
|
10
9
|
import { randomUUID } from 'node:crypto';
|
|
11
10
|
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -270,8 +269,32 @@ export function saveSessionStore(path, store) {
|
|
|
270
269
|
mkdirSync(dirname(path), { recursive: true });
|
|
271
270
|
writeFileSync(path, JSON.stringify(store, null, 2), 'utf8');
|
|
272
271
|
}
|
|
272
|
+
/** dsh 0.1.5+ wire endpoint is `namespace/method` (slash), not `namespace.method`. */
|
|
273
|
+
export function normalizeRpcEndpoint(method) {
|
|
274
|
+
if (method.includes('/'))
|
|
275
|
+
return method;
|
|
276
|
+
const dot = method.indexOf('.');
|
|
277
|
+
if (dot <= 0)
|
|
278
|
+
return method;
|
|
279
|
+
return `${method.slice(0, dot)}/${method.slice(dot + 1)}`;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Typert gateway requires `{ args }` on the wire. Unary Remotes with one
|
|
283
|
+
* `request` parameter expect `{ args: { request: fields } }`; zero-arg Remotes
|
|
284
|
+
* expect `{ args: {} }`.
|
|
285
|
+
*/
|
|
286
|
+
export function wrapRemoteArgs(params) {
|
|
287
|
+
const keys = Object.keys(params);
|
|
288
|
+
if (keys.length === 1 && keys[0] === 'args' && typeof params.args === 'object' && params.args !== null && !Array.isArray(params.args)) {
|
|
289
|
+
return { args: params.args };
|
|
290
|
+
}
|
|
291
|
+
if (keys.length === 0)
|
|
292
|
+
return { args: {} };
|
|
293
|
+
return { args: { request: params } };
|
|
294
|
+
}
|
|
273
295
|
export function encodeClientRequest(method, payload, rpcId = randomUUID()) {
|
|
274
|
-
|
|
296
|
+
const endpoint = normalizeRpcEndpoint(method);
|
|
297
|
+
return { type: 'client-request', rpcId, method: endpoint, payload: wrapRemoteArgs(payload) };
|
|
275
298
|
}
|
|
276
299
|
export function unwrapRpc(body) {
|
|
277
300
|
if (typeof body !== 'object' || body === null)
|
|
@@ -685,11 +708,21 @@ export function historyEvents(body) {
|
|
|
685
708
|
if (typeof unwrapped !== 'object' || unwrapped === null)
|
|
686
709
|
return [];
|
|
687
710
|
const rec = unwrapped;
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
711
|
+
// 0.1.5 session/page → { records: [{ type:'event', event }] }
|
|
712
|
+
const fromRecords = Array.isArray(rec.records)
|
|
713
|
+
? rec.records.map((row) => {
|
|
714
|
+
if (typeof row === 'object' && row !== null && row.type === 'event') {
|
|
715
|
+
return row.event ?? row;
|
|
716
|
+
}
|
|
717
|
+
return row;
|
|
718
|
+
})
|
|
719
|
+
: undefined;
|
|
720
|
+
const raw = fromRecords
|
|
721
|
+
?? (Array.isArray(rec.events) ? rec.events
|
|
722
|
+
: Array.isArray(rec.messages) ? rec.messages
|
|
723
|
+
: Array.isArray(rec.items) ? rec.items
|
|
724
|
+
: Array.isArray(rec.log) ? rec.log
|
|
725
|
+
: []);
|
|
693
726
|
return raw.map(unwrapHistoryItem);
|
|
694
727
|
}
|
|
695
728
|
export function lastAssistantText(events) {
|
|
@@ -779,7 +812,10 @@ export function pickWechatModel(models, env = process.env) {
|
|
|
779
812
|
const provider = env.REZ_WECHAT_PROVIDER?.trim();
|
|
780
813
|
return provider !== undefined && provider !== '' ? { provider, model: forced } : { model: forced };
|
|
781
814
|
}
|
|
782
|
-
|
|
815
|
+
// Follow the web default (official agent-default-model is DeepSeek-V4-Flash).
|
|
816
|
+
// Do not switch a DeepSeek session onto Kimi: session/selectModel also writes
|
|
817
|
+
// the global default, so a WeChat message would make the next restart land on Kimi.
|
|
818
|
+
if (env.REZ_WECHAT_PREFER_KIMI !== '1')
|
|
783
819
|
return undefined;
|
|
784
820
|
const current = currentModelRef(models);
|
|
785
821
|
if (current !== undefined && looksLikeKimi(`${current.provider ?? ''} ${current.model}`))
|
|
@@ -842,8 +878,9 @@ export async function postRpc(baseUrl, method, params, timeoutMs = RPC_TIMEOUT_M
|
|
|
842
878
|
return webBaseUrl(env);
|
|
843
879
|
}
|
|
844
880
|
})();
|
|
845
|
-
const
|
|
846
|
-
const
|
|
881
|
+
const endpoint = normalizeRpcEndpoint(method);
|
|
882
|
+
const url = `${origin}/api/${endpoint}`;
|
|
883
|
+
const envelope = encodeClientRequest(endpoint, params);
|
|
847
884
|
const send = async (cookie) => {
|
|
848
885
|
const headers = { 'content-type': 'application/json' };
|
|
849
886
|
if (cookie !== undefined && cookie.length > 0)
|
|
@@ -892,35 +929,28 @@ async function ensureWorkspace(rpc, cwd) {
|
|
|
892
929
|
mkdirSync(cwd, { recursive: true });
|
|
893
930
|
ensureWechatInboxAgents(cwd);
|
|
894
931
|
try {
|
|
895
|
-
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
return id;
|
|
899
|
-
}
|
|
900
|
-
catch {
|
|
901
|
-
// create may 409 / invalid-path; list is the reconnect authority
|
|
902
|
-
}
|
|
903
|
-
try {
|
|
904
|
-
return findWorkspaceId(await rpc('workspace.list', {}), cwd);
|
|
932
|
+
// 0.1.5 workspace/create is upsert-like ({ created: boolean }); list RPC is gone.
|
|
933
|
+
const created = await rpc('workspace/create', { path: cwd });
|
|
934
|
+
return extractWorkspaceId(created) ?? findWorkspaceId(created, cwd);
|
|
905
935
|
}
|
|
906
936
|
catch {
|
|
907
937
|
return undefined;
|
|
908
938
|
}
|
|
909
939
|
}
|
|
910
940
|
async function createSession(rpc, cwd, workspaceId) {
|
|
911
|
-
// Official session
|
|
912
|
-
// workspaceId is the one that
|
|
941
|
+
// Official session/create accepts at most one of workspaceId / cwd.
|
|
942
|
+
// workspaceId is the one that insertSessionBefore-s into the 微信 sidebar.
|
|
913
943
|
const payload = workspaceId !== undefined ? { workspaceId } : { cwd };
|
|
914
|
-
const created = await rpc('session
|
|
944
|
+
const created = await rpc('session/create', payload);
|
|
915
945
|
const id = extractSessionId(created);
|
|
916
946
|
if (id === undefined)
|
|
917
|
-
throw new Error('session
|
|
947
|
+
throw new Error('session/create 没有返回 sessionId');
|
|
918
948
|
return id;
|
|
919
949
|
}
|
|
920
950
|
async function maybeSelectModel(rpc, sessionId, env) {
|
|
921
951
|
let models;
|
|
922
952
|
try {
|
|
923
|
-
models = await rpc('session
|
|
953
|
+
models = await rpc('session/modelCatalog', {});
|
|
924
954
|
}
|
|
925
955
|
catch {
|
|
926
956
|
models = undefined;
|
|
@@ -930,7 +960,7 @@ async function maybeSelectModel(rpc, sessionId, env) {
|
|
|
930
960
|
return;
|
|
931
961
|
for (const payload of selectModelPayloads(sessionId, ref)) {
|
|
932
962
|
try {
|
|
933
|
-
await rpc('session
|
|
963
|
+
await rpc('session/selectModel', payload);
|
|
934
964
|
return;
|
|
935
965
|
}
|
|
936
966
|
catch {
|
|
@@ -938,15 +968,47 @@ async function maybeSelectModel(rpc, sessionId, env) {
|
|
|
938
968
|
}
|
|
939
969
|
}
|
|
940
970
|
}
|
|
971
|
+
/** Prefer session/page (0.1.5 surface); fall back to session/history (apiproxy). */
|
|
972
|
+
async function fetchSessionHistory(rpc, sessionId, maxMessages = 40) {
|
|
973
|
+
const attempts = [
|
|
974
|
+
{
|
|
975
|
+
method: 'session/page',
|
|
976
|
+
params: {
|
|
977
|
+
address: { kind: 'session', sessionId },
|
|
978
|
+
throughSeq: Number.MAX_SAFE_INTEGER,
|
|
979
|
+
maxMessages,
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
{ method: 'session/history', params: { sessionId, maxMessages } },
|
|
983
|
+
];
|
|
984
|
+
let lastError;
|
|
985
|
+
for (const attempt of attempts) {
|
|
986
|
+
try {
|
|
987
|
+
return historyEvents(await rpc(attempt.method, attempt.params));
|
|
988
|
+
}
|
|
989
|
+
catch (error) {
|
|
990
|
+
lastError = error;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
994
|
+
}
|
|
941
995
|
async function sessionAlive(rpc, sessionId) {
|
|
942
996
|
try {
|
|
943
|
-
await rpc
|
|
997
|
+
await fetchSessionHistory(rpc, sessionId, 1);
|
|
944
998
|
return true;
|
|
945
999
|
}
|
|
946
1000
|
catch {
|
|
947
1001
|
return false;
|
|
948
1002
|
}
|
|
949
1003
|
}
|
|
1004
|
+
function promptPayload(sessionId, text) {
|
|
1005
|
+
return {
|
|
1006
|
+
requestId: randomUUID(),
|
|
1007
|
+
sessionId,
|
|
1008
|
+
mode: 'queue',
|
|
1009
|
+
content: [{ type: 'text', text }],
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
950
1012
|
export function extractArchivedSessionIds(body) {
|
|
951
1013
|
const unwrapped = unwrapRpc(body);
|
|
952
1014
|
if (typeof unwrapped !== 'object' || unwrapped === null)
|
|
@@ -974,15 +1036,19 @@ async function tryRpc(rpc, method, params) {
|
|
|
974
1036
|
}
|
|
975
1037
|
/** Stock dsh archives one-way and hides blank sessions. Restore + attach + title. */
|
|
976
1038
|
export async function ensureSessionVisible(rpc, sessionId, env = process.env, workspaceId, loopback = true) {
|
|
977
|
-
|
|
978
|
-
await tryRpc(rpc, 'session.unarchive', { sessionId });
|
|
1039
|
+
// 0.1.5 dropped unarchive/attach RPCs; insertSessionBefore is the sidebar join.
|
|
979
1040
|
if (loopback) {
|
|
980
1041
|
const workspacePath = wechatWorkspaceDir(env);
|
|
981
|
-
const
|
|
1042
|
+
const origin = webBaseUrl(env);
|
|
1043
|
+
const url = `${origin}/api/dsh-rez-suite/weixin/unarchive`;
|
|
982
1044
|
try {
|
|
1045
|
+
const headers = { 'content-type': 'application/json' };
|
|
1046
|
+
const cookie = await authCookieFor(origin, env);
|
|
1047
|
+
if (cookie !== undefined)
|
|
1048
|
+
headers.cookie = cookie;
|
|
983
1049
|
await fetch(url, {
|
|
984
1050
|
method: 'POST',
|
|
985
|
-
headers
|
|
1051
|
+
headers,
|
|
986
1052
|
body: JSON.stringify({ sessionId, workspacePath }),
|
|
987
1053
|
signal: AbortSignal.timeout(3000),
|
|
988
1054
|
});
|
|
@@ -992,17 +1058,16 @@ export async function ensureSessionVisible(rpc, sessionId, env = process.env, wo
|
|
|
992
1058
|
}
|
|
993
1059
|
}
|
|
994
1060
|
if (workspaceId !== undefined) {
|
|
995
|
-
await tryRpc(rpc, 'workspace
|
|
996
|
-
await tryRpc(rpc, 'workspace.insertSessionBefore', { workspaceId, sessionId });
|
|
1061
|
+
await tryRpc(rpc, 'workspace/insertSessionBefore', { workspaceId, sessionId });
|
|
997
1062
|
}
|
|
998
1063
|
const title = basename(wechatWorkspaceDir(env)) || WECHAT_WORKSPACE_NAME;
|
|
999
|
-
await tryRpc(rpc, 'session
|
|
1064
|
+
await tryRpc(rpc, 'session/rename', { sessionId, title });
|
|
1000
1065
|
}
|
|
1001
1066
|
async function archiveSession(rpc, sessionId) {
|
|
1002
|
-
await tryRpc(rpc, 'workspace
|
|
1067
|
+
await tryRpc(rpc, 'workspace/archiveSession', { sessionId });
|
|
1003
1068
|
}
|
|
1004
1069
|
async function abortSessionTurn(rpc, sessionId) {
|
|
1005
|
-
for (const method of ['session
|
|
1070
|
+
for (const method of ['session/cancel', 'session/abort', 'session/stop', 'session/interrupt']) {
|
|
1006
1071
|
if (await tryRpc(rpc, method, { sessionId }))
|
|
1007
1072
|
return;
|
|
1008
1073
|
}
|
|
@@ -1032,7 +1097,7 @@ async function tryAnswerPendingQuestion(rpc, sessionId, choice) {
|
|
|
1032
1097
|
{ sessionId, answer },
|
|
1033
1098
|
{ sessionId, answers: answer.answers },
|
|
1034
1099
|
];
|
|
1035
|
-
for (const method of ['question
|
|
1100
|
+
for (const method of ['question/respond', 'session/respondQuestion']) {
|
|
1036
1101
|
for (const params of payloads) {
|
|
1037
1102
|
if (await tryRpcQuick(rpc, method, params))
|
|
1038
1103
|
return true;
|
|
@@ -1057,7 +1122,7 @@ async function waitForAssistant(rpc, sessionId, beforeText, timeoutMs, ignorePen
|
|
|
1057
1122
|
while (Date.now() < deadline) {
|
|
1058
1123
|
let events = [];
|
|
1059
1124
|
try {
|
|
1060
|
-
events =
|
|
1125
|
+
events = await fetchSessionHistory(rpc, sessionId, 40);
|
|
1061
1126
|
}
|
|
1062
1127
|
catch {
|
|
1063
1128
|
events = [];
|
|
@@ -1128,7 +1193,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
1128
1193
|
let before = '';
|
|
1129
1194
|
let events = [];
|
|
1130
1195
|
try {
|
|
1131
|
-
events =
|
|
1196
|
+
events = await fetchSessionHistory(rpc, sessionId, 40);
|
|
1132
1197
|
before = usableAssistantText(lastAssistantText(events));
|
|
1133
1198
|
}
|
|
1134
1199
|
catch {
|
|
@@ -1147,11 +1212,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
1147
1212
|
const answered = await tryAnswerPendingQuestion(rpc, sessionId, choice);
|
|
1148
1213
|
if (!answered) {
|
|
1149
1214
|
await abortSessionTurn(rpc, sessionId);
|
|
1150
|
-
await rpc('session
|
|
1151
|
-
sessionId,
|
|
1152
|
-
mode: 'queue',
|
|
1153
|
-
content: [{ type: 'text', text: `用户在微信选择了:${choice.label}` }],
|
|
1154
|
-
});
|
|
1215
|
+
await rpc('session/prompt', promptPayload(sessionId, `用户在微信选择了:${choice.label}`));
|
|
1155
1216
|
}
|
|
1156
1217
|
skipUserPrompt = true;
|
|
1157
1218
|
}
|
|
@@ -1160,11 +1221,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
1160
1221
|
if (!turnIsIdle(events) || turnIsBlocked(events)) {
|
|
1161
1222
|
await abortSessionTurn(rpc, sessionId);
|
|
1162
1223
|
}
|
|
1163
|
-
await rpc('session
|
|
1164
|
-
sessionId,
|
|
1165
|
-
mode: 'queue',
|
|
1166
|
-
content: [{ type: 'text', text: promptText }],
|
|
1167
|
-
});
|
|
1224
|
+
await rpc('session/prompt', promptPayload(sessionId, promptText));
|
|
1168
1225
|
}
|
|
1169
1226
|
const reply = await waitForAssistant(rpc, sessionId, before, timeoutMs, questions, stuckAck(folder));
|
|
1170
1227
|
store.sessions[key] = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rezti/dsh-rez-wechat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "ReZ-TI WeChat/WeCom bridges. Personal WeChat is QClaw/ClawBot scan-and-chat via dsh-wechat-bridge; WeCom AI bots use the official @wecom/aibot-node-sdk (BotID + Secret) bound per Harness room.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|