@rezti/dsh-rez-wechat 0.1.7 → 0.1.8
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 +7 -0
- package/lib/web-shim.js +57 -37
- package/package.json +1 -1
package/lib/web-shim.d.ts
CHANGED
|
@@ -35,9 +35,16 @@ export declare function sessionStorePath(env?: NodeJS.ProcessEnv, home?: string)
|
|
|
35
35
|
export declare function webBaseUrl(env?: NodeJS.ProcessEnv): string;
|
|
36
36
|
export declare function loadSessionStore(path: string): SessionStore;
|
|
37
37
|
export declare function saveSessionStore(path: string, store: SessionStore): void;
|
|
38
|
+
export declare function encodeClientRequest(method: string, payload: Record<string, unknown>, rpcId?: `${string}-${string}-${string}-${string}-${string}`): {
|
|
39
|
+
type: 'client-request';
|
|
40
|
+
rpcId: string;
|
|
41
|
+
method: string;
|
|
42
|
+
payload: Record<string, unknown>;
|
|
43
|
+
};
|
|
38
44
|
export declare function unwrapRpc(body: unknown): unknown;
|
|
39
45
|
export declare function rpcErrorMessage(body: unknown): string | undefined;
|
|
40
46
|
export declare function extractSessionId(body: unknown): string | undefined;
|
|
47
|
+
export declare function extractWorkspaceId(body: unknown): string | undefined;
|
|
41
48
|
export declare function historyEvents(body: unknown): unknown[];
|
|
42
49
|
export declare function lastAssistantText(events: unknown[]): string;
|
|
43
50
|
export declare function turnIsIdle(events: unknown[]): boolean;
|
package/lib/web-shim.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* folder is named 微信, turns continue, and the model follows the web default
|
|
8
8
|
* (Kimi if that is what the user selected).
|
|
9
9
|
*/
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
10
11
|
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
12
|
import { homedir } from 'node:os';
|
|
12
13
|
import { basename, dirname, join } from 'node:path';
|
|
@@ -70,10 +71,19 @@ export function saveSessionStore(path, store) {
|
|
|
70
71
|
mkdirSync(dirname(path), { recursive: true });
|
|
71
72
|
writeFileSync(path, JSON.stringify(store, null, 2), 'utf8');
|
|
72
73
|
}
|
|
74
|
+
export function encodeClientRequest(method, payload, rpcId = randomUUID()) {
|
|
75
|
+
return { type: 'client-request', rpcId, method, payload };
|
|
76
|
+
}
|
|
73
77
|
export function unwrapRpc(body) {
|
|
74
78
|
if (typeof body !== 'object' || body === null)
|
|
75
79
|
return body;
|
|
76
80
|
const rec = body;
|
|
81
|
+
if (rec.type === 'server-response' && typeof rec.result === 'object' && rec.result !== null) {
|
|
82
|
+
const result = rec.result;
|
|
83
|
+
if (result.ok === true)
|
|
84
|
+
return result.value;
|
|
85
|
+
return rec.result;
|
|
86
|
+
}
|
|
77
87
|
if (rec.error !== undefined)
|
|
78
88
|
return rec;
|
|
79
89
|
if (typeof rec.result === 'object' && rec.result !== null)
|
|
@@ -116,6 +126,21 @@ export function extractSessionId(body) {
|
|
|
116
126
|
}
|
|
117
127
|
return undefined;
|
|
118
128
|
}
|
|
129
|
+
export function extractWorkspaceId(body) {
|
|
130
|
+
if (typeof body !== 'object' || body === null)
|
|
131
|
+
return undefined;
|
|
132
|
+
const rec = body;
|
|
133
|
+
if (typeof rec.workspaceId === 'string')
|
|
134
|
+
return rec.workspaceId;
|
|
135
|
+
if (typeof rec.workspace === 'object' && rec.workspace !== null) {
|
|
136
|
+
const nested = rec.workspace;
|
|
137
|
+
if (typeof nested.workspaceId === 'string')
|
|
138
|
+
return nested.workspaceId;
|
|
139
|
+
if (typeof nested.id === 'string')
|
|
140
|
+
return nested.id;
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
119
144
|
function flattenText(content) {
|
|
120
145
|
if (typeof content === 'string')
|
|
121
146
|
return content;
|
|
@@ -134,22 +159,25 @@ function flattenText(content) {
|
|
|
134
159
|
})
|
|
135
160
|
.join('');
|
|
136
161
|
}
|
|
162
|
+
function unwrapHistoryItem(item) {
|
|
163
|
+
if (typeof item !== 'object' || item === null)
|
|
164
|
+
return item;
|
|
165
|
+
const rec = item;
|
|
166
|
+
return rec.event ?? item;
|
|
167
|
+
}
|
|
137
168
|
export function historyEvents(body) {
|
|
138
169
|
const unwrapped = unwrapRpc(body);
|
|
139
170
|
if (Array.isArray(unwrapped))
|
|
140
|
-
return unwrapped;
|
|
171
|
+
return unwrapped.map(unwrapHistoryItem);
|
|
141
172
|
if (typeof unwrapped !== 'object' || unwrapped === null)
|
|
142
173
|
return [];
|
|
143
174
|
const rec = unwrapped;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (Array.isArray(rec.log))
|
|
151
|
-
return rec.log;
|
|
152
|
-
return [];
|
|
175
|
+
const raw = Array.isArray(rec.events) ? rec.events
|
|
176
|
+
: Array.isArray(rec.messages) ? rec.messages
|
|
177
|
+
: Array.isArray(rec.items) ? rec.items
|
|
178
|
+
: Array.isArray(rec.log) ? rec.log
|
|
179
|
+
: [];
|
|
180
|
+
return raw.map(unwrapHistoryItem);
|
|
153
181
|
}
|
|
154
182
|
export function lastAssistantText(events) {
|
|
155
183
|
let text = '';
|
|
@@ -197,12 +225,14 @@ function collectModelRows(input, out, depth = 0, inheritedProvider) {
|
|
|
197
225
|
if (typeof input !== 'object')
|
|
198
226
|
return;
|
|
199
227
|
const rec = input;
|
|
228
|
+
const isGroup = Array.isArray(rec.models);
|
|
229
|
+
const groupProvider = isGroup && typeof rec.id === 'string' ? rec.id : inheritedProvider;
|
|
200
230
|
const provider = typeof rec.provider === 'string' ? rec.provider
|
|
201
231
|
: typeof rec.providerID === 'string' ? rec.providerID
|
|
202
232
|
: typeof rec.adapter === 'string' ? rec.adapter
|
|
203
|
-
:
|
|
233
|
+
: groupProvider;
|
|
204
234
|
const model = typeof rec.model === 'string' ? rec.model
|
|
205
|
-
: typeof rec.id === 'string' && !rec.id.startsWith('session') ? rec.id
|
|
235
|
+
: !isGroup && typeof rec.id === 'string' && !rec.id.startsWith('session') ? rec.id
|
|
206
236
|
: undefined;
|
|
207
237
|
if (model !== undefined)
|
|
208
238
|
out.push(provider !== undefined ? { provider, model } : { model });
|
|
@@ -250,12 +280,9 @@ export function pickWechatModel(models, env = process.env) {
|
|
|
250
280
|
return coding ?? kimi[0];
|
|
251
281
|
}
|
|
252
282
|
export function selectModelPayloads(sessionId, ref) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
{ sessionId, model: ref },
|
|
257
|
-
];
|
|
258
|
-
return payloads;
|
|
283
|
+
if (ref.provider === undefined)
|
|
284
|
+
return [];
|
|
285
|
+
return [{ sessionId, provider: ref.provider, model: ref.model }];
|
|
259
286
|
}
|
|
260
287
|
export function writeWeixinDshLauncher(opts) {
|
|
261
288
|
mkdirSync(opts.dataDir, { recursive: true });
|
|
@@ -283,12 +310,13 @@ async function sleep(ms) {
|
|
|
283
310
|
}
|
|
284
311
|
export async function postRpc(baseUrl, method, params) {
|
|
285
312
|
const url = `${baseUrl.replace(/\/$/, '')}/api/${method}`;
|
|
313
|
+
const envelope = encodeClientRequest(method, params);
|
|
286
314
|
let response;
|
|
287
315
|
try {
|
|
288
316
|
response = await fetch(url, {
|
|
289
317
|
method: 'POST',
|
|
290
318
|
headers: { 'content-type': 'application/json' },
|
|
291
|
-
body: JSON.stringify(
|
|
319
|
+
body: JSON.stringify(envelope),
|
|
292
320
|
});
|
|
293
321
|
}
|
|
294
322
|
catch (error) {
|
|
@@ -312,10 +340,12 @@ export async function postRpc(baseUrl, method, params) {
|
|
|
312
340
|
}
|
|
313
341
|
async function ensureWorkspace(rpc, cwd) {
|
|
314
342
|
mkdirSync(cwd, { recursive: true });
|
|
315
|
-
await rpc('workspace.create', { path: cwd
|
|
343
|
+
const created = await rpc('workspace.create', { path: cwd });
|
|
344
|
+
return extractWorkspaceId(created);
|
|
316
345
|
}
|
|
317
|
-
async function createSession(rpc, cwd) {
|
|
318
|
-
const
|
|
346
|
+
async function createSession(rpc, cwd, workspaceId) {
|
|
347
|
+
const payload = workspaceId !== undefined ? { workspaceId } : { cwd };
|
|
348
|
+
const created = await rpc('session.create', payload);
|
|
319
349
|
const id = extractSessionId(created);
|
|
320
350
|
if (id === undefined)
|
|
321
351
|
throw new Error('session.create 没有返回 sessionId');
|
|
@@ -348,13 +378,7 @@ async function sessionAlive(rpc, sessionId) {
|
|
|
348
378
|
return true;
|
|
349
379
|
}
|
|
350
380
|
catch {
|
|
351
|
-
|
|
352
|
-
await rpc('session.get', { sessionId });
|
|
353
|
-
return true;
|
|
354
|
-
}
|
|
355
|
-
catch {
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
381
|
+
return false;
|
|
358
382
|
}
|
|
359
383
|
}
|
|
360
384
|
async function waitForAssistant(rpc, sessionId, beforeText, timeoutMs) {
|
|
@@ -367,12 +391,7 @@ async function waitForAssistant(rpc, sessionId, beforeText, timeoutMs) {
|
|
|
367
391
|
events = historyEvents(await rpc('session.history', { sessionId, maxMessages: 40 }));
|
|
368
392
|
}
|
|
369
393
|
catch {
|
|
370
|
-
|
|
371
|
-
events = historyEvents(await rpc('session.get', { sessionId }));
|
|
372
|
-
}
|
|
373
|
-
catch {
|
|
374
|
-
events = [];
|
|
375
|
-
}
|
|
394
|
+
events = [];
|
|
376
395
|
}
|
|
377
396
|
const text = lastAssistantText(events);
|
|
378
397
|
if (text !== '')
|
|
@@ -400,7 +419,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
400
419
|
const key = basename(opts.cwd ?? process.cwd()) || 'default';
|
|
401
420
|
const rpc = opts.rpc ?? ((method, params) => postRpc(webBaseUrl(env), method, params));
|
|
402
421
|
const timeoutMs = opts.timeoutMs ?? Number(env.DSH_BRIDGE_TIMEOUT_MS ?? 10 * 60 * 1000);
|
|
403
|
-
await ensureWorkspace(rpc, workspace);
|
|
422
|
+
const workspaceId = await ensureWorkspace(rpc, workspace);
|
|
404
423
|
const store = loadSessionStore(storeFile);
|
|
405
424
|
let sessionId = store.sessions[key]?.sessionId;
|
|
406
425
|
const fresh = isFreshBridgeTurn(opts.task);
|
|
@@ -413,7 +432,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
413
432
|
sessionId = undefined;
|
|
414
433
|
}
|
|
415
434
|
if (sessionId === undefined) {
|
|
416
|
-
sessionId = await createSession(rpc, workspace);
|
|
435
|
+
sessionId = await createSession(rpc, workspace, workspaceId);
|
|
417
436
|
await maybeSelectModel(rpc, sessionId, env);
|
|
418
437
|
}
|
|
419
438
|
store.sessions[key] = { sessionId, updatedAt: Date.now() };
|
|
@@ -427,6 +446,7 @@ export async function runHeadlessViaWeb(opts) {
|
|
|
427
446
|
}
|
|
428
447
|
await rpc('session.prompt', {
|
|
429
448
|
sessionId,
|
|
449
|
+
mode: 'queue',
|
|
430
450
|
content: [{ type: 'text', text }],
|
|
431
451
|
});
|
|
432
452
|
return await waitForAssistant(rpc, sessionId, before, timeoutMs);
|
package/package.json
CHANGED