@rezti/dsh-rez-wechat 0.1.18 → 0.1.20

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/lib/web-shim.d.ts CHANGED
@@ -9,6 +9,14 @@
9
9
  */
10
10
  export declare const WECHAT_WORKSPACE_NAME = "\u5FAE\u4FE1";
11
11
  export declare const DEFAULT_WEB_URL = "http://127.0.0.1:3080";
12
+ /** Written by suite when dsh web boots; carries ?token= for 0.1.5 browser auth. */
13
+ export declare function dshWebUrlFile(env?: NodeJS.ProcessEnv, home?: string): string;
14
+ /** Origin only (no path/query). API posts go to `${origin}/api/...`. */
15
+ export declare function webBaseUrl(env?: NodeJS.ProcessEnv, home?: string): string;
16
+ /** Launch token from env, REZ_DSH_WEB_URL query, or ~/.dsh/dsh-web.url. */
17
+ export declare function webLaunchToken(env?: NodeJS.ProcessEnv, home?: string): string | undefined;
18
+ /** Exchange launch token for the HttpOnly dsh-auth cookie (dsh 0.1.5+). */
19
+ export declare function mintWebAuthCookie(origin: string, token: string, timeoutMs?: number): Promise<string>;
12
20
  /** Seeded only when the inbox folder has no AGENTS.md yet. */
13
21
  export declare const WECHAT_INBOX_AGENTS: string;
14
22
  export interface ModelRef {
@@ -65,9 +73,18 @@ export declare function wechatWorkspaceDir(env?: NodeJS.ProcessEnv, home?: strin
65
73
  /** Write a short inbox AGENTS.md once; never overwrite a living file. Skip non-微信 rooms (企微按房间绑定). */
66
74
  export declare function ensureWechatInboxAgents(cwd: string): void;
67
75
  export declare function sessionStorePath(env?: NodeJS.ProcessEnv, home?: string): string;
68
- export declare function webBaseUrl(env?: NodeJS.ProcessEnv): string;
69
76
  export declare function loadSessionStore(path: string): SessionStore;
70
77
  export declare function saveSessionStore(path: string, store: SessionStore): void;
78
+ /** dsh 0.1.5+ wire endpoint is `namespace/method` (slash), not `namespace.method`. */
79
+ export declare function normalizeRpcEndpoint(method: string): string;
80
+ /**
81
+ * Typert gateway requires `{ args }` on the wire. Unary Remotes with one
82
+ * `request` parameter expect `{ args: { request: fields } }`; zero-arg Remotes
83
+ * expect `{ args: {} }`.
84
+ */
85
+ export declare function wrapRemoteArgs(params: Record<string, unknown>): {
86
+ args: Record<string, unknown>;
87
+ };
71
88
  export declare function encodeClientRequest(method: string, payload: Record<string, unknown>, rpcId?: string): {
72
89
  type: 'client-request';
73
90
  rpcId: string;
@@ -104,7 +121,7 @@ export declare function weixinBridgeEnv(opts: {
104
121
  launcherPath: string;
105
122
  shimScript: string;
106
123
  }): NodeJS.ProcessEnv;
107
- export declare function postRpc(baseUrl: string, method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
124
+ export declare function postRpc(baseUrl: string, method: string, params: Record<string, unknown>, timeoutMs?: number, env?: NodeJS.ProcessEnv): Promise<unknown>;
108
125
  export declare function extractArchivedSessionIds(body: unknown): string[];
109
126
  /** Stock dsh archives one-way and hides blank sessions. Restore + attach + title. */
110
127
  export declare function ensureSessionVisible(rpc: RpcFn, sessionId: string, env?: NodeJS.ProcessEnv, workspaceId?: string, loopback?: boolean): Promise<void>;
package/lib/web-shim.js CHANGED
@@ -13,6 +13,107 @@ import { homedir } from 'node:os';
13
13
  import { basename, dirname, join } from 'node:path';
14
14
  export const WECHAT_WORKSPACE_NAME = '微信';
15
15
  export const DEFAULT_WEB_URL = 'http://127.0.0.1:3080';
16
+ /** Written by suite when dsh web boots; carries ?token= for 0.1.5 browser auth. */
17
+ export function dshWebUrlFile(env = process.env, home = homedir()) {
18
+ return join(dshHomeDir(env, home), 'dsh-web.url');
19
+ }
20
+ /** Origin only (no path/query). API posts go to `${origin}/api/...`. */
21
+ export function webBaseUrl(env = process.env, home = homedir()) {
22
+ const fromFile = (() => {
23
+ try {
24
+ return readFileSync(dshWebUrlFile(env, home), 'utf8').trim();
25
+ }
26
+ catch {
27
+ return undefined;
28
+ }
29
+ })();
30
+ for (const raw of [env.REZ_DSH_WEB_URL, fromFile, DEFAULT_WEB_URL]) {
31
+ if (raw === undefined || raw.trim() === '')
32
+ continue;
33
+ try {
34
+ const withScheme = /:\/\//.test(raw.trim()) ? raw.trim() : `http://${raw.trim()}`;
35
+ const url = new URL(withScheme);
36
+ return `${url.protocol}//${url.host}`;
37
+ }
38
+ catch {
39
+ /* try next */
40
+ }
41
+ }
42
+ return DEFAULT_WEB_URL;
43
+ }
44
+ /** Launch token from env, REZ_DSH_WEB_URL query, or ~/.dsh/dsh-web.url. */
45
+ export function webLaunchToken(env = process.env, home = homedir()) {
46
+ const fromEnv = env.REZ_DSH_WEB_TOKEN?.trim();
47
+ if (fromEnv)
48
+ return fromEnv;
49
+ const candidates = [env.REZ_DSH_WEB_URL, (() => {
50
+ try {
51
+ return readFileSync(dshWebUrlFile(env, home), 'utf8').trim();
52
+ }
53
+ catch {
54
+ return undefined;
55
+ }
56
+ })()];
57
+ for (const raw of candidates) {
58
+ if (raw === undefined || raw === '')
59
+ continue;
60
+ try {
61
+ const withScheme = /:\/\//.test(raw) ? raw : `http://${raw}`;
62
+ const token = new URL(withScheme).searchParams.get('token');
63
+ if (token !== null && token.length > 0)
64
+ return token;
65
+ }
66
+ catch {
67
+ /* try next */
68
+ }
69
+ }
70
+ return undefined;
71
+ }
72
+ const authCookies = new Map();
73
+ function collectSetCookies(headers) {
74
+ const anyHeaders = headers;
75
+ if (typeof anyHeaders.getSetCookie === 'function') {
76
+ return anyHeaders.getSetCookie();
77
+ }
78
+ const single = headers.get('set-cookie');
79
+ return single === null ? [] : [single];
80
+ }
81
+ /** Exchange launch token for the HttpOnly dsh-auth cookie (dsh 0.1.5+). */
82
+ export async function mintWebAuthCookie(origin, token, timeoutMs = RPC_TIMEOUT_MS) {
83
+ const url = `${origin.replace(/\/$/, '')}/?token=${encodeURIComponent(token)}`;
84
+ let response;
85
+ try {
86
+ response = await fetch(url, {
87
+ method: 'GET',
88
+ redirect: 'manual',
89
+ signal: AbortSignal.timeout(timeoutMs),
90
+ });
91
+ }
92
+ catch (error) {
93
+ const why = error instanceof Error ? error.message : String(error);
94
+ throw new Error(`换取 dsh web 认证 cookie 失败(${origin}):${why}`);
95
+ }
96
+ const pairs = collectSetCookies(response.headers)
97
+ .map((row) => row.split(';', 1)[0]?.trim())
98
+ .filter((row) => typeof row === 'string' && row.includes('='));
99
+ if (pairs.length === 0) {
100
+ throw new Error('dsh web 未下发认证 cookie。请用终端打印的完整地址打开网页(必须带 ?token=),或确认 ~/.dsh/dsh-web.url 已由 suite 写入。');
101
+ }
102
+ return pairs.join('; ');
103
+ }
104
+ async function authCookieFor(origin, env, force = false) {
105
+ if (!force) {
106
+ const cached = authCookies.get(origin);
107
+ if (cached !== undefined)
108
+ return cached;
109
+ }
110
+ const token = webLaunchToken(env);
111
+ if (token === undefined)
112
+ return undefined;
113
+ const cookie = await mintWebAuthCookie(origin, token);
114
+ authCookies.set(origin, cookie);
115
+ return cookie;
116
+ }
16
117
  /** Seeded only when the inbox folder has no AGENTS.md yet. */
17
118
  export const WECHAT_INBOX_AGENTS = [
18
119
  '# 微信',
@@ -151,9 +252,6 @@ export function sessionStorePath(env = process.env, home = homedir()) {
151
252
  return env.REZ_WECHAT_SESSION_STORE;
152
253
  return join(dshHomeDir(env, home), 'dsh-rez-weixin', 'web-sessions.json');
153
254
  }
154
- export function webBaseUrl(env = process.env) {
155
- return (env.REZ_DSH_WEB_URL ?? DEFAULT_WEB_URL).replace(/\/$/, '');
156
- }
157
255
  export function loadSessionStore(path) {
158
256
  try {
159
257
  const parsed = JSON.parse(readFileSync(path, 'utf8'));
@@ -172,8 +270,32 @@ export function saveSessionStore(path, store) {
172
270
  mkdirSync(dirname(path), { recursive: true });
173
271
  writeFileSync(path, JSON.stringify(store, null, 2), 'utf8');
174
272
  }
273
+ /** dsh 0.1.5+ wire endpoint is `namespace/method` (slash), not `namespace.method`. */
274
+ export function normalizeRpcEndpoint(method) {
275
+ if (method.includes('/'))
276
+ return method;
277
+ const dot = method.indexOf('.');
278
+ if (dot <= 0)
279
+ return method;
280
+ return `${method.slice(0, dot)}/${method.slice(dot + 1)}`;
281
+ }
282
+ /**
283
+ * Typert gateway requires `{ args }` on the wire. Unary Remotes with one
284
+ * `request` parameter expect `{ args: { request: fields } }`; zero-arg Remotes
285
+ * expect `{ args: {} }`.
286
+ */
287
+ export function wrapRemoteArgs(params) {
288
+ const keys = Object.keys(params);
289
+ if (keys.length === 1 && keys[0] === 'args' && typeof params.args === 'object' && params.args !== null && !Array.isArray(params.args)) {
290
+ return { args: params.args };
291
+ }
292
+ if (keys.length === 0)
293
+ return { args: {} };
294
+ return { args: { request: params } };
295
+ }
175
296
  export function encodeClientRequest(method, payload, rpcId = randomUUID()) {
176
- return { type: 'client-request', rpcId, method, payload };
297
+ const endpoint = normalizeRpcEndpoint(method);
298
+ return { type: 'client-request', rpcId, method: endpoint, payload: wrapRemoteArgs(payload) };
177
299
  }
178
300
  export function unwrapRpc(body) {
179
301
  if (typeof body !== 'object' || body === null)
@@ -587,11 +709,21 @@ export function historyEvents(body) {
587
709
  if (typeof unwrapped !== 'object' || unwrapped === null)
588
710
  return [];
589
711
  const rec = unwrapped;
590
- const raw = Array.isArray(rec.events) ? rec.events
591
- : Array.isArray(rec.messages) ? rec.messages
592
- : Array.isArray(rec.items) ? rec.items
593
- : Array.isArray(rec.log) ? rec.log
594
- : [];
712
+ // 0.1.5 session/page → { records: [{ type:'event', event }] }
713
+ const fromRecords = Array.isArray(rec.records)
714
+ ? rec.records.map((row) => {
715
+ if (typeof row === 'object' && row !== null && row.type === 'event') {
716
+ return row.event ?? row;
717
+ }
718
+ return row;
719
+ })
720
+ : undefined;
721
+ const raw = fromRecords
722
+ ?? (Array.isArray(rec.events) ? rec.events
723
+ : Array.isArray(rec.messages) ? rec.messages
724
+ : Array.isArray(rec.items) ? rec.items
725
+ : Array.isArray(rec.log) ? rec.log
726
+ : []);
595
727
  return raw.map(unwrapHistoryItem);
596
728
  }
597
729
  export function lastAssistantText(events) {
@@ -717,27 +849,61 @@ export function weixinBridgeEnv(opts) {
717
849
  env.DSH_BRIDGE_DSH = opts.launcherPath;
718
850
  env.REZ_WECHAT_SESSION_STORE = env.REZ_WECHAT_SESSION_STORE ?? join(opts.dataDir, 'web-sessions.json');
719
851
  env.REZ_WECHAT_WORKSPACE = env.REZ_WECHAT_WORKSPACE ?? wechatWorkspaceDir(env);
720
- env.REZ_DSH_WEB_URL = env.REZ_DSH_WEB_URL ?? DEFAULT_WEB_URL;
852
+ // Prefer printed/suite URL (port + ?token=); do not force bare :3080 over it.
853
+ if (env.REZ_DSH_WEB_URL === undefined || env.REZ_DSH_WEB_URL.trim() === '') {
854
+ try {
855
+ const printed = readFileSync(dshWebUrlFile(env), 'utf8').trim();
856
+ if (printed.length > 0)
857
+ env.REZ_DSH_WEB_URL = printed;
858
+ }
859
+ catch {
860
+ env.REZ_DSH_WEB_URL = DEFAULT_WEB_URL;
861
+ }
862
+ }
721
863
  return env;
722
864
  }
723
865
  async function sleep(ms) {
724
866
  await new Promise(resolve => setTimeout(resolve, ms));
725
867
  }
726
- export async function postRpc(baseUrl, method, params, timeoutMs = RPC_TIMEOUT_MS) {
727
- const url = `${baseUrl.replace(/\/$/, '')}/api/${method}`;
728
- const envelope = encodeClientRequest(method, params);
729
- let response;
730
- try {
731
- response = await fetch(url, {
868
+ export async function postRpc(baseUrl, method, params, timeoutMs = RPC_TIMEOUT_MS, env = process.env) {
869
+ const origin = (() => {
870
+ try {
871
+ const withScheme = /:\/\//.test(baseUrl) ? baseUrl : `http://${baseUrl}`;
872
+ const url = new URL(withScheme);
873
+ return `${url.protocol}//${url.host}`;
874
+ }
875
+ catch {
876
+ return webBaseUrl(env);
877
+ }
878
+ })();
879
+ const endpoint = normalizeRpcEndpoint(method);
880
+ const url = `${origin}/api/${endpoint}`;
881
+ const envelope = encodeClientRequest(endpoint, params);
882
+ const send = async (cookie) => {
883
+ const headers = { 'content-type': 'application/json' };
884
+ if (cookie !== undefined && cookie.length > 0)
885
+ headers.cookie = cookie;
886
+ return fetch(url, {
732
887
  method: 'POST',
733
- headers: { 'content-type': 'application/json' },
888
+ headers,
734
889
  body: JSON.stringify(envelope),
735
890
  signal: AbortSignal.timeout(timeoutMs),
736
891
  });
892
+ };
893
+ let cookie = await authCookieFor(origin, env);
894
+ let response;
895
+ try {
896
+ response = await send(cookie);
897
+ if (response.status === 401) {
898
+ authCookies.delete(origin);
899
+ cookie = await authCookieFor(origin, env, true);
900
+ if (cookie !== undefined)
901
+ response = await send(cookie);
902
+ }
737
903
  }
738
904
  catch (error) {
739
905
  const why = error instanceof Error ? error.message : String(error);
740
- throw new Error(`连不上本机 dsh web(${baseUrl}):${why}。请保持网页端开着。`);
906
+ throw new Error(`连不上本机 dsh web(${origin}):${why}。请保持网页端开着。`);
741
907
  }
742
908
  const raw = await response.text();
743
909
  let parsed;
@@ -745,6 +911,9 @@ export async function postRpc(baseUrl, method, params, timeoutMs = RPC_TIMEOUT_M
745
911
  parsed = raw === '' ? {} : JSON.parse(raw);
746
912
  }
747
913
  catch {
914
+ if (response.status === 401) {
915
+ throw new Error(`dsh web ${method} 返回 401 unauthorized。请用终端打印的带 ?token= 的完整 URL 打开网页一次,或升级 suite 后确认 ~/.dsh/dsh-web.url 存在。原文: ${raw.slice(0, 160)}`);
916
+ }
748
917
  throw new Error(`dsh web ${method} 返回非 JSON (${response.status}): ${raw.slice(0, 240)}`);
749
918
  }
750
919
  const body = unwrapRpc(parsed);
@@ -758,35 +927,28 @@ async function ensureWorkspace(rpc, cwd) {
758
927
  mkdirSync(cwd, { recursive: true });
759
928
  ensureWechatInboxAgents(cwd);
760
929
  try {
761
- const created = await rpc('workspace.create', { path: cwd });
762
- const id = extractWorkspaceId(created) ?? findWorkspaceId(created, cwd);
763
- if (id !== undefined)
764
- return id;
765
- }
766
- catch {
767
- // create may 409 / invalid-path; list is the reconnect authority
768
- }
769
- try {
770
- return findWorkspaceId(await rpc('workspace.list', {}), cwd);
930
+ // 0.1.5 workspace/create is upsert-like ({ created: boolean }); list RPC is gone.
931
+ const created = await rpc('workspace/create', { path: cwd });
932
+ return extractWorkspaceId(created) ?? findWorkspaceId(created, cwd);
771
933
  }
772
934
  catch {
773
935
  return undefined;
774
936
  }
775
937
  }
776
938
  async function createSession(rpc, cwd, workspaceId) {
777
- // Official session.create accepts at most one of workspaceId / cwd.
778
- // workspaceId is the one that attachSession-s into the 微信 sidebar.
939
+ // Official session/create accepts at most one of workspaceId / cwd.
940
+ // workspaceId is the one that insertSessionBefore-s into the 微信 sidebar.
779
941
  const payload = workspaceId !== undefined ? { workspaceId } : { cwd };
780
- const created = await rpc('session.create', payload);
942
+ const created = await rpc('session/create', payload);
781
943
  const id = extractSessionId(created);
782
944
  if (id === undefined)
783
- throw new Error('session.create 没有返回 sessionId');
945
+ throw new Error('session/create 没有返回 sessionId');
784
946
  return id;
785
947
  }
786
948
  async function maybeSelectModel(rpc, sessionId, env) {
787
949
  let models;
788
950
  try {
789
- models = await rpc('session.models', { sessionId });
951
+ models = await rpc('session/modelCatalog', {});
790
952
  }
791
953
  catch {
792
954
  models = undefined;
@@ -796,7 +958,7 @@ async function maybeSelectModel(rpc, sessionId, env) {
796
958
  return;
797
959
  for (const payload of selectModelPayloads(sessionId, ref)) {
798
960
  try {
799
- await rpc('session.selectModel', payload);
961
+ await rpc('session/selectModel', payload);
800
962
  return;
801
963
  }
802
964
  catch {
@@ -804,15 +966,31 @@ async function maybeSelectModel(rpc, sessionId, env) {
804
966
  }
805
967
  }
806
968
  }
969
+ /** 0.1.5 replaced session.history with session/page. */
970
+ async function fetchSessionHistory(rpc, sessionId, maxMessages = 40) {
971
+ return historyEvents(await rpc('session/page', {
972
+ address: { kind: 'session', sessionId },
973
+ throughSeq: Number.MAX_SAFE_INTEGER,
974
+ maxMessages,
975
+ }));
976
+ }
807
977
  async function sessionAlive(rpc, sessionId) {
808
978
  try {
809
- await rpc('session.history', { sessionId, maxMessages: 1 });
979
+ await fetchSessionHistory(rpc, sessionId, 1);
810
980
  return true;
811
981
  }
812
982
  catch {
813
983
  return false;
814
984
  }
815
985
  }
986
+ function promptPayload(sessionId, text) {
987
+ return {
988
+ requestId: randomUUID(),
989
+ sessionId,
990
+ mode: 'queue',
991
+ content: [{ type: 'text', text }],
992
+ };
993
+ }
816
994
  export function extractArchivedSessionIds(body) {
817
995
  const unwrapped = unwrapRpc(body);
818
996
  if (typeof unwrapped !== 'object' || unwrapped === null)
@@ -840,15 +1018,19 @@ async function tryRpc(rpc, method, params) {
840
1018
  }
841
1019
  /** Stock dsh archives one-way and hides blank sessions. Restore + attach + title. */
842
1020
  export async function ensureSessionVisible(rpc, sessionId, env = process.env, workspaceId, loopback = true) {
843
- await tryRpc(rpc, 'workspace.unarchiveSession', { sessionId });
844
- await tryRpc(rpc, 'session.unarchive', { sessionId });
1021
+ // 0.1.5 dropped unarchive/attach RPCs; insertSessionBefore is the sidebar join.
845
1022
  if (loopback) {
846
1023
  const workspacePath = wechatWorkspaceDir(env);
847
- const url = `${webBaseUrl(env)}/api/dsh-rez-suite/weixin/unarchive`;
1024
+ const origin = webBaseUrl(env);
1025
+ const url = `${origin}/api/dsh-rez-suite/weixin/unarchive`;
848
1026
  try {
1027
+ const headers = { 'content-type': 'application/json' };
1028
+ const cookie = await authCookieFor(origin, env);
1029
+ if (cookie !== undefined)
1030
+ headers.cookie = cookie;
849
1031
  await fetch(url, {
850
1032
  method: 'POST',
851
- headers: { 'content-type': 'application/json' },
1033
+ headers,
852
1034
  body: JSON.stringify({ sessionId, workspacePath }),
853
1035
  signal: AbortSignal.timeout(3000),
854
1036
  });
@@ -858,17 +1040,16 @@ export async function ensureSessionVisible(rpc, sessionId, env = process.env, wo
858
1040
  }
859
1041
  }
860
1042
  if (workspaceId !== undefined) {
861
- await tryRpc(rpc, 'workspace.attachSession', { workspaceId, sessionId });
862
- await tryRpc(rpc, 'workspace.insertSessionBefore', { workspaceId, sessionId });
1043
+ await tryRpc(rpc, 'workspace/insertSessionBefore', { workspaceId, sessionId });
863
1044
  }
864
1045
  const title = basename(wechatWorkspaceDir(env)) || WECHAT_WORKSPACE_NAME;
865
- await tryRpc(rpc, 'session.rename', { sessionId, title });
1046
+ await tryRpc(rpc, 'session/rename', { sessionId, title });
866
1047
  }
867
1048
  async function archiveSession(rpc, sessionId) {
868
- await tryRpc(rpc, 'workspace.archiveSession', { sessionId });
1049
+ await tryRpc(rpc, 'workspace/archiveSession', { sessionId });
869
1050
  }
870
1051
  async function abortSessionTurn(rpc, sessionId) {
871
- for (const method of ['session.abort', 'session.cancel', 'session.stop', 'session.interrupt']) {
1052
+ for (const method of ['session/cancel', 'session/abort', 'session/stop', 'session/interrupt']) {
872
1053
  if (await tryRpc(rpc, method, { sessionId }))
873
1054
  return;
874
1055
  }
@@ -898,7 +1079,7 @@ async function tryAnswerPendingQuestion(rpc, sessionId, choice) {
898
1079
  { sessionId, answer },
899
1080
  { sessionId, answers: answer.answers },
900
1081
  ];
901
- for (const method of ['question.respond', 'session.respondQuestion']) {
1082
+ for (const method of ['question/respond', 'session/respondQuestion']) {
902
1083
  for (const params of payloads) {
903
1084
  if (await tryRpcQuick(rpc, method, params))
904
1085
  return true;
@@ -923,7 +1104,7 @@ async function waitForAssistant(rpc, sessionId, beforeText, timeoutMs, ignorePen
923
1104
  while (Date.now() < deadline) {
924
1105
  let events = [];
925
1106
  try {
926
- events = historyEvents(await rpc('session.history', { sessionId, maxMessages: 40 }));
1107
+ events = await fetchSessionHistory(rpc, sessionId, 40);
927
1108
  }
928
1109
  catch {
929
1110
  events = [];
@@ -994,7 +1175,7 @@ export async function runHeadlessViaWeb(opts) {
994
1175
  let before = '';
995
1176
  let events = [];
996
1177
  try {
997
- events = historyEvents(await rpc('session.history', { sessionId, maxMessages: 40 }));
1178
+ events = await fetchSessionHistory(rpc, sessionId, 40);
998
1179
  before = usableAssistantText(lastAssistantText(events));
999
1180
  }
1000
1181
  catch {
@@ -1013,11 +1194,7 @@ export async function runHeadlessViaWeb(opts) {
1013
1194
  const answered = await tryAnswerPendingQuestion(rpc, sessionId, choice);
1014
1195
  if (!answered) {
1015
1196
  await abortSessionTurn(rpc, sessionId);
1016
- await rpc('session.prompt', {
1017
- sessionId,
1018
- mode: 'queue',
1019
- content: [{ type: 'text', text: `用户在微信选择了:${choice.label}` }],
1020
- });
1197
+ await rpc('session/prompt', promptPayload(sessionId, `用户在微信选择了:${choice.label}`));
1021
1198
  }
1022
1199
  skipUserPrompt = true;
1023
1200
  }
@@ -1026,11 +1203,7 @@ export async function runHeadlessViaWeb(opts) {
1026
1203
  if (!turnIsIdle(events) || turnIsBlocked(events)) {
1027
1204
  await abortSessionTurn(rpc, sessionId);
1028
1205
  }
1029
- await rpc('session.prompt', {
1030
- sessionId,
1031
- mode: 'queue',
1032
- content: [{ type: 'text', text: promptText }],
1033
- });
1206
+ await rpc('session/prompt', promptPayload(sessionId, promptText));
1034
1207
  }
1035
1208
  const reply = await waitForAssistant(rpc, sessionId, before, timeoutMs, questions, stuckAck(folder));
1036
1209
  store.sessions[key] = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rezti/dsh-rez-wechat",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
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": {