@hermespilot/link 0.8.0 → 0.8.1-beta.1
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/{chunk-GHZLIFQF.js → chunk-WYVLVDXH.js} +1426 -249
- package/dist/cli/index.js +175 -9
- package/dist/http/app.d.ts +1 -0
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import Router from "@koa/router";
|
|
|
4
4
|
|
|
5
5
|
// src/conversations/conversation-service.ts
|
|
6
6
|
import { EventEmitter } from "events";
|
|
7
|
-
import { createHash as
|
|
7
|
+
import { createHash as createHash8, randomUUID as randomUUID12 } from "crypto";
|
|
8
8
|
import path26 from "path";
|
|
9
9
|
|
|
10
10
|
// src/database/link-database.ts
|
|
@@ -151,6 +151,62 @@ var MIGRATIONS = [
|
|
|
151
151
|
OR message_count > 0
|
|
152
152
|
OR run_count > 0;
|
|
153
153
|
`
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
version: 4,
|
|
157
|
+
name: "live_activity_registry",
|
|
158
|
+
sql: `
|
|
159
|
+
CREATE TABLE IF NOT EXISTS live_activities (
|
|
160
|
+
activity_id TEXT PRIMARY KEY,
|
|
161
|
+
activity_token TEXT NOT NULL,
|
|
162
|
+
apns_environment TEXT NOT NULL CHECK (apns_environment IN ('sandbox', 'production')),
|
|
163
|
+
apns_topic TEXT NOT NULL,
|
|
164
|
+
link_id TEXT NOT NULL,
|
|
165
|
+
account_id TEXT,
|
|
166
|
+
app_instance_id TEXT NOT NULL,
|
|
167
|
+
conversation_id TEXT NOT NULL,
|
|
168
|
+
conversation_title TEXT,
|
|
169
|
+
target_kind TEXT NOT NULL CHECK (target_kind IN ('run', 'context_compression')),
|
|
170
|
+
target_id TEXT NOT NULL,
|
|
171
|
+
run_id TEXT,
|
|
172
|
+
operation_id TEXT,
|
|
173
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'ended', 'expired', 'invalid')),
|
|
174
|
+
language TEXT CHECK (language IS NULL OR language IN ('zh', 'en')),
|
|
175
|
+
privacy_level TEXT NOT NULL DEFAULT 'summary'
|
|
176
|
+
CHECK (privacy_level IN ('minimal', 'summary', 'detailed')),
|
|
177
|
+
last_phase TEXT,
|
|
178
|
+
last_summary_hash TEXT,
|
|
179
|
+
last_pushed_at TEXT,
|
|
180
|
+
push_count INTEGER NOT NULL DEFAULT 0,
|
|
181
|
+
started_at TEXT NOT NULL,
|
|
182
|
+
ended_at TEXT,
|
|
183
|
+
created_at TEXT NOT NULL,
|
|
184
|
+
updated_at TEXT NOT NULL,
|
|
185
|
+
CHECK (
|
|
186
|
+
(target_kind = 'run' AND run_id IS NOT NULL AND operation_id IS NULL)
|
|
187
|
+
OR
|
|
188
|
+
(target_kind = 'context_compression' AND operation_id IS NOT NULL AND run_id IS NULL)
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_live_activities_target_active
|
|
193
|
+
ON live_activities(app_instance_id, conversation_id, target_kind, target_id)
|
|
194
|
+
WHERE status = 'active';
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_live_activities_target_lookup
|
|
196
|
+
ON live_activities(conversation_id, target_kind, target_id, status);
|
|
197
|
+
CREATE INDEX IF NOT EXISTS idx_live_activities_status_updated
|
|
198
|
+
ON live_activities(status, updated_at);
|
|
199
|
+
`
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
version: 5,
|
|
203
|
+
name: "live_activity_visible_state",
|
|
204
|
+
sql: `
|
|
205
|
+
ALTER TABLE live_activities ADD COLUMN last_status_label TEXT;
|
|
206
|
+
ALTER TABLE live_activities ADD COLUMN last_progress_text TEXT;
|
|
207
|
+
ALTER TABLE live_activities ADD COLUMN last_detail_text TEXT;
|
|
208
|
+
ALTER TABLE live_activities ADD COLUMN last_visible_updated_at TEXT;
|
|
209
|
+
`
|
|
154
210
|
}
|
|
155
211
|
];
|
|
156
212
|
async function migrateLinkDatabase(paths) {
|
|
@@ -229,6 +285,245 @@ async function upsertConversationStats(paths, record) {
|
|
|
229
285
|
db.close();
|
|
230
286
|
}
|
|
231
287
|
}
|
|
288
|
+
async function upsertLiveActivity(paths, input) {
|
|
289
|
+
await migrateLinkDatabase(paths);
|
|
290
|
+
const db = openDatabase(paths);
|
|
291
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
292
|
+
try {
|
|
293
|
+
db.exec("BEGIN IMMEDIATE");
|
|
294
|
+
try {
|
|
295
|
+
const restoreState = readLiveActivityRestoreStateForTarget(db, {
|
|
296
|
+
accountId: input.accountId,
|
|
297
|
+
appInstanceId: input.appInstanceId,
|
|
298
|
+
conversationId: input.conversationId,
|
|
299
|
+
targetKind: input.targetKind,
|
|
300
|
+
targetId: input.targetId
|
|
301
|
+
});
|
|
302
|
+
db.prepare(
|
|
303
|
+
`
|
|
304
|
+
UPDATE live_activities
|
|
305
|
+
SET status = 'expired',
|
|
306
|
+
ended_at = COALESCE(ended_at, ?),
|
|
307
|
+
updated_at = ?
|
|
308
|
+
WHERE app_instance_id = ?
|
|
309
|
+
AND activity_id != ?
|
|
310
|
+
AND status = 'active'
|
|
311
|
+
`
|
|
312
|
+
).run(now, now, input.appInstanceId, input.activityId);
|
|
313
|
+
db.prepare(
|
|
314
|
+
`
|
|
315
|
+
INSERT INTO live_activities (
|
|
316
|
+
activity_id,
|
|
317
|
+
activity_token,
|
|
318
|
+
apns_environment,
|
|
319
|
+
apns_topic,
|
|
320
|
+
link_id,
|
|
321
|
+
account_id,
|
|
322
|
+
app_instance_id,
|
|
323
|
+
conversation_id,
|
|
324
|
+
conversation_title,
|
|
325
|
+
target_kind,
|
|
326
|
+
target_id,
|
|
327
|
+
run_id,
|
|
328
|
+
operation_id,
|
|
329
|
+
status,
|
|
330
|
+
language,
|
|
331
|
+
privacy_level,
|
|
332
|
+
last_phase,
|
|
333
|
+
last_summary_hash,
|
|
334
|
+
last_pushed_at,
|
|
335
|
+
last_status_label,
|
|
336
|
+
last_progress_text,
|
|
337
|
+
last_detail_text,
|
|
338
|
+
last_visible_updated_at,
|
|
339
|
+
push_count,
|
|
340
|
+
started_at,
|
|
341
|
+
ended_at,
|
|
342
|
+
created_at,
|
|
343
|
+
updated_at
|
|
344
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', ?, ?, ?, NULL, NULL, ?, ?, ?, ?, 0, ?, NULL, ?, ?)
|
|
345
|
+
ON CONFLICT(activity_id) DO UPDATE SET
|
|
346
|
+
activity_token = excluded.activity_token,
|
|
347
|
+
apns_environment = excluded.apns_environment,
|
|
348
|
+
apns_topic = excluded.apns_topic,
|
|
349
|
+
link_id = excluded.link_id,
|
|
350
|
+
account_id = excluded.account_id,
|
|
351
|
+
app_instance_id = excluded.app_instance_id,
|
|
352
|
+
conversation_id = excluded.conversation_id,
|
|
353
|
+
conversation_title = excluded.conversation_title,
|
|
354
|
+
target_kind = excluded.target_kind,
|
|
355
|
+
target_id = excluded.target_id,
|
|
356
|
+
run_id = excluded.run_id,
|
|
357
|
+
operation_id = excluded.operation_id,
|
|
358
|
+
status = 'active',
|
|
359
|
+
language = excluded.language,
|
|
360
|
+
privacy_level = excluded.privacy_level,
|
|
361
|
+
last_phase = excluded.last_phase,
|
|
362
|
+
last_summary_hash = NULL,
|
|
363
|
+
last_pushed_at = NULL,
|
|
364
|
+
last_status_label = excluded.last_status_label,
|
|
365
|
+
last_progress_text = excluded.last_progress_text,
|
|
366
|
+
last_detail_text = excluded.last_detail_text,
|
|
367
|
+
last_visible_updated_at = excluded.last_visible_updated_at,
|
|
368
|
+
push_count = 0,
|
|
369
|
+
started_at = excluded.started_at,
|
|
370
|
+
ended_at = NULL,
|
|
371
|
+
updated_at = excluded.updated_at
|
|
372
|
+
`
|
|
373
|
+
).run(
|
|
374
|
+
input.activityId,
|
|
375
|
+
input.activityToken,
|
|
376
|
+
input.apnsEnvironment,
|
|
377
|
+
input.apnsTopic,
|
|
378
|
+
input.linkId,
|
|
379
|
+
input.accountId ?? null,
|
|
380
|
+
input.appInstanceId,
|
|
381
|
+
input.conversationId,
|
|
382
|
+
input.conversationTitle ?? null,
|
|
383
|
+
input.targetKind,
|
|
384
|
+
input.targetId,
|
|
385
|
+
input.runId ?? null,
|
|
386
|
+
input.operationId ?? null,
|
|
387
|
+
input.language ?? null,
|
|
388
|
+
input.privacyLevel ?? "summary",
|
|
389
|
+
restoreState?.phase ?? "connecting",
|
|
390
|
+
restoreState?.statusLabel ?? null,
|
|
391
|
+
restoreState?.progressText ?? null,
|
|
392
|
+
restoreState?.detailText ?? null,
|
|
393
|
+
restoreState?.updatedAt ?? null,
|
|
394
|
+
input.startedAt,
|
|
395
|
+
now,
|
|
396
|
+
now
|
|
397
|
+
);
|
|
398
|
+
db.exec("COMMIT");
|
|
399
|
+
} catch (error) {
|
|
400
|
+
rollback(db);
|
|
401
|
+
throw error;
|
|
402
|
+
}
|
|
403
|
+
const row = readLiveActivityRow(db, input.activityId);
|
|
404
|
+
if (!row) {
|
|
405
|
+
throw new Error("Live Activity was not persisted");
|
|
406
|
+
}
|
|
407
|
+
return row;
|
|
408
|
+
} finally {
|
|
409
|
+
db.close();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async function findActiveLiveActivityForTarget(paths, input) {
|
|
413
|
+
await migrateLinkDatabase(paths);
|
|
414
|
+
const db = openDatabase(paths);
|
|
415
|
+
try {
|
|
416
|
+
const accountFilter = input.accountId ? "AND account_id = ?" : "";
|
|
417
|
+
const appInstanceFilter = input.appInstanceId ? "AND app_instance_id = ?" : "";
|
|
418
|
+
const row = db.prepare(
|
|
419
|
+
`
|
|
420
|
+
SELECT *
|
|
421
|
+
FROM live_activities
|
|
422
|
+
WHERE conversation_id = ?
|
|
423
|
+
AND target_kind = ?
|
|
424
|
+
AND target_id = ?
|
|
425
|
+
AND status = 'active'
|
|
426
|
+
${accountFilter}
|
|
427
|
+
${appInstanceFilter}
|
|
428
|
+
ORDER BY datetime(started_at) DESC
|
|
429
|
+
LIMIT 1
|
|
430
|
+
`
|
|
431
|
+
).get(
|
|
432
|
+
input.conversationId,
|
|
433
|
+
input.targetKind,
|
|
434
|
+
input.targetId,
|
|
435
|
+
...input.accountId ? [input.accountId] : [],
|
|
436
|
+
...input.appInstanceId ? [input.appInstanceId] : []
|
|
437
|
+
);
|
|
438
|
+
return liveActivityFromRow(row);
|
|
439
|
+
} finally {
|
|
440
|
+
db.close();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
async function findLiveActivityRestoreState(paths, input) {
|
|
444
|
+
await migrateLinkDatabase(paths);
|
|
445
|
+
const db = openDatabase(paths);
|
|
446
|
+
try {
|
|
447
|
+
return readLiveActivityRestoreStateForTarget(db, input);
|
|
448
|
+
} finally {
|
|
449
|
+
db.close();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
async function endLiveActivity(paths, activityId) {
|
|
453
|
+
await migrateLinkDatabase(paths);
|
|
454
|
+
const db = openDatabase(paths);
|
|
455
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
456
|
+
try {
|
|
457
|
+
const result = db.prepare(
|
|
458
|
+
`
|
|
459
|
+
UPDATE live_activities
|
|
460
|
+
SET status = 'ended',
|
|
461
|
+
ended_at = COALESCE(ended_at, ?),
|
|
462
|
+
updated_at = ?
|
|
463
|
+
WHERE activity_id = ?
|
|
464
|
+
`
|
|
465
|
+
).run(now, now, activityId);
|
|
466
|
+
return result.changes > 0;
|
|
467
|
+
} finally {
|
|
468
|
+
db.close();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async function updateLiveActivityPushState(paths, input) {
|
|
472
|
+
await migrateLinkDatabase(paths);
|
|
473
|
+
const db = openDatabase(paths);
|
|
474
|
+
try {
|
|
475
|
+
db.prepare(
|
|
476
|
+
`
|
|
477
|
+
UPDATE live_activities
|
|
478
|
+
SET last_phase = ?,
|
|
479
|
+
last_summary_hash = ?,
|
|
480
|
+
last_pushed_at = ?,
|
|
481
|
+
last_status_label = ?,
|
|
482
|
+
last_progress_text = ?,
|
|
483
|
+
last_detail_text = ?,
|
|
484
|
+
last_visible_updated_at = ?,
|
|
485
|
+
push_count = push_count + 1,
|
|
486
|
+
status = CASE WHEN ? THEN 'ended' ELSE status END,
|
|
487
|
+
ended_at = CASE WHEN ? THEN COALESCE(ended_at, ?) ELSE ended_at END,
|
|
488
|
+
updated_at = ?
|
|
489
|
+
WHERE activity_id = ?
|
|
490
|
+
`
|
|
491
|
+
).run(
|
|
492
|
+
input.phase,
|
|
493
|
+
input.summaryHash,
|
|
494
|
+
input.pushedAt,
|
|
495
|
+
normalizeNullableText(input.statusLabel),
|
|
496
|
+
normalizeNullableText(input.progressText),
|
|
497
|
+
normalizeNullableText(input.detailText),
|
|
498
|
+
input.visibleUpdatedAt,
|
|
499
|
+
input.terminal ? 1 : 0,
|
|
500
|
+
input.terminal ? 1 : 0,
|
|
501
|
+
input.pushedAt,
|
|
502
|
+
input.pushedAt,
|
|
503
|
+
input.activityId
|
|
504
|
+
);
|
|
505
|
+
} finally {
|
|
506
|
+
db.close();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
async function invalidateLiveActivity(paths, activityId) {
|
|
510
|
+
await migrateLinkDatabase(paths);
|
|
511
|
+
const db = openDatabase(paths);
|
|
512
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
513
|
+
try {
|
|
514
|
+
db.prepare(
|
|
515
|
+
`
|
|
516
|
+
UPDATE live_activities
|
|
517
|
+
SET status = 'invalid',
|
|
518
|
+
ended_at = COALESCE(ended_at, ?),
|
|
519
|
+
updated_at = ?
|
|
520
|
+
WHERE activity_id = ?
|
|
521
|
+
`
|
|
522
|
+
).run(now, now, activityId);
|
|
523
|
+
} finally {
|
|
524
|
+
db.close();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
232
527
|
async function listConversationStatsPage(paths, input) {
|
|
233
528
|
await migrateLinkDatabase(paths);
|
|
234
529
|
const rawLimit = Number.isFinite(input.limit) ? Math.trunc(input.limit) : 25;
|
|
@@ -975,6 +1270,109 @@ function runUsageFactParams(record) {
|
|
|
975
1270
|
record.updatedAt
|
|
976
1271
|
];
|
|
977
1272
|
}
|
|
1273
|
+
function readLiveActivityRow(db, activityId) {
|
|
1274
|
+
const row = db.prepare("SELECT * FROM live_activities WHERE activity_id = ? LIMIT 1").get(activityId);
|
|
1275
|
+
return liveActivityFromRow(row);
|
|
1276
|
+
}
|
|
1277
|
+
function readLiveActivityRestoreStateForTarget(db, input) {
|
|
1278
|
+
const accountFilter = input.accountId ? "AND (account_id = ? OR account_id IS NULL)" : "";
|
|
1279
|
+
const row = db.prepare(
|
|
1280
|
+
`
|
|
1281
|
+
SELECT *
|
|
1282
|
+
FROM live_activities
|
|
1283
|
+
WHERE app_instance_id = ?
|
|
1284
|
+
AND conversation_id = ?
|
|
1285
|
+
AND target_kind = ?
|
|
1286
|
+
AND target_id = ?
|
|
1287
|
+
AND status IN ('active', 'ended', 'expired')
|
|
1288
|
+
AND last_phase IS NOT NULL
|
|
1289
|
+
AND last_status_label IS NOT NULL
|
|
1290
|
+
AND last_progress_text IS NOT NULL
|
|
1291
|
+
${accountFilter}
|
|
1292
|
+
ORDER BY datetime(COALESCE(last_visible_updated_at, updated_at)) DESC
|
|
1293
|
+
LIMIT 1
|
|
1294
|
+
`
|
|
1295
|
+
).get(
|
|
1296
|
+
input.appInstanceId,
|
|
1297
|
+
input.conversationId,
|
|
1298
|
+
input.targetKind,
|
|
1299
|
+
input.targetId,
|
|
1300
|
+
...input.accountId ? [input.accountId] : []
|
|
1301
|
+
);
|
|
1302
|
+
return liveActivityRestoreStateFromRow(row);
|
|
1303
|
+
}
|
|
1304
|
+
function liveActivityFromRow(row) {
|
|
1305
|
+
const activityId = readString(row, "activity_id");
|
|
1306
|
+
const activityToken = readString(row, "activity_token");
|
|
1307
|
+
const apnsEnvironment = readString(row, "apns_environment");
|
|
1308
|
+
const apnsTopic = readString(row, "apns_topic");
|
|
1309
|
+
const linkId = readString(row, "link_id");
|
|
1310
|
+
const appInstanceId = readString(row, "app_instance_id");
|
|
1311
|
+
const conversationId = readString(row, "conversation_id");
|
|
1312
|
+
const targetKind = readString(row, "target_kind");
|
|
1313
|
+
const targetId = readString(row, "target_id");
|
|
1314
|
+
const status = readString(row, "status");
|
|
1315
|
+
const startedAt = readString(row, "started_at");
|
|
1316
|
+
const createdAt = readString(row, "created_at");
|
|
1317
|
+
const updatedAt = readString(row, "updated_at");
|
|
1318
|
+
if (!activityId || !activityToken || apnsEnvironment !== "sandbox" && apnsEnvironment !== "production" || !apnsTopic || !linkId || !appInstanceId || !conversationId || targetKind !== "run" && targetKind !== "context_compression" || !targetId || !isLiveActivityStatus(status) || !startedAt || !createdAt || !updatedAt) {
|
|
1319
|
+
return null;
|
|
1320
|
+
}
|
|
1321
|
+
const language = readString(row, "language");
|
|
1322
|
+
const privacyLevel = readString(row, "privacy_level");
|
|
1323
|
+
return {
|
|
1324
|
+
activityId,
|
|
1325
|
+
activityToken,
|
|
1326
|
+
apnsEnvironment,
|
|
1327
|
+
apnsTopic,
|
|
1328
|
+
linkId,
|
|
1329
|
+
accountId: readNullableString(row, "account_id"),
|
|
1330
|
+
appInstanceId,
|
|
1331
|
+
conversationId,
|
|
1332
|
+
conversationTitle: readNullableString(row, "conversation_title"),
|
|
1333
|
+
targetKind,
|
|
1334
|
+
targetId,
|
|
1335
|
+
runId: readNullableString(row, "run_id"),
|
|
1336
|
+
operationId: readNullableString(row, "operation_id"),
|
|
1337
|
+
status,
|
|
1338
|
+
language: language === "zh" || language === "en" ? language : null,
|
|
1339
|
+
privacyLevel: privacyLevel === "minimal" || privacyLevel === "summary" || privacyLevel === "detailed" ? privacyLevel : "summary",
|
|
1340
|
+
lastPhase: readNullableString(row, "last_phase"),
|
|
1341
|
+
lastSummaryHash: readNullableString(row, "last_summary_hash"),
|
|
1342
|
+
lastPushedAt: readNullableString(row, "last_pushed_at"),
|
|
1343
|
+
lastStatusLabel: readNullableString(row, "last_status_label"),
|
|
1344
|
+
lastProgressText: readNullableString(row, "last_progress_text"),
|
|
1345
|
+
lastDetailText: readNullableString(row, "last_detail_text"),
|
|
1346
|
+
lastVisibleUpdatedAt: readNullableString(row, "last_visible_updated_at"),
|
|
1347
|
+
pushCount: readNumber(row, "push_count"),
|
|
1348
|
+
startedAt,
|
|
1349
|
+
endedAt: readNullableString(row, "ended_at"),
|
|
1350
|
+
createdAt,
|
|
1351
|
+
updatedAt
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
function liveActivityRestoreStateFromRow(row) {
|
|
1355
|
+
const phase = readString(row, "last_phase");
|
|
1356
|
+
const statusLabel = readString(row, "last_status_label");
|
|
1357
|
+
const progressText = readString(row, "last_progress_text");
|
|
1358
|
+
if (!phase || !statusLabel || !progressText) {
|
|
1359
|
+
return null;
|
|
1360
|
+
}
|
|
1361
|
+
return {
|
|
1362
|
+
phase,
|
|
1363
|
+
statusLabel,
|
|
1364
|
+
progressText,
|
|
1365
|
+
detailText: readNullableString(row, "last_detail_text"),
|
|
1366
|
+
updatedAt: readNullableString(row, "last_visible_updated_at") ?? readNullableString(row, "updated_at")
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
function isLiveActivityStatus(value) {
|
|
1370
|
+
return value === "active" || value === "ended" || value === "expired" || value === "invalid";
|
|
1371
|
+
}
|
|
1372
|
+
function normalizeNullableText(value) {
|
|
1373
|
+
const trimmed = value?.trim();
|
|
1374
|
+
return trimmed ? trimmed : null;
|
|
1375
|
+
}
|
|
978
1376
|
function rollback(db) {
|
|
979
1377
|
try {
|
|
980
1378
|
db.exec("ROLLBACK");
|
|
@@ -1544,7 +1942,7 @@ var messages = {
|
|
|
1544
1942
|
"autostart.enabled": "Boot autostart enabled via {method}: {path}",
|
|
1545
1943
|
"autostart.disabled": "Boot autostart disabled.",
|
|
1546
1944
|
"autostart.status.enabled": "Boot autostart: enabled via {method}: {path}",
|
|
1547
|
-
"autostart.status.disabled": "Boot autostart: disabled. Method: {method}.
|
|
1945
|
+
"autostart.status.disabled": "Boot autostart: disabled. Method: {method}. Target: {path}",
|
|
1548
1946
|
"autostart.unsupported": "Boot autostart is not supported on this platform yet.",
|
|
1549
1947
|
"autostart.alreadyEnabled": "Boot autostart is already enabled via {method}: {path}",
|
|
1550
1948
|
"pair.description": "Create a Hermes Link pairing session",
|
|
@@ -1787,12 +2185,12 @@ var messages = {
|
|
|
1787
2185
|
"autostart.on.description": "\u542F\u7528\u5F00\u673A\u81EA\u542F",
|
|
1788
2186
|
"autostart.off.description": "\u5173\u95ED\u5F00\u673A\u81EA\u542F",
|
|
1789
2187
|
"autostart.status.description": "\u67E5\u770B\u5F00\u673A\u81EA\u542F\u72B6\u6001",
|
|
1790
|
-
"autostart.enabled": "\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\
|
|
2188
|
+
"autostart.enabled": "\u5DF2\u542F\u7528\u5F00\u673A\u81EA\u542F\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u4F4D\u7F6E\uFF1A{path}",
|
|
1791
2189
|
"autostart.disabled": "\u5DF2\u5173\u95ED\u5F00\u673A\u81EA\u542F\u3002",
|
|
1792
|
-
"autostart.status.enabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\
|
|
1793
|
-
"autostart.status.disabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u672A\u542F\u7528\u3002\u65B9\u5F0F\uFF1A{method}\uFF0C\
|
|
2190
|
+
"autostart.status.enabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u4F4D\u7F6E\uFF1A{path}",
|
|
2191
|
+
"autostart.status.disabled": "\u5F00\u673A\u81EA\u542F\uFF1A\u672A\u542F\u7528\u3002\u65B9\u5F0F\uFF1A{method}\uFF0C\u76EE\u6807\uFF1A{path}",
|
|
1794
2192
|
"autostart.unsupported": "\u5F53\u524D\u5E73\u53F0\u6682\u4E0D\u652F\u6301\u5F00\u673A\u81EA\u542F\u3002",
|
|
1795
|
-
"autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\
|
|
2193
|
+
"autostart.alreadyEnabled": "\u5F00\u673A\u81EA\u542F\u5DF2\u542F\u7528\uFF0C\u65B9\u5F0F\uFF1A{method}\uFF0C\u4F4D\u7F6E\uFF1A{path}",
|
|
1796
2194
|
"pair.description": "\u521B\u5EFA Hermes Link \u914D\u5BF9\u4F1A\u8BDD",
|
|
1797
2195
|
"pair.preflight": "\u6B63\u5728\u914D\u5BF9\u524D\u68C0\u67E5\u672C\u673A Hermes \u914D\u7F6E...",
|
|
1798
2196
|
"pair.preflight.hermesFiles": "\u6B63\u5728\u68C0\u67E5 Hermes \u6570\u636E\u76EE\u5F55\u3001\u914D\u7F6E\u6587\u4EF6\u548C\u73AF\u5883\u6587\u4EF6...",
|
|
@@ -7215,7 +7613,7 @@ function isConversationMissingError(error) {
|
|
|
7215
7613
|
}
|
|
7216
7614
|
|
|
7217
7615
|
// src/constants.ts
|
|
7218
|
-
var LINK_VERSION = "0.8.
|
|
7616
|
+
var LINK_VERSION = "0.8.1-beta.1";
|
|
7219
7617
|
var LINK_COMMAND = "hermeslink";
|
|
7220
7618
|
var LINK_DEFAULT_PORT = 52379;
|
|
7221
7619
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -7526,6 +7924,271 @@ function readErrorMessage(payload) {
|
|
|
7526
7924
|
return typeof message === "string" ? message : null;
|
|
7527
7925
|
}
|
|
7528
7926
|
|
|
7927
|
+
// src/link/live-activity-events.ts
|
|
7928
|
+
import { createHash } from "crypto";
|
|
7929
|
+
var MIN_LIVE_ACTIVITY_PUSH_INTERVAL_MS = 1e3;
|
|
7930
|
+
var liveActivityReportQueues = /* @__PURE__ */ new Map();
|
|
7931
|
+
async function reportLiveActivityEventToServer(options) {
|
|
7932
|
+
const queueKey = liveActivityReportQueueKey(options.event);
|
|
7933
|
+
const previous = liveActivityReportQueues.get(queueKey) ?? Promise.resolve();
|
|
7934
|
+
const next = previous.catch(() => void 0).then(() => reportLiveActivityEventToServerNow(options));
|
|
7935
|
+
liveActivityReportQueues.set(queueKey, next);
|
|
7936
|
+
try {
|
|
7937
|
+
await next;
|
|
7938
|
+
} finally {
|
|
7939
|
+
if (liveActivityReportQueues.get(queueKey) === next) {
|
|
7940
|
+
liveActivityReportQueues.delete(queueKey);
|
|
7941
|
+
}
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
async function reportLiveActivityEventToServerNow(options) {
|
|
7945
|
+
const [identity, config] = await Promise.all([
|
|
7946
|
+
loadIdentity(options.paths),
|
|
7947
|
+
loadConfig(options.paths)
|
|
7948
|
+
]);
|
|
7949
|
+
if (!identity?.link_id) {
|
|
7950
|
+
return;
|
|
7951
|
+
}
|
|
7952
|
+
const activity = await findActiveLiveActivityForTarget(options.paths, {
|
|
7953
|
+
conversationId: options.event.conversationId,
|
|
7954
|
+
targetKind: options.event.targetKind,
|
|
7955
|
+
targetId: options.event.targetId,
|
|
7956
|
+
accountId: options.event.accountId,
|
|
7957
|
+
appInstanceId: options.event.appInstanceId
|
|
7958
|
+
});
|
|
7959
|
+
if (!activity) {
|
|
7960
|
+
return;
|
|
7961
|
+
}
|
|
7962
|
+
const event = liveActivityEventWithInheritedDetail(activity, options.event);
|
|
7963
|
+
const occurredAt = normalizeIso2(options.event.occurredAt) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
7964
|
+
const summaryHash = hashLiveActivitySummary(event);
|
|
7965
|
+
const skipReason = resolveSkipReason(activity, event, summaryHash);
|
|
7966
|
+
if (skipReason) {
|
|
7967
|
+
await options.logger.debug("live_activity_event_skipped", {
|
|
7968
|
+
activity_id: activity.activityId,
|
|
7969
|
+
conversation_id: event.conversationId,
|
|
7970
|
+
target_kind: event.targetKind,
|
|
7971
|
+
target_id: event.targetId,
|
|
7972
|
+
phase: event.phase,
|
|
7973
|
+
reason: skipReason
|
|
7974
|
+
});
|
|
7975
|
+
return;
|
|
7976
|
+
}
|
|
7977
|
+
const reportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7978
|
+
const payload = {
|
|
7979
|
+
type: "hermes_link_live_activity_push",
|
|
7980
|
+
link_id: identity.link_id,
|
|
7981
|
+
install_id: identity.install_id,
|
|
7982
|
+
source_event_id: event.sourceEventId,
|
|
7983
|
+
event_kind: event.eventKind,
|
|
7984
|
+
activity_id: activity.activityId,
|
|
7985
|
+
activity_token: activity.activityToken,
|
|
7986
|
+
apns_environment: activity.apnsEnvironment,
|
|
7987
|
+
apns_topic: activity.apnsTopic,
|
|
7988
|
+
conversation_id: event.conversationId,
|
|
7989
|
+
target_kind: event.targetKind,
|
|
7990
|
+
target_id: event.targetId,
|
|
7991
|
+
phase: event.phase,
|
|
7992
|
+
terminal: event.terminal === true,
|
|
7993
|
+
occurred_at: occurredAt,
|
|
7994
|
+
reported_at: reportedAt
|
|
7995
|
+
};
|
|
7996
|
+
addOptional2(payload, "account_id", activity.accountId ?? event.accountId, 128);
|
|
7997
|
+
addOptional2(payload, "app_instance_id", activity.appInstanceId ?? event.appInstanceId, 128);
|
|
7998
|
+
addOptional2(payload, "run_id", event.runId ?? activity.runId, 128);
|
|
7999
|
+
addOptional2(payload, "operation_id", event.operationId ?? activity.operationId, 128);
|
|
8000
|
+
addOptional2(payload, "conversation_title", event.conversationTitle ?? activity.conversationTitle, 80);
|
|
8001
|
+
addOptional2(payload, "status_label", event.statusLabel, 24);
|
|
8002
|
+
addOptional2(payload, "progress_text", event.progressText, 120);
|
|
8003
|
+
addOptional2(payload, "detail_text", event.detailText, 240);
|
|
8004
|
+
addOptional2(payload, "language", activity.language, 16);
|
|
8005
|
+
addOptional2(payload, "privacy_level", activity.privacyLevel, 32);
|
|
8006
|
+
if (typeof event.requiresUserAction === "boolean") {
|
|
8007
|
+
payload.requires_user_action = event.requiresUserAction;
|
|
8008
|
+
}
|
|
8009
|
+
const signature = signIdentityPayload(identity, canonicalJson2(payload));
|
|
8010
|
+
const fetcher = options.fetchImpl ?? fetch;
|
|
8011
|
+
const response = await fetcher(
|
|
8012
|
+
`${config.serverBaseUrl.replace(/\/+$/u, "")}/api/v1/links/${encodeURIComponent(identity.link_id)}/live-activity-pushes`,
|
|
8013
|
+
{
|
|
8014
|
+
method: "POST",
|
|
8015
|
+
headers: {
|
|
8016
|
+
accept: "application/json",
|
|
8017
|
+
"content-type": "application/json"
|
|
8018
|
+
},
|
|
8019
|
+
body: JSON.stringify({
|
|
8020
|
+
...payload,
|
|
8021
|
+
public_key_pem: identity.public_key_pem,
|
|
8022
|
+
signature
|
|
8023
|
+
})
|
|
8024
|
+
}
|
|
8025
|
+
);
|
|
8026
|
+
const body = await response.json().catch(() => null);
|
|
8027
|
+
if (!response.ok) {
|
|
8028
|
+
const message = readErrorMessage2(body) ?? `HermesPilot Server request failed with HTTP ${response.status}`;
|
|
8029
|
+
throw new LinkHttpError(response.status, "server_request_failed", message);
|
|
8030
|
+
}
|
|
8031
|
+
await updateLiveActivityPushState(options.paths, {
|
|
8032
|
+
activityId: activity.activityId,
|
|
8033
|
+
phase: event.phase,
|
|
8034
|
+
summaryHash,
|
|
8035
|
+
pushedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8036
|
+
visibleUpdatedAt: occurredAt,
|
|
8037
|
+
terminal: event.terminal === true,
|
|
8038
|
+
statusLabel: event.statusLabel,
|
|
8039
|
+
progressText: event.progressText,
|
|
8040
|
+
detailText: event.detailText
|
|
8041
|
+
});
|
|
8042
|
+
const apnsReason = readApnsReason(body);
|
|
8043
|
+
if (apnsReason && shouldInvalidateLiveActivity(apnsReason)) {
|
|
8044
|
+
await invalidateLiveActivity(options.paths, activity.activityId);
|
|
8045
|
+
}
|
|
8046
|
+
}
|
|
8047
|
+
function liveActivityEventWithInheritedDetail(activity, event) {
|
|
8048
|
+
if (isLiveActivityTitleUpdateEvent(event)) {
|
|
8049
|
+
const phase = isLiveActivityPhase(activity.lastPhase) ? activity.lastPhase : event.phase;
|
|
8050
|
+
return {
|
|
8051
|
+
...event,
|
|
8052
|
+
phase,
|
|
8053
|
+
statusLabel: activity.lastStatusLabel?.trim() || event.statusLabel,
|
|
8054
|
+
progressText: activity.lastProgressText?.trim() || event.progressText,
|
|
8055
|
+
detailText: activity.lastDetailText?.trim() || event.detailText
|
|
8056
|
+
};
|
|
8057
|
+
}
|
|
8058
|
+
if (event.detailText?.trim() || !isToolPhase(event.phase)) {
|
|
8059
|
+
return event;
|
|
8060
|
+
}
|
|
8061
|
+
const detailText = activity.lastDetailText?.trim();
|
|
8062
|
+
return detailText ? { ...event, detailText } : event;
|
|
8063
|
+
}
|
|
8064
|
+
function resolveSkipReason(activity, event, summaryHash) {
|
|
8065
|
+
if (shouldThrottleLiveActivityEvent(activity, event)) {
|
|
8066
|
+
return "push_interval_throttled";
|
|
8067
|
+
}
|
|
8068
|
+
if (activity.pushCount >= 60 && event.terminal !== true) {
|
|
8069
|
+
return "push_count_exceeded";
|
|
8070
|
+
}
|
|
8071
|
+
if (activity.lastSummaryHash === summaryHash && event.terminal !== true) {
|
|
8072
|
+
return "duplicate_summary";
|
|
8073
|
+
}
|
|
8074
|
+
if (activity.lastPhase === "context_compression_timed_out" && event.phase === "context_compressed" && activity.targetKind === "context_compression") {
|
|
8075
|
+
return "late_context_compression_completed_after_timeout";
|
|
8076
|
+
}
|
|
8077
|
+
return null;
|
|
8078
|
+
}
|
|
8079
|
+
function shouldThrottleLiveActivityEvent(activity, event) {
|
|
8080
|
+
if (event.terminal === true || event.requiresUserAction === true || event.phase === "needs_input" || event.phase === "needs_approval") {
|
|
8081
|
+
return false;
|
|
8082
|
+
}
|
|
8083
|
+
if (isLiveActivityTitleUpdateEvent(event)) {
|
|
8084
|
+
return false;
|
|
8085
|
+
}
|
|
8086
|
+
const lastVisibleAt = liveActivityLastVisibleTimeMs(activity);
|
|
8087
|
+
if (!Number.isFinite(lastVisibleAt)) {
|
|
8088
|
+
return false;
|
|
8089
|
+
}
|
|
8090
|
+
if (isAssistantProgressEvent(event) && isToolPhase(activity.lastPhase)) {
|
|
8091
|
+
return false;
|
|
8092
|
+
}
|
|
8093
|
+
return liveActivityEventTimeMs(event) - lastVisibleAt < MIN_LIVE_ACTIVITY_PUSH_INTERVAL_MS;
|
|
8094
|
+
}
|
|
8095
|
+
function liveActivityEventTimeMs(event) {
|
|
8096
|
+
const parsed = Date.parse(event.occurredAt ?? "");
|
|
8097
|
+
return Number.isFinite(parsed) ? parsed : Date.now();
|
|
8098
|
+
}
|
|
8099
|
+
function liveActivityLastVisibleTimeMs(activity) {
|
|
8100
|
+
const visible = Date.parse(activity.lastVisibleUpdatedAt ?? "");
|
|
8101
|
+
if (Number.isFinite(visible)) {
|
|
8102
|
+
return visible;
|
|
8103
|
+
}
|
|
8104
|
+
return Date.parse(activity.lastPushedAt ?? "");
|
|
8105
|
+
}
|
|
8106
|
+
function liveActivityReportQueueKey(event) {
|
|
8107
|
+
return [
|
|
8108
|
+
event.accountId?.trim() ?? "",
|
|
8109
|
+
event.appInstanceId?.trim() ?? "",
|
|
8110
|
+
event.conversationId,
|
|
8111
|
+
event.targetKind,
|
|
8112
|
+
event.targetId
|
|
8113
|
+
].join(":");
|
|
8114
|
+
}
|
|
8115
|
+
function isAssistantProgressEvent(event) {
|
|
8116
|
+
return event.eventKind === "reasoning_available";
|
|
8117
|
+
}
|
|
8118
|
+
function isLiveActivityTitleUpdateEvent(event) {
|
|
8119
|
+
return event.eventKind === "conversation_updated" && Boolean(event.conversationTitle?.trim());
|
|
8120
|
+
}
|
|
8121
|
+
function isToolPhase(phase) {
|
|
8122
|
+
return phase === "using_tool" || phase === "tool_completed";
|
|
8123
|
+
}
|
|
8124
|
+
function isLiveActivityPhase(value) {
|
|
8125
|
+
return value === "connecting" || value === "accepted" || value === "running" || value === "using_tool" || value === "tool_completed" || value === "needs_input" || value === "needs_approval" || value === "goal_running" || value === "goal_paused" || value === "context_compressing" || value === "context_compressed" || value === "context_compression_failed" || value === "context_compression_timed_out" || value === "paused" || value === "recovering" || value === "completed" || value === "failed" || value === "cancelled";
|
|
8126
|
+
}
|
|
8127
|
+
function hashLiveActivitySummary(event) {
|
|
8128
|
+
return createHash("sha256").update(
|
|
8129
|
+
[
|
|
8130
|
+
event.phase,
|
|
8131
|
+
event.conversationTitle?.trim() ?? "",
|
|
8132
|
+
event.statusLabel?.trim() ?? "",
|
|
8133
|
+
event.progressText?.trim() ?? "",
|
|
8134
|
+
event.detailText?.trim() ?? "",
|
|
8135
|
+
event.terminal === true ? "terminal" : "update"
|
|
8136
|
+
].join("|")
|
|
8137
|
+
).digest("hex");
|
|
8138
|
+
}
|
|
8139
|
+
function addOptional2(payload, key, value, maxLength) {
|
|
8140
|
+
const normalized = value?.trim();
|
|
8141
|
+
if (normalized) {
|
|
8142
|
+
payload[key] = normalized.slice(0, maxLength);
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
function normalizeIso2(value) {
|
|
8146
|
+
const normalized = value?.trim();
|
|
8147
|
+
if (!normalized) {
|
|
8148
|
+
return null;
|
|
8149
|
+
}
|
|
8150
|
+
const date = new Date(normalized);
|
|
8151
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
8152
|
+
}
|
|
8153
|
+
function canonicalJson2(value) {
|
|
8154
|
+
return JSON.stringify(sortJsonValue2(value));
|
|
8155
|
+
}
|
|
8156
|
+
function sortJsonValue2(value) {
|
|
8157
|
+
if (Array.isArray(value)) {
|
|
8158
|
+
return value.map(sortJsonValue2);
|
|
8159
|
+
}
|
|
8160
|
+
if (value && typeof value === "object") {
|
|
8161
|
+
const record = value;
|
|
8162
|
+
const sorted = {};
|
|
8163
|
+
for (const key of Object.keys(record).sort()) {
|
|
8164
|
+
sorted[key] = sortJsonValue2(record[key]);
|
|
8165
|
+
}
|
|
8166
|
+
return sorted;
|
|
8167
|
+
}
|
|
8168
|
+
return value;
|
|
8169
|
+
}
|
|
8170
|
+
function readErrorMessage2(payload) {
|
|
8171
|
+
if (typeof payload !== "object" || payload === null) {
|
|
8172
|
+
return null;
|
|
8173
|
+
}
|
|
8174
|
+
const error = payload.error;
|
|
8175
|
+
if (typeof error !== "object" || error === null) {
|
|
8176
|
+
return null;
|
|
8177
|
+
}
|
|
8178
|
+
const message = error.message;
|
|
8179
|
+
return typeof message === "string" ? message : null;
|
|
8180
|
+
}
|
|
8181
|
+
function readApnsReason(payload) {
|
|
8182
|
+
if (typeof payload !== "object" || payload === null) {
|
|
8183
|
+
return null;
|
|
8184
|
+
}
|
|
8185
|
+
const reason = payload.apnsReason ?? payload.apns_reason;
|
|
8186
|
+
return typeof reason === "string" ? reason : null;
|
|
8187
|
+
}
|
|
8188
|
+
function shouldInvalidateLiveActivity(reason) {
|
|
8189
|
+
return ["BadDeviceToken", "Unregistered", "DeviceTokenNotForTopic", "TopicDisallowed"].includes(reason);
|
|
8190
|
+
}
|
|
8191
|
+
|
|
7529
8192
|
// src/hermes/gateway.ts
|
|
7530
8193
|
import { execFile as execFile2, spawn } from "child_process";
|
|
7531
8194
|
import { access, readFile as readFile5, stat as stat4 } from "fs/promises";
|
|
@@ -11465,7 +12128,7 @@ function toRecord3(value) {
|
|
|
11465
12128
|
}
|
|
11466
12129
|
|
|
11467
12130
|
// src/conversations/approvals.ts
|
|
11468
|
-
import { createHash } from "crypto";
|
|
12131
|
+
import { createHash as createHash2 } from "crypto";
|
|
11469
12132
|
var LINK_APPROVAL_RESUME_HINT_ZH = "Hermes \u5F53\u524D\u8FD8\u672A\u63D0\u4F9B\u53EF\u8C03\u7528\u7684\u5BA1\u6279\u7EED\u8DD1\u63A5\u53E3\uFF0C\u60A8\u53EF\u4EE5\u70B9\u51FB\u201C\u59CB\u7EC8\u5141\u8BB8\u201D\uFF0C\u7136\u540E\u91CD\u65B0\u53D1\u51FA\u547D\u4EE4\uFF0C\u6216\u5728\u201CProfile \u6743\u9650\u201D\u8BBE\u7F6E\u9875\u9762\u4FEE\u6539\u5BA1\u6279\u7B56\u7565\u3002";
|
|
11470
12133
|
var LINK_APPROVAL_RESUME_HINT_EN = "Hermes does not yet provide a callable approval-resume API. Tap \u201CAlways allow\u201D, then send the command again, or change the approval policy on the \u201CProfile permissions\u201D settings page.";
|
|
11471
12134
|
var LINK_APPROVAL_CONFIRM_HINT_ZH = "\u8BF7\u786E\u8BA4\u662F\u5426\u5141\u8BB8 Hermes \u7EE7\u7EED\u6267\u884C\u8FD9\u6761\u547D\u4EE4\u3002";
|
|
@@ -11565,7 +12228,7 @@ function coerceRecord(value) {
|
|
|
11565
12228
|
return toRecord4(value);
|
|
11566
12229
|
}
|
|
11567
12230
|
function createApprovalId(input) {
|
|
11568
|
-
const digest =
|
|
12231
|
+
const digest = createHash2("sha256").update(input.runId).update("\0").update(input.messageId).update("\0").update(input.command).update("\0").update(input.patternKey ?? "").digest("hex").slice(0, 24);
|
|
11569
12232
|
return `approval_${digest}`;
|
|
11570
12233
|
}
|
|
11571
12234
|
function readString6(payload, key) {
|
|
@@ -11583,7 +12246,7 @@ function toRecord4(value) {
|
|
|
11583
12246
|
}
|
|
11584
12247
|
|
|
11585
12248
|
// src/conversations/input-requests.ts
|
|
11586
|
-
import { createHash as
|
|
12249
|
+
import { createHash as createHash3 } from "crypto";
|
|
11587
12250
|
function extractInputRequestFromEvent(input) {
|
|
11588
12251
|
const kind = readInputRequestKind(input.event.payloadType);
|
|
11589
12252
|
if (!kind) {
|
|
@@ -11731,7 +12394,7 @@ function readInputRequestKind(payloadType) {
|
|
|
11731
12394
|
return null;
|
|
11732
12395
|
}
|
|
11733
12396
|
function createInputRequestId(input) {
|
|
11734
|
-
const digest =
|
|
12397
|
+
const digest = createHash3("sha256").update(input.runId).update("\0").update(input.messageId).update("\0").update(input.kind).update("\0").update(input.hermesRequestId).digest("hex").slice(0, 24);
|
|
11735
12398
|
return `input_${digest}`;
|
|
11736
12399
|
}
|
|
11737
12400
|
function readString7(payload, key) {
|
|
@@ -12207,7 +12870,7 @@ import { mkdir as mkdir6, readFile as readFile7, readdir as readdir4, rm as rm3,
|
|
|
12207
12870
|
import path11 from "path";
|
|
12208
12871
|
|
|
12209
12872
|
// src/conversations/media.ts
|
|
12210
|
-
import { createHash as
|
|
12873
|
+
import { createHash as createHash4 } from "crypto";
|
|
12211
12874
|
import path10 from "path";
|
|
12212
12875
|
|
|
12213
12876
|
// src/conversations/delivery-contract.ts
|
|
@@ -12419,7 +13082,7 @@ function readImportedMediaSourceKeys(message) {
|
|
|
12419
13082
|
);
|
|
12420
13083
|
}
|
|
12421
13084
|
function mediaSourceKey(sourcePath) {
|
|
12422
|
-
return
|
|
13085
|
+
return createHash4("sha256").update(resolveMediaSourcePath(sourcePath)).digest("hex").slice(0, 32);
|
|
12423
13086
|
}
|
|
12424
13087
|
function sanitizeFilename(value, fallback) {
|
|
12425
13088
|
const base = path10.basename((value ?? "").replace(/[\r\n\t]/gu, " ").trim());
|
|
@@ -17685,7 +18348,7 @@ function isConversationNotFoundError(error) {
|
|
|
17685
18348
|
}
|
|
17686
18349
|
|
|
17687
18350
|
// src/conversations/agent-events.ts
|
|
17688
|
-
import { createHash as
|
|
18351
|
+
import { createHash as createHash5 } from "crypto";
|
|
17689
18352
|
var APP_TOOL_EVENT_FIELDS_TO_DROP = /* @__PURE__ */ new Set([
|
|
17690
18353
|
"output",
|
|
17691
18354
|
"content",
|
|
@@ -17726,7 +18389,7 @@ function projectAgentEvent(input) {
|
|
|
17726
18389
|
summary,
|
|
17727
18390
|
args
|
|
17728
18391
|
});
|
|
17729
|
-
const detail = status === "failed" ?
|
|
18392
|
+
const detail = status === "failed" ? readErrorMessage3(input.payload) ?? actionSummary ?? void 0 : actionSummary ?? void 0;
|
|
17730
18393
|
const subtitle = actionSummary ?? (status === "running" ? agentEventText(input.language, `\u6B63\u5728\u8C03\u7528 ${name}`, `Running ${name}`) : status === "completed" ? agentEventText(input.language, `${name} \u5DF2\u5B8C\u6210`, `${name} done`) : agentEventText(input.language, `${name} \u6267\u884C\u5931\u8D25`, `${name} failed`));
|
|
17731
18394
|
return {
|
|
17732
18395
|
id,
|
|
@@ -18068,9 +18731,9 @@ function stableStringify(value) {
|
|
|
18068
18731
|
}
|
|
18069
18732
|
}
|
|
18070
18733
|
function hashAgentEventKey(value) {
|
|
18071
|
-
return
|
|
18734
|
+
return createHash5("sha256").update(value).digest("hex").slice(0, 16);
|
|
18072
18735
|
}
|
|
18073
|
-
function
|
|
18736
|
+
function readErrorMessage3(payload) {
|
|
18074
18737
|
if (typeof payload.error === "string" && payload.error.trim()) {
|
|
18075
18738
|
return payload.error.trim();
|
|
18076
18739
|
}
|
|
@@ -21705,7 +22368,7 @@ function isNodeError14(error, code) {
|
|
|
21705
22368
|
}
|
|
21706
22369
|
|
|
21707
22370
|
// src/conversations/run-lifecycle.ts
|
|
21708
|
-
import { createHash as
|
|
22371
|
+
import { createHash as createHash7 } from "crypto";
|
|
21709
22372
|
import { readdir as readdir9 } from "fs/promises";
|
|
21710
22373
|
|
|
21711
22374
|
// src/hermes/api-server.ts
|
|
@@ -24775,7 +25438,7 @@ function isNodeError17(error, code) {
|
|
|
24775
25438
|
}
|
|
24776
25439
|
|
|
24777
25440
|
// src/conversations/run-tool-event-ids.ts
|
|
24778
|
-
import { createHash as
|
|
25441
|
+
import { createHash as createHash6 } from "crypto";
|
|
24779
25442
|
var RunToolEventIdCoalescer = class {
|
|
24780
25443
|
scope;
|
|
24781
25444
|
ordinal = 0;
|
|
@@ -24940,7 +25603,7 @@ function stableStringify2(value) {
|
|
|
24940
25603
|
}
|
|
24941
25604
|
}
|
|
24942
25605
|
function hashStableValue(value) {
|
|
24943
|
-
return
|
|
25606
|
+
return createHash6("sha256").update(value).digest("hex").slice(0, 16);
|
|
24944
25607
|
}
|
|
24945
25608
|
function readString17(payload, key) {
|
|
24946
25609
|
const value = payload[key];
|
|
@@ -24964,7 +25627,7 @@ function normalizeHermesStreamEvent(event) {
|
|
|
24964
25627
|
...event.payload,
|
|
24965
25628
|
type: "run.failed",
|
|
24966
25629
|
error: {
|
|
24967
|
-
message:
|
|
25630
|
+
message: readErrorMessage4(event.payload) ?? readDelta(event.payload) ?? "Hermes run failed"
|
|
24968
25631
|
}
|
|
24969
25632
|
}
|
|
24970
25633
|
};
|
|
@@ -25154,7 +25817,7 @@ function normalizeStreamingTextDelta(currentText, nextChunk) {
|
|
|
25154
25817
|
}
|
|
25155
25818
|
return nextChunk;
|
|
25156
25819
|
}
|
|
25157
|
-
function
|
|
25820
|
+
function readErrorMessage4(payload) {
|
|
25158
25821
|
if (typeof payload.error === "string" && payload.error.trim()) {
|
|
25159
25822
|
return payload.error.trim();
|
|
25160
25823
|
}
|
|
@@ -25197,7 +25860,7 @@ function isTopLevelErrorEvent(event) {
|
|
|
25197
25860
|
if (type.startsWith("tool.")) {
|
|
25198
25861
|
return false;
|
|
25199
25862
|
}
|
|
25200
|
-
return type === "error" || type === "run.error" || event.eventName === "error" || Boolean(
|
|
25863
|
+
return type === "error" || type === "run.error" || event.eventName === "error" || Boolean(readErrorMessage4(event.payload));
|
|
25201
25864
|
}
|
|
25202
25865
|
function readChatCompletionDelta(payload) {
|
|
25203
25866
|
const choice = readFirstChoice(payload);
|
|
@@ -26173,7 +26836,7 @@ var ConversationRunLifecycle = class {
|
|
|
26173
26836
|
await this.failRun(
|
|
26174
26837
|
input.conversationId,
|
|
26175
26838
|
input.runId,
|
|
26176
|
-
|
|
26839
|
+
readErrorMessage4(input.event.payload) ?? "Hermes run failed",
|
|
26177
26840
|
input.event
|
|
26178
26841
|
);
|
|
26179
26842
|
return true;
|
|
@@ -27375,7 +28038,7 @@ ${details.join("\n")}` : localizedEmptyHermesResponseMessage(language);
|
|
|
27375
28038
|
run.status = "failed";
|
|
27376
28039
|
run.completed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
27377
28040
|
run.error_message = message;
|
|
27378
|
-
run.error_detail = source ?
|
|
28041
|
+
run.error_detail = source ? readErrorMessage4(source.payload) ?? void 0 : void 0;
|
|
27379
28042
|
const language = run.language === "en" ? "en" : "zh-CN";
|
|
27380
28043
|
const visibleMessage = formatFailureMessage(
|
|
27381
28044
|
message,
|
|
@@ -27728,7 +28391,7 @@ ${details.join("\n")}` : localizedEmptyHermesResponseMessage(language);
|
|
|
27728
28391
|
if (raw.length <= 200) {
|
|
27729
28392
|
return raw;
|
|
27730
28393
|
}
|
|
27731
|
-
return `hermespilot:${
|
|
28394
|
+
return `hermespilot:${createHash7("sha256").update(raw).digest("hex")}`;
|
|
27732
28395
|
}
|
|
27733
28396
|
async assistantMessageIdForRun(conversationId, runId) {
|
|
27734
28397
|
const snapshot = await this.deps.readSnapshot(conversationId).catch(() => null);
|
|
@@ -28345,15 +29008,15 @@ function previewText2(message) {
|
|
|
28345
29008
|
return text ? text.slice(0, 512) : null;
|
|
28346
29009
|
}
|
|
28347
29010
|
function runNotificationSourceEventId(conversationId, runId, eventKind) {
|
|
28348
|
-
const digest =
|
|
29011
|
+
const digest = createHash7("sha256").update(`${conversationId}:${runId}:${eventKind}`).digest("hex").slice(0, 24);
|
|
28349
29012
|
return `${conversationId}:${eventKind}:${digest}`;
|
|
28350
29013
|
}
|
|
28351
29014
|
function approvalNotificationSourceEventId(conversationId, runId, approvalId) {
|
|
28352
|
-
const digest =
|
|
29015
|
+
const digest = createHash7("sha256").update(`${conversationId}:${runId}:${approvalId}:approval_required`).digest("hex").slice(0, 24);
|
|
28353
29016
|
return `${conversationId}:approval_required:${digest}`;
|
|
28354
29017
|
}
|
|
28355
29018
|
function inputRequestNotificationSourceEventId(conversationId, runId, inputRequestId) {
|
|
28356
|
-
const digest =
|
|
29019
|
+
const digest = createHash7("sha256").update(`${conversationId}:${runId}:${inputRequestId}:input_required`).digest("hex").slice(0, 24);
|
|
28357
29020
|
return `${conversationId}:input_required:${digest}`;
|
|
28358
29021
|
}
|
|
28359
29022
|
async function closeSseIterator(iterator) {
|
|
@@ -30084,8 +30747,40 @@ var ConversationService = class {
|
|
|
30084
30747
|
const event = await this.store.appendEvent(conversationId, input);
|
|
30085
30748
|
this.emitter.emit(this.liveEventName(conversationId), event);
|
|
30086
30749
|
this.emitter.emit(ALL_CONVERSATION_EVENTS, event);
|
|
30750
|
+
void this.reportLiveActivityEvent(conversationId, event);
|
|
30087
30751
|
return event;
|
|
30088
30752
|
}
|
|
30753
|
+
async reportLiveActivityEvent(conversationId, event) {
|
|
30754
|
+
try {
|
|
30755
|
+
const [manifest, snapshot] = await Promise.all([
|
|
30756
|
+
this.store.readManifest(conversationId),
|
|
30757
|
+
this.store.readSnapshot(conversationId)
|
|
30758
|
+
]);
|
|
30759
|
+
if (manifest.status !== "active" || !manifest.owner_account_id) {
|
|
30760
|
+
return;
|
|
30761
|
+
}
|
|
30762
|
+
const liveActivityEvent = buildLiveActivityEvent({
|
|
30763
|
+
manifest,
|
|
30764
|
+
snapshot,
|
|
30765
|
+
event
|
|
30766
|
+
});
|
|
30767
|
+
if (!liveActivityEvent) {
|
|
30768
|
+
return;
|
|
30769
|
+
}
|
|
30770
|
+
await reportLiveActivityEventToServer({
|
|
30771
|
+
paths: this.paths,
|
|
30772
|
+
logger: this.logger,
|
|
30773
|
+
event: liveActivityEvent
|
|
30774
|
+
});
|
|
30775
|
+
} catch (error) {
|
|
30776
|
+
void this.logger.warn("live_activity_event_report_failed", {
|
|
30777
|
+
conversation_id: conversationId,
|
|
30778
|
+
event_type: event.type,
|
|
30779
|
+
event_seq: event.seq,
|
|
30780
|
+
error: error instanceof Error ? error.message : String(error)
|
|
30781
|
+
});
|
|
30782
|
+
}
|
|
30783
|
+
}
|
|
30089
30784
|
abortActiveRunsForConversation(conversationId) {
|
|
30090
30785
|
for (const [runId, active] of this.activeRunControllers) {
|
|
30091
30786
|
if (active.conversationId !== conversationId) {
|
|
@@ -30123,7 +30818,7 @@ function findApproval(snapshot, approvalId) {
|
|
|
30123
30818
|
return null;
|
|
30124
30819
|
}
|
|
30125
30820
|
function cronNotificationSourceEventId(conversationId, jobId, outputPath, eventKind) {
|
|
30126
|
-
const digest =
|
|
30821
|
+
const digest = createHash8("sha256").update(`${conversationId}:${jobId}:${outputPath}:${eventKind}`).digest("hex").slice(0, 24);
|
|
30127
30822
|
return `${conversationId}:${eventKind}:${digest}`;
|
|
30128
30823
|
}
|
|
30129
30824
|
function conversationHermesSessionIds(manifest) {
|
|
@@ -30189,12 +30884,315 @@ function notificationPreviewText(message) {
|
|
|
30189
30884
|
const text = messageText(message).replace(/<[^>]+>/gu, " ").replace(/\s+/gu, " ").trim();
|
|
30190
30885
|
return text ? text.slice(0, 512) : null;
|
|
30191
30886
|
}
|
|
30887
|
+
function buildLiveActivityEvent(input) {
|
|
30888
|
+
const run = liveActivityRunForEvent(input.event, input.snapshot);
|
|
30889
|
+
const contextOperation = readContextCompressionOperation(input.event.payload);
|
|
30890
|
+
const target = resolveLiveActivityTarget({ event: input.event, run, contextOperation });
|
|
30891
|
+
if (!target) {
|
|
30892
|
+
return null;
|
|
30893
|
+
}
|
|
30894
|
+
const phase = liveActivityPhaseForEvent(input.event, run, contextOperation);
|
|
30895
|
+
if (!phase) {
|
|
30896
|
+
return null;
|
|
30897
|
+
}
|
|
30898
|
+
const language = run?.language === "en" ? "en" : "zh";
|
|
30899
|
+
const text = liveActivityTextForEvent({
|
|
30900
|
+
event: input.event,
|
|
30901
|
+
snapshot: input.snapshot,
|
|
30902
|
+
run,
|
|
30903
|
+
phase,
|
|
30904
|
+
language,
|
|
30905
|
+
contextOperation
|
|
30906
|
+
});
|
|
30907
|
+
return {
|
|
30908
|
+
sourceEventId: `${input.manifest.id}:${input.event.seq}:${input.event.type}`,
|
|
30909
|
+
eventKind: input.event.type.replace(/\./gu, "_"),
|
|
30910
|
+
conversationId: input.manifest.id,
|
|
30911
|
+
conversationTitle: liveActivityConversationTitle(input.manifest, input.event, phase, language),
|
|
30912
|
+
accountId: input.manifest.owner_account_id,
|
|
30913
|
+
appInstanceId: input.manifest.owner_app_instance_id,
|
|
30914
|
+
targetKind: target.kind,
|
|
30915
|
+
targetId: target.id,
|
|
30916
|
+
runId: target.kind === "run" ? target.id : void 0,
|
|
30917
|
+
operationId: target.kind === "context_compression" ? target.id : contextOperation?.operation_id,
|
|
30918
|
+
phase,
|
|
30919
|
+
statusLabel: text.statusLabel,
|
|
30920
|
+
progressText: text.progressText,
|
|
30921
|
+
detailText: text.detailText,
|
|
30922
|
+
requiresUserAction: phase === "needs_input" || phase === "needs_approval",
|
|
30923
|
+
terminal: isLiveActivityTerminalEvent(phase, target.kind),
|
|
30924
|
+
occurredAt: input.event.created_at
|
|
30925
|
+
};
|
|
30926
|
+
}
|
|
30927
|
+
function liveActivityConversationTitle(manifest, event, phase, language) {
|
|
30928
|
+
if (phase === "goal_running" || phase === "goal_paused") {
|
|
30929
|
+
const goal = manifest.command_state?.goal;
|
|
30930
|
+
const rawTitle = goal?.title?.trim() || goal?.content?.trim() || "";
|
|
30931
|
+
if (!rawTitle) {
|
|
30932
|
+
return null;
|
|
30933
|
+
}
|
|
30934
|
+
const title = truncateLiveActivityTitle(rawTitle, 18);
|
|
30935
|
+
return language === "en" ? `Goal: ${title}` : `\u76EE\u6807\uFF1A${title}`;
|
|
30936
|
+
}
|
|
30937
|
+
const eventTitle = liveActivityTitleFromConversationUpdate(event);
|
|
30938
|
+
if (eventTitle !== void 0) {
|
|
30939
|
+
return eventTitle;
|
|
30940
|
+
}
|
|
30941
|
+
return liveActivityTitleFromManifest(manifest);
|
|
30942
|
+
}
|
|
30943
|
+
function liveActivityTitleFromConversationUpdate(event) {
|
|
30944
|
+
if (event.type.toLowerCase() !== "conversation.updated") {
|
|
30945
|
+
return void 0;
|
|
30946
|
+
}
|
|
30947
|
+
const titleSource = readString20(event.payload, "title_source");
|
|
30948
|
+
if (titleSource === "default" || titleSource === "temporary_fallback") {
|
|
30949
|
+
return null;
|
|
30950
|
+
}
|
|
30951
|
+
const title = readString20(event.payload, "title");
|
|
30952
|
+
return title ? truncateLiveActivityTitle(title, 24) : null;
|
|
30953
|
+
}
|
|
30954
|
+
function liveActivityTitleFromManifest(manifest) {
|
|
30955
|
+
if (manifest.title_source === "default" || manifest.title_source === "temporary_fallback") {
|
|
30956
|
+
return null;
|
|
30957
|
+
}
|
|
30958
|
+
if (isDefaultConversationTitle(manifest.title)) {
|
|
30959
|
+
return null;
|
|
30960
|
+
}
|
|
30961
|
+
return truncateLiveActivityTitle(manifest.title, 24);
|
|
30962
|
+
}
|
|
30963
|
+
function truncateLiveActivityTitle(value, maxLength) {
|
|
30964
|
+
const normalized = value.replace(/\s+/gu, " ").trim();
|
|
30965
|
+
if (!normalized) {
|
|
30966
|
+
return null;
|
|
30967
|
+
}
|
|
30968
|
+
const chars = Array.from(normalized);
|
|
30969
|
+
if (chars.length <= maxLength) {
|
|
30970
|
+
return normalized;
|
|
30971
|
+
}
|
|
30972
|
+
return `${chars.slice(0, maxLength).join("")}...`;
|
|
30973
|
+
}
|
|
30974
|
+
function liveActivityRunForEvent(event, snapshot) {
|
|
30975
|
+
if (event.run_id) {
|
|
30976
|
+
return snapshot.runs.find((item) => item.id === event.run_id) ?? null;
|
|
30977
|
+
}
|
|
30978
|
+
if (!isConversationTitleUpdateEvent(event)) {
|
|
30979
|
+
return null;
|
|
30980
|
+
}
|
|
30981
|
+
return latestTrackableLiveActivityRun(snapshot);
|
|
30982
|
+
}
|
|
30983
|
+
function latestTrackableLiveActivityRun(snapshot) {
|
|
30984
|
+
const candidates = snapshot.runs.filter((run) => run.status === "running" || run.status === "queued").sort((left, right) => Date.parse(right.started_at) - Date.parse(left.started_at));
|
|
30985
|
+
return candidates[0] ?? null;
|
|
30986
|
+
}
|
|
30987
|
+
function isConversationTitleUpdateEvent(event) {
|
|
30988
|
+
if (event.type.toLowerCase() !== "conversation.updated") {
|
|
30989
|
+
return false;
|
|
30990
|
+
}
|
|
30991
|
+
return Boolean(readString20(event.payload, "title")?.trim());
|
|
30992
|
+
}
|
|
30993
|
+
function resolveLiveActivityTarget(input) {
|
|
30994
|
+
if (input.run?.kind === "compression") {
|
|
30995
|
+
const operationId = input.contextOperation?.operation_id ?? input.run.context_compression?.operation_id;
|
|
30996
|
+
return operationId ? { kind: "context_compression", id: operationId } : null;
|
|
30997
|
+
}
|
|
30998
|
+
if (input.run?.id) {
|
|
30999
|
+
return { kind: "run", id: input.run.id };
|
|
31000
|
+
}
|
|
31001
|
+
if (input.contextOperation?.operation_id) {
|
|
31002
|
+
return { kind: "context_compression", id: input.contextOperation.operation_id };
|
|
31003
|
+
}
|
|
31004
|
+
return null;
|
|
31005
|
+
}
|
|
31006
|
+
function liveActivityPhaseForEvent(event, run, contextOperation) {
|
|
31007
|
+
const type = event.type.toLowerCase();
|
|
31008
|
+
if (type === "run.started" || type === "run.queued") {
|
|
31009
|
+
return run?.mode === "goal" ? "goal_running" : "accepted";
|
|
31010
|
+
}
|
|
31011
|
+
if (type === "conversation.goal.updated") {
|
|
31012
|
+
const goal = readRecord(event.payload).goal;
|
|
31013
|
+
const status = readString20(goal, "status");
|
|
31014
|
+
return status === "paused" ? "goal_paused" : "goal_running";
|
|
31015
|
+
}
|
|
31016
|
+
if (isConversationTitleUpdateEvent(event)) {
|
|
31017
|
+
return run?.mode === "goal" ? "goal_running" : "running";
|
|
31018
|
+
}
|
|
31019
|
+
if (type === "tool.started") {
|
|
31020
|
+
return "using_tool";
|
|
31021
|
+
}
|
|
31022
|
+
if (type === "tool.completed") {
|
|
31023
|
+
return "tool_completed";
|
|
31024
|
+
}
|
|
31025
|
+
if (type === "input_request.created") {
|
|
31026
|
+
return "needs_input";
|
|
31027
|
+
}
|
|
31028
|
+
if (type === "approval.requested") {
|
|
31029
|
+
return "needs_approval";
|
|
31030
|
+
}
|
|
31031
|
+
if (type === "reasoning.available") {
|
|
31032
|
+
return run?.mode === "goal" ? "goal_running" : "running";
|
|
31033
|
+
}
|
|
31034
|
+
if (type === "context_compression.started") {
|
|
31035
|
+
return "context_compressing";
|
|
31036
|
+
}
|
|
31037
|
+
if (type === "context_compression.completed") {
|
|
31038
|
+
return "context_compressed";
|
|
31039
|
+
}
|
|
31040
|
+
if (type === "context_compression.failed") {
|
|
31041
|
+
return contextOperation?.status === "timed_out" ? "context_compression_timed_out" : "context_compression_failed";
|
|
31042
|
+
}
|
|
31043
|
+
if (type === "context_compression.timed_out") {
|
|
31044
|
+
return "context_compression_timed_out";
|
|
31045
|
+
}
|
|
31046
|
+
if (type === "run.completed") {
|
|
31047
|
+
return "completed";
|
|
31048
|
+
}
|
|
31049
|
+
if (type === "run.failed") {
|
|
31050
|
+
return "failed";
|
|
31051
|
+
}
|
|
31052
|
+
if (type === "run.cancelled" || type === "run.canceled") {
|
|
31053
|
+
return "cancelled";
|
|
31054
|
+
}
|
|
31055
|
+
return null;
|
|
31056
|
+
}
|
|
31057
|
+
function liveActivityTextForEvent(input) {
|
|
31058
|
+
const toolName = readToolName2(input.event.payload);
|
|
31059
|
+
const assistantText = input.event.message_id ? input.snapshot.messages.find((message) => message.id === input.event.message_id) : null;
|
|
31060
|
+
const preview = input.event.type.toLowerCase() === "reasoning.available" ? liveActivityReasoningPreview(input.event.payload) : isLiveActivityTerminalEvent(input.phase, input.run?.kind === "compression" ? "context_compression" : "run") && assistantText ? notificationPreviewText(assistantText) : null;
|
|
31061
|
+
if (input.language === "en") {
|
|
31062
|
+
return liveActivityTextEn(input.phase, toolName, preview, input.contextOperation);
|
|
31063
|
+
}
|
|
31064
|
+
return liveActivityTextZh(input.phase, toolName, preview, input.contextOperation);
|
|
31065
|
+
}
|
|
31066
|
+
function liveActivityTextZh(phase, toolName, preview, contextOperation) {
|
|
31067
|
+
switch (phase) {
|
|
31068
|
+
case "using_tool":
|
|
31069
|
+
return { statusLabel: "\u8C03\u7528\u5DE5\u5177", progressText: toolName ? `\u6B63\u5728\u4F7F\u7528 ${toolName}` : "Hermes \u6B63\u5728\u8C03\u7528\u5DE5\u5177", detailText: preview ?? void 0 };
|
|
31070
|
+
case "tool_completed":
|
|
31071
|
+
return { statusLabel: "\u5DE5\u5177\u5B8C\u6210", progressText: toolName ? `${toolName} \u5DF2\u5B8C\u6210` : "\u5DE5\u5177\u8C03\u7528\u5DF2\u5B8C\u6210", detailText: preview ?? void 0 };
|
|
31072
|
+
case "needs_input":
|
|
31073
|
+
return { statusLabel: "\u9700\u56DE\u590D", progressText: "Hermes \u9700\u8981\u4F60\u8865\u5145\u4FE1\u606F", detailText: "\u70B9\u51FB\u56DE\u5230 App \u7EE7\u7EED\u3002" };
|
|
31074
|
+
case "needs_approval":
|
|
31075
|
+
return { statusLabel: "\u9700\u6388\u6743", progressText: "Hermes \u8BF7\u6C42\u6267\u884C\u6743\u9650", detailText: "\u70B9\u51FB\u56DE\u5230 App \u67E5\u770B\u3002" };
|
|
31076
|
+
case "goal_running":
|
|
31077
|
+
return { statusLabel: "\u76EE\u6807\u4E2D", progressText: "Hermes \u6B63\u5728\u63A8\u8FDB\u76EE\u6807", detailText: preview ?? "\u6B63\u5728\u6267\u884C\u4E0B\u4E00\u6B65\u3002" };
|
|
31078
|
+
case "goal_paused":
|
|
31079
|
+
return { statusLabel: "\u5F85\u6307\u5F15", progressText: "\u76EE\u6807\u4EFB\u52A1\u7B49\u5F85\u4F60\u7684\u6307\u5F15", detailText: "\u70B9\u51FB\u56DE\u5230 App \u7EE7\u7EED\u3002" };
|
|
31080
|
+
case "context_compressing":
|
|
31081
|
+
return {
|
|
31082
|
+
statusLabel: contextOperation?.source === "auto" ? "\u6574\u7406\u4E2D" : "\u538B\u7F29\u4E2D",
|
|
31083
|
+
progressText: contextOperation?.source === "auto" ? "Hermes \u6B63\u5728\u81EA\u52A8\u6574\u7406\u4E0A\u4E0B\u6587" : "Hermes \u6B63\u5728\u6574\u7406\u4E0A\u4E0B\u6587",
|
|
31084
|
+
detailText: contextOperation?.source === "auto" ? "\u6211\u5148\u6574\u7406\u4E0A\u4E0B\u6587\uFF0C\u518D\u7EE7\u7EED\u6267\u884C\u3002" : "\u6211\u6B63\u5728\u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587\u3002"
|
|
31085
|
+
};
|
|
31086
|
+
case "context_compressed":
|
|
31087
|
+
return { statusLabel: "\u5DF2\u6574\u7406", progressText: "\u4E0A\u4E0B\u6587\u5DF2\u6574\u7406", detailText: "\u53EF\u4EE5\u7EE7\u7EED\u5F53\u524D\u4EFB\u52A1\u3002" };
|
|
31088
|
+
case "context_compression_failed":
|
|
31089
|
+
return { statusLabel: "\u538B\u7F29\u5931\u8D25", progressText: "\u4E0A\u4E0B\u6587\u538B\u7F29\u5931\u8D25", detailText: "\u70B9\u51FB\u56DE\u5230 App \u67E5\u770B\u8BE6\u60C5\u3002" };
|
|
31090
|
+
case "context_compression_timed_out":
|
|
31091
|
+
return { statusLabel: "\u538B\u7F29\u8D85\u65F6", progressText: "\u6B63\u5728\u6062\u590D Hermes", detailText: "\u6267\u884C\u540E\u7AEF\u6B63\u5728\u6062\u590D\u3002" };
|
|
31092
|
+
case "completed":
|
|
31093
|
+
return { statusLabel: "\u5B8C\u6210", progressText: "\u4EFB\u52A1\u5DF2\u5B8C\u6210", detailText: preview ?? "\u70B9\u51FB\u67E5\u770B\u7ED3\u679C\u3002" };
|
|
31094
|
+
case "failed":
|
|
31095
|
+
return { statusLabel: "\u5931\u8D25", progressText: "\u4EFB\u52A1\u8FD0\u884C\u5931\u8D25", detailText: "\u70B9\u51FB\u67E5\u770B\u5931\u8D25\u8BE6\u60C5\u3002" };
|
|
31096
|
+
case "cancelled":
|
|
31097
|
+
return { statusLabel: "\u5DF2\u53D6\u6D88", progressText: "\u4EFB\u52A1\u5DF2\u53D6\u6D88", detailText: "\u70B9\u51FB\u56DE\u5230 App \u67E5\u770B\u3002" };
|
|
31098
|
+
default:
|
|
31099
|
+
return { statusLabel: "\u6267\u884C\u4E2D", progressText: "\u6B63\u5728\u5904\u7406\u4F60\u7684\u8BF7\u6C42", detailText: preview ?? void 0 };
|
|
31100
|
+
}
|
|
31101
|
+
}
|
|
31102
|
+
function liveActivityTextEn(phase, toolName, preview, contextOperation) {
|
|
31103
|
+
switch (phase) {
|
|
31104
|
+
case "using_tool":
|
|
31105
|
+
return { statusLabel: "Tool", progressText: toolName ? `Using ${toolName}` : "Hermes is using a tool", detailText: preview ?? void 0 };
|
|
31106
|
+
case "tool_completed":
|
|
31107
|
+
return { statusLabel: "Tool done", progressText: toolName ? `${toolName} completed` : "Tool completed", detailText: preview ?? void 0 };
|
|
31108
|
+
case "needs_input":
|
|
31109
|
+
return { statusLabel: "Reply", progressText: "Hermes needs your response", detailText: "Open the app to continue." };
|
|
31110
|
+
case "needs_approval":
|
|
31111
|
+
return { statusLabel: "Approve", progressText: "Hermes needs approval", detailText: "Open the app to review it." };
|
|
31112
|
+
case "goal_running":
|
|
31113
|
+
return { statusLabel: "Goal", progressText: "Hermes is working on the goal", detailText: preview ?? "Working through the next step." };
|
|
31114
|
+
case "goal_paused":
|
|
31115
|
+
return { statusLabel: "Guide", progressText: "Goal needs guidance", detailText: "Open the app to continue." };
|
|
31116
|
+
case "context_compressing":
|
|
31117
|
+
return {
|
|
31118
|
+
statusLabel: contextOperation?.source === "auto" ? "Tidying" : "Compact",
|
|
31119
|
+
progressText: contextOperation?.source === "auto" ? "Hermes is reorganizing context" : "Hermes is compacting context",
|
|
31120
|
+
detailText: contextOperation?.source === "auto" ? "Tidying context before continuing." : "Compacting this conversation context."
|
|
31121
|
+
};
|
|
31122
|
+
case "context_compressed":
|
|
31123
|
+
return { statusLabel: "Ready", progressText: "Context compacted", detailText: "You can continue this task." };
|
|
31124
|
+
case "context_compression_failed":
|
|
31125
|
+
return { statusLabel: "Failed", progressText: "Context compression failed", detailText: "Open the app for details." };
|
|
31126
|
+
case "context_compression_timed_out":
|
|
31127
|
+
return { statusLabel: "Timeout", progressText: "Restoring Hermes", detailText: "The execution backend is recovering." };
|
|
31128
|
+
case "completed":
|
|
31129
|
+
return { statusLabel: "Done", progressText: "Task completed", detailText: preview ?? "Open the app to view the result." };
|
|
31130
|
+
case "failed":
|
|
31131
|
+
return { statusLabel: "Failed", progressText: "Task failed", detailText: "Open the app for details." };
|
|
31132
|
+
case "cancelled":
|
|
31133
|
+
return { statusLabel: "Canceled", progressText: "Task canceled", detailText: "Open the app for details." };
|
|
31134
|
+
default:
|
|
31135
|
+
return { statusLabel: "Running", progressText: "Working on your request", detailText: preview ?? void 0 };
|
|
31136
|
+
}
|
|
31137
|
+
}
|
|
31138
|
+
function liveActivityReasoningPreview(payload) {
|
|
31139
|
+
const text = readString20(payload, "text")?.replace(/<[^>]+>/gu, " ").replace(/\s+/gu, " ").trim();
|
|
31140
|
+
return liveActivityCleanAssistantPreview(text);
|
|
31141
|
+
}
|
|
31142
|
+
function liveActivityCleanAssistantPreview(text) {
|
|
31143
|
+
const normalized = text?.replace(/\s+/gu, " ").trim();
|
|
31144
|
+
if (!normalized || normalized.length < 4) {
|
|
31145
|
+
return null;
|
|
31146
|
+
}
|
|
31147
|
+
if (looksUnsafeForLockScreen(normalized)) {
|
|
31148
|
+
return null;
|
|
31149
|
+
}
|
|
31150
|
+
return normalized.length > 90 ? `${normalized.slice(0, 90)}...` : normalized;
|
|
31151
|
+
}
|
|
31152
|
+
function looksUnsafeForLockScreen(text) {
|
|
31153
|
+
return /(?:^|\s)(?:https?:\/\/|\/[A-Za-z0-9_.-]+\/|[A-Za-z]:\\|[A-Z_]{8,}=)/u.test(text) || /(?:```|<\?xml|BEGIN [A-Z ]+KEY|token|api[_ -]?key|password|secret)/iu.test(text);
|
|
31154
|
+
}
|
|
31155
|
+
function isLiveActivityTerminalEvent(phase, targetKind) {
|
|
31156
|
+
if (phase === "completed" || phase === "failed" || phase === "cancelled") {
|
|
31157
|
+
return true;
|
|
31158
|
+
}
|
|
31159
|
+
return targetKind === "context_compression" && (phase === "context_compressed" || phase === "context_compression_failed" || phase === "context_compression_timed_out");
|
|
31160
|
+
}
|
|
31161
|
+
function readContextCompressionOperation(payload) {
|
|
31162
|
+
const operation = readRecord(payload).operation;
|
|
31163
|
+
if (!operation || typeof operation !== "object") {
|
|
31164
|
+
return null;
|
|
31165
|
+
}
|
|
31166
|
+
const operationId = readString20(operation, "operation_id");
|
|
31167
|
+
if (!operationId) {
|
|
31168
|
+
return null;
|
|
31169
|
+
}
|
|
31170
|
+
const record = operation;
|
|
31171
|
+
return {
|
|
31172
|
+
operation_id: operationId,
|
|
31173
|
+
generation: typeof record.generation === "number" ? record.generation : 0,
|
|
31174
|
+
status: readString20(record, "status") === "completed" ? "completed" : readString20(record, "status") === "failed" ? "failed" : readString20(record, "status") === "timed_out" ? "timed_out" : readString20(record, "status") === "cancelled" ? "cancelled" : "compressing",
|
|
31175
|
+
started_at: readString20(record, "started_at") ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
31176
|
+
source: readString20(record, "source") === "manual" ? "manual" : "auto"
|
|
31177
|
+
};
|
|
31178
|
+
}
|
|
31179
|
+
function readToolName2(payload) {
|
|
31180
|
+
const record = readRecord(payload);
|
|
31181
|
+
return readString20(record, "tool_name") ?? readString20(record, "tool") ?? readString20(record, "name") ?? readString20(readRecord(record.tool), "name");
|
|
31182
|
+
}
|
|
31183
|
+
function readRecord(value) {
|
|
31184
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
31185
|
+
}
|
|
31186
|
+
function readString20(value, key) {
|
|
31187
|
+
const raw = readRecord(value)[key];
|
|
31188
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
31189
|
+
}
|
|
30192
31190
|
function approvalRestartText(language, zh, en) {
|
|
30193
31191
|
return language === "en" ? en : zh;
|
|
30194
31192
|
}
|
|
30195
31193
|
|
|
30196
31194
|
// src/security/devices.ts
|
|
30197
|
-
import { randomBytes as randomBytes3, randomUUID as randomUUID13, timingSafeEqual, createHash as
|
|
31195
|
+
import { randomBytes as randomBytes3, randomUUID as randomUUID13, timingSafeEqual, createHash as createHash9 } from "crypto";
|
|
30198
31196
|
var ACCESS_TOKEN_TTL_MS = 15 * 60 * 1e3;
|
|
30199
31197
|
var REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
30200
31198
|
var DEVICE_SEEN_WRITE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
@@ -30490,7 +31488,7 @@ function randomToken(prefix) {
|
|
|
30490
31488
|
return `${prefix}${randomBytes3(24).toString("base64url")}`;
|
|
30491
31489
|
}
|
|
30492
31490
|
function sha256(value) {
|
|
30493
|
-
return
|
|
31491
|
+
return createHash9("sha256").update(value).digest("hex");
|
|
30494
31492
|
}
|
|
30495
31493
|
function safeEqual(left, right) {
|
|
30496
31494
|
const leftBytes = Buffer.from(left);
|
|
@@ -30697,7 +31695,7 @@ async function readRawBody(request, maxBytes) {
|
|
|
30697
31695
|
}
|
|
30698
31696
|
return Buffer.concat(chunks);
|
|
30699
31697
|
}
|
|
30700
|
-
function
|
|
31698
|
+
function readString21(body, key) {
|
|
30701
31699
|
const value = body[key];
|
|
30702
31700
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
30703
31701
|
}
|
|
@@ -30732,7 +31730,7 @@ function readSupportedLanguage(value) {
|
|
|
30732
31730
|
return null;
|
|
30733
31731
|
}
|
|
30734
31732
|
function readOptionalProfileName(body) {
|
|
30735
|
-
return
|
|
31733
|
+
return readString21(body, "profile") ?? readString21(body, "profile_name") ?? readString21(body, "profileName") ?? void 0;
|
|
30736
31734
|
}
|
|
30737
31735
|
function readStringArray(body, ...keys) {
|
|
30738
31736
|
for (const key of keys) {
|
|
@@ -31152,7 +32150,7 @@ function registerConversationRoutes(router, options) {
|
|
|
31152
32150
|
const language = readPreferredLanguage(ctx);
|
|
31153
32151
|
const body = await readJsonBody(ctx.req);
|
|
31154
32152
|
ctx.status = 201;
|
|
31155
|
-
const rawReasoningEffort =
|
|
32153
|
+
const rawReasoningEffort = readString21(body, "reasoning_effort") ?? readString21(body, "reasoningEffort") ?? readString21(body, "default_reasoning_effort") ?? readString21(body, "defaultReasoningEffort");
|
|
31156
32154
|
const reasoningEffort = normalizeReasoningEffort(rawReasoningEffort);
|
|
31157
32155
|
if (rawReasoningEffort && !reasoningEffort) {
|
|
31158
32156
|
throw new LinkHttpError(
|
|
@@ -31165,15 +32163,15 @@ function registerConversationRoutes(router, options) {
|
|
|
31165
32163
|
ok: true,
|
|
31166
32164
|
conversation: localizeConversationSummary(
|
|
31167
32165
|
await conversations.createConversation({
|
|
31168
|
-
title:
|
|
32166
|
+
title: readString21(body, "title") ?? void 0,
|
|
31169
32167
|
profileName: readOptionalProfileName(body),
|
|
31170
32168
|
accountId: auth.accountId,
|
|
31171
32169
|
appInstanceId: auth.appInstanceId,
|
|
31172
32170
|
workspaceId: readConversationWorkspaceId(body),
|
|
31173
|
-
modelId:
|
|
31174
|
-
modelProvider:
|
|
31175
|
-
modelBaseUrl:
|
|
31176
|
-
modelApiMode:
|
|
32171
|
+
modelId: readString21(body, "model_id") ?? readString21(body, "modelId") ?? readString21(body, "model") ?? void 0,
|
|
32172
|
+
modelProvider: readString21(body, "model_provider") ?? readString21(body, "modelProvider") ?? readString21(body, "provider") ?? void 0,
|
|
32173
|
+
modelBaseUrl: readString21(body, "model_base_url") ?? readString21(body, "modelBaseUrl") ?? readString21(body, "base_url") ?? readString21(body, "baseUrl") ?? void 0,
|
|
32174
|
+
modelApiMode: readString21(body, "model_api_mode") ?? readString21(body, "modelApiMode") ?? readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? void 0,
|
|
31177
32175
|
reasoningEffort
|
|
31178
32176
|
}),
|
|
31179
32177
|
language
|
|
@@ -31250,9 +32248,9 @@ function registerConversationRoutes(router, options) {
|
|
|
31250
32248
|
const auth = await authenticateRequest(ctx, paths);
|
|
31251
32249
|
const language = readPreferredLanguage(ctx);
|
|
31252
32250
|
const body = await readJsonBody(ctx.req);
|
|
31253
|
-
const content =
|
|
32251
|
+
const content = readString21(body, "content") ?? readString21(body, "text") ?? readString21(body, "input") ?? "";
|
|
31254
32252
|
const attachments = readMessageAttachments(body.attachments ?? body.blobs);
|
|
31255
|
-
const mode =
|
|
32253
|
+
const mode = readString21(body, "mode") ?? readString21(body, "send_mode");
|
|
31256
32254
|
if (mode && mode !== "message" && mode !== "goal") {
|
|
31257
32255
|
throw new LinkHttpError(
|
|
31258
32256
|
400,
|
|
@@ -31275,7 +32273,7 @@ function registerConversationRoutes(router, options) {
|
|
|
31275
32273
|
conversationId: ctx.params.conversationId,
|
|
31276
32274
|
content,
|
|
31277
32275
|
attachments,
|
|
31278
|
-
clientMessageId:
|
|
32276
|
+
clientMessageId: readString21(body, "client_message_id") ?? readString21(body, "clientMessageId") ?? void 0,
|
|
31279
32277
|
idempotencyKey: readHeader(ctx, "idempotency-key") ?? void 0,
|
|
31280
32278
|
profileName: readOptionalProfileName(body),
|
|
31281
32279
|
mode: mode === "goal" ? "goal" : "message",
|
|
@@ -31342,8 +32340,8 @@ function registerConversationRoutes(router, options) {
|
|
|
31342
32340
|
...localizeConversationResult(
|
|
31343
32341
|
await conversations.startContextCompression({
|
|
31344
32342
|
conversationId: ctx.params.conversationId,
|
|
31345
|
-
focus:
|
|
31346
|
-
clientOperationId:
|
|
32343
|
+
focus: readString21(body, "focus") ?? readString21(body, "focus_topic") ?? readString21(body, "focusTopic") ?? void 0,
|
|
32344
|
+
clientOperationId: readString21(body, "client_operation_id") ?? readString21(body, "clientOperationId") ?? readHeader(ctx, "idempotency-key") ?? void 0,
|
|
31347
32345
|
createUserMessage: false,
|
|
31348
32346
|
accountId: auth.accountId,
|
|
31349
32347
|
appInstanceId: auth.appInstanceId,
|
|
@@ -31357,11 +32355,11 @@ function registerConversationRoutes(router, options) {
|
|
|
31357
32355
|
router.patch("/api/v1/conversations/:conversationId/model", async (ctx) => {
|
|
31358
32356
|
await authenticateRequest(ctx, paths);
|
|
31359
32357
|
const body = await readJsonBody(ctx.req);
|
|
31360
|
-
const modelId =
|
|
31361
|
-
const modelProvider =
|
|
31362
|
-
const modelBaseUrl =
|
|
31363
|
-
const modelApiMode =
|
|
31364
|
-
const rawReasoningEffort =
|
|
32358
|
+
const modelId = readString21(body, "model_id") ?? readString21(body, "modelId") ?? readString21(body, "model");
|
|
32359
|
+
const modelProvider = readString21(body, "model_provider") ?? readString21(body, "modelProvider") ?? readString21(body, "provider") ?? void 0;
|
|
32360
|
+
const modelBaseUrl = readString21(body, "model_base_url") ?? readString21(body, "modelBaseUrl") ?? readString21(body, "base_url") ?? readString21(body, "baseUrl") ?? void 0;
|
|
32361
|
+
const modelApiMode = readString21(body, "model_api_mode") ?? readString21(body, "modelApiMode") ?? readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? void 0;
|
|
32362
|
+
const rawReasoningEffort = readString21(body, "reasoning_effort") ?? readString21(body, "reasoningEffort") ?? readString21(body, "default_reasoning_effort") ?? readString21(body, "defaultReasoningEffort");
|
|
31365
32363
|
const reasoningEffort = normalizeReasoningEffort(rawReasoningEffort);
|
|
31366
32364
|
if (rawReasoningEffort && !reasoningEffort) {
|
|
31367
32365
|
throw new LinkHttpError(
|
|
@@ -31411,7 +32409,7 @@ function registerConversationRoutes(router, options) {
|
|
|
31411
32409
|
await authenticateRequest(ctx, paths);
|
|
31412
32410
|
const language = readPreferredLanguage(ctx);
|
|
31413
32411
|
const body = await readJsonBody(ctx.req);
|
|
31414
|
-
const title =
|
|
32412
|
+
const title = readString21(body, "title") ?? readString21(body, "name") ?? readString21(body, "display_name");
|
|
31415
32413
|
if (!title) {
|
|
31416
32414
|
throw new LinkHttpError(400, "title_required", "title is required");
|
|
31417
32415
|
}
|
|
@@ -31603,7 +32601,7 @@ function registerConversationRoutes(router, options) {
|
|
|
31603
32601
|
async (ctx) => {
|
|
31604
32602
|
await authenticateRequest(ctx, paths);
|
|
31605
32603
|
const body = await readJsonBody(ctx.req);
|
|
31606
|
-
const scope =
|
|
32604
|
+
const scope = readString21(body, "scope") ?? "always";
|
|
31607
32605
|
ctx.body = {
|
|
31608
32606
|
ok: true,
|
|
31609
32607
|
...await conversations.resolveApproval({
|
|
@@ -31653,7 +32651,7 @@ function registerConversationRoutes(router, options) {
|
|
|
31653
32651
|
conversationId: ctx.params.conversationId,
|
|
31654
32652
|
requestId: ctx.params.requestId,
|
|
31655
32653
|
kind,
|
|
31656
|
-
answer:
|
|
32654
|
+
answer: readString21(body, "answer") ?? void 0,
|
|
31657
32655
|
password: readRawString(body, "password"),
|
|
31658
32656
|
value: readRawString(body, "value")
|
|
31659
32657
|
})
|
|
@@ -31815,10 +32813,10 @@ function readConversationWorkspaceFilter(query) {
|
|
|
31815
32813
|
}
|
|
31816
32814
|
function readConversationWorkspaceId(body) {
|
|
31817
32815
|
if (Object.prototype.hasOwnProperty.call(body, "workspace_id") || Object.prototype.hasOwnProperty.call(body, "workspaceId")) {
|
|
31818
|
-
return
|
|
32816
|
+
return readString21(body, "workspace_id") ?? readString21(body, "workspaceId");
|
|
31819
32817
|
}
|
|
31820
32818
|
if (Object.prototype.hasOwnProperty.call(body, "workspace")) {
|
|
31821
|
-
return
|
|
32819
|
+
return readString21(body, "workspace");
|
|
31822
32820
|
}
|
|
31823
32821
|
return void 0;
|
|
31824
32822
|
}
|
|
@@ -31912,7 +32910,7 @@ function resolveConversationEventCursor(input) {
|
|
|
31912
32910
|
return Math.max(queryAfter, headerAfter);
|
|
31913
32911
|
}
|
|
31914
32912
|
function readConversationClearPlanTargetStatus(body) {
|
|
31915
|
-
const raw =
|
|
32913
|
+
const raw = readString21(body, "target_status") ?? readString21(body, "targetStatus") ?? "active";
|
|
31916
32914
|
if (raw === "active" || raw === "archived") {
|
|
31917
32915
|
return raw;
|
|
31918
32916
|
}
|
|
@@ -31923,7 +32921,7 @@ function readConversationClearPlanTargetStatus(body) {
|
|
|
31923
32921
|
);
|
|
31924
32922
|
}
|
|
31925
32923
|
function readInputRequestKind2(body) {
|
|
31926
|
-
const kind =
|
|
32924
|
+
const kind = readString21(body, "kind") ?? readString21(body, "type");
|
|
31927
32925
|
if (kind === "clarify" || kind === "sudo" || kind === "secret") {
|
|
31928
32926
|
return kind;
|
|
31929
32927
|
}
|
|
@@ -32321,7 +33319,7 @@ function toHermesCronJobInput(input) {
|
|
|
32321
33319
|
};
|
|
32322
33320
|
}
|
|
32323
33321
|
async function bindAndDecorateCronJobForHermesLink(input) {
|
|
32324
|
-
const jobId =
|
|
33322
|
+
const jobId = readString21(input.job, "id") ?? readString21(input.job, "job_id");
|
|
32325
33323
|
if (!jobId) {
|
|
32326
33324
|
return input.job;
|
|
32327
33325
|
}
|
|
@@ -32340,9 +33338,9 @@ async function bindAndDecorateCronJobForHermesLink(input) {
|
|
|
32340
33338
|
}
|
|
32341
33339
|
function readCronJobCreateInput(body) {
|
|
32342
33340
|
const input = {};
|
|
32343
|
-
const name =
|
|
32344
|
-
const prompt =
|
|
32345
|
-
const schedule =
|
|
33341
|
+
const name = readString21(body, "name") ?? readString21(body, "title");
|
|
33342
|
+
const prompt = readString21(body, "prompt") ?? readString21(body, "description") ?? readString21(body, "task");
|
|
33343
|
+
const schedule = readString21(body, "schedule");
|
|
32346
33344
|
if (!name) {
|
|
32347
33345
|
throw new LinkHttpError(400, "cron_job_name_required", "name is required");
|
|
32348
33346
|
}
|
|
@@ -32363,7 +33361,7 @@ function readCronJobCreateInput(body) {
|
|
|
32363
33361
|
input.name = name;
|
|
32364
33362
|
input.prompt = prompt;
|
|
32365
33363
|
input.schedule = schedule;
|
|
32366
|
-
input.deliver =
|
|
33364
|
+
input.deliver = readString21(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
|
|
32367
33365
|
const skills = readOptionalCronSkills(body);
|
|
32368
33366
|
if (skills) {
|
|
32369
33367
|
input.skills = skills;
|
|
@@ -32491,7 +33489,7 @@ function assertCronJobId(jobId) {
|
|
|
32491
33489
|
}
|
|
32492
33490
|
|
|
32493
33491
|
// src/http/routes/model-configs.ts
|
|
32494
|
-
import { createHash as
|
|
33492
|
+
import { createHash as createHash10 } from "crypto";
|
|
32495
33493
|
|
|
32496
33494
|
// src/model-catalog/catalog.ts
|
|
32497
33495
|
import { randomInt } from "crypto";
|
|
@@ -32727,7 +33725,7 @@ function normalizeModelCapabilityCatalog(value) {
|
|
|
32727
33725
|
const models = rawModels.map(normalizeModelCapabilityEntry).filter((entry) => entry !== null);
|
|
32728
33726
|
return {
|
|
32729
33727
|
schemaVersion: readPositiveInteger3(record.schemaVersion) ?? 1,
|
|
32730
|
-
updatedAt:
|
|
33728
|
+
updatedAt: readString22(record.updatedAt),
|
|
32731
33729
|
models
|
|
32732
33730
|
};
|
|
32733
33731
|
}
|
|
@@ -32736,7 +33734,7 @@ function normalizeModelCapabilityEntry(value) {
|
|
|
32736
33734
|
return null;
|
|
32737
33735
|
}
|
|
32738
33736
|
const record = value;
|
|
32739
|
-
const canonicalId =
|
|
33737
|
+
const canonicalId = readString22(record.canonicalId) ?? readString22(record.canonical_id) ?? readString22(record.id);
|
|
32740
33738
|
if (!canonicalId) {
|
|
32741
33739
|
return null;
|
|
32742
33740
|
}
|
|
@@ -32764,12 +33762,12 @@ function normalizeModelCapabilityEntry(value) {
|
|
|
32764
33762
|
outputModalities: readStringArray2(
|
|
32765
33763
|
record.outputModalities ?? record.output_modalities
|
|
32766
33764
|
),
|
|
32767
|
-
source:
|
|
32768
|
-
updatedAt:
|
|
32769
|
-
notes:
|
|
33765
|
+
source: readString22(record.source),
|
|
33766
|
+
updatedAt: readString22(record.updatedAt ?? record.updated_at),
|
|
33767
|
+
notes: readString22(record.notes)
|
|
32770
33768
|
};
|
|
32771
33769
|
}
|
|
32772
|
-
function
|
|
33770
|
+
function readString22(value) {
|
|
32773
33771
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
32774
33772
|
}
|
|
32775
33773
|
function readStringArray2(value) {
|
|
@@ -32779,7 +33777,7 @@ function readStringArray2(value) {
|
|
|
32779
33777
|
const seen = /* @__PURE__ */ new Set();
|
|
32780
33778
|
const values = [];
|
|
32781
33779
|
for (const item of value) {
|
|
32782
|
-
const text =
|
|
33780
|
+
const text = readString22(item);
|
|
32783
33781
|
if (!text || seen.has(text)) {
|
|
32784
33782
|
continue;
|
|
32785
33783
|
}
|
|
@@ -32796,7 +33794,7 @@ function readPositiveInteger3(value) {
|
|
|
32796
33794
|
return Math.floor(number);
|
|
32797
33795
|
}
|
|
32798
33796
|
function readReasoningSupportPolicy(value) {
|
|
32799
|
-
const normalized =
|
|
33797
|
+
const normalized = readString22(value)?.toLowerCase();
|
|
32800
33798
|
if (!normalized || normalized === "unknown" || normalized === "auto") {
|
|
32801
33799
|
return null;
|
|
32802
33800
|
}
|
|
@@ -32827,7 +33825,7 @@ function readNullableBoolean(value) {
|
|
|
32827
33825
|
if (typeof value === "boolean") {
|
|
32828
33826
|
return value;
|
|
32829
33827
|
}
|
|
32830
|
-
const normalized =
|
|
33828
|
+
const normalized = readString22(value)?.toLowerCase();
|
|
32831
33829
|
if (!normalized) {
|
|
32832
33830
|
return null;
|
|
32833
33831
|
}
|
|
@@ -33720,7 +34718,7 @@ function modelProviderIdFromParts(input) {
|
|
|
33720
34718
|
input.keyEnv ?? "",
|
|
33721
34719
|
input.authType ?? ""
|
|
33722
34720
|
].join("");
|
|
33723
|
-
return `mp_${
|
|
34721
|
+
return `mp_${createHash10("sha256").update(identity).digest("hex").slice(0, 18)}`;
|
|
33724
34722
|
}
|
|
33725
34723
|
function mergeCredentialState(left, right) {
|
|
33726
34724
|
if (left === "configured" || right === "configured") {
|
|
@@ -33976,8 +34974,8 @@ function normalizeUrlForIdentity(value) {
|
|
|
33976
34974
|
return value.trim().replace(/\/+$/u, "").toLowerCase();
|
|
33977
34975
|
}
|
|
33978
34976
|
function readModelProviderConfigInput(body) {
|
|
33979
|
-
const providerName =
|
|
33980
|
-
const baseUrl =
|
|
34977
|
+
const providerName = readString21(body, "display_name") ?? readString21(body, "displayName") ?? readString21(body, "provider_name") ?? readString21(body, "providerName") ?? readString21(body, "name");
|
|
34978
|
+
const baseUrl = readString21(body, "base_url") ?? readString21(body, "baseUrl");
|
|
33981
34979
|
if (!providerName || !baseUrl) {
|
|
33982
34980
|
throw new LinkHttpError(
|
|
33983
34981
|
400,
|
|
@@ -33988,15 +34986,15 @@ function readModelProviderConfigInput(body) {
|
|
|
33988
34986
|
return {
|
|
33989
34987
|
providerName,
|
|
33990
34988
|
baseUrl,
|
|
33991
|
-
apiMode:
|
|
33992
|
-
keyEnv:
|
|
33993
|
-
apiKey:
|
|
34989
|
+
apiMode: readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? readString21(body, "transport") ?? void 0,
|
|
34990
|
+
keyEnv: readString21(body, "key_env") ?? readString21(body, "keyEnv") ?? void 0,
|
|
34991
|
+
apiKey: readString21(body, "api_key") ?? readString21(body, "apiKey") ?? void 0
|
|
33994
34992
|
};
|
|
33995
34993
|
}
|
|
33996
34994
|
function readModelConfigInput(body) {
|
|
33997
|
-
const id =
|
|
33998
|
-
const provider =
|
|
33999
|
-
const baseUrl =
|
|
34995
|
+
const id = readString21(body, "id") ?? readString21(body, "model_id") ?? readString21(body, "modelId");
|
|
34996
|
+
const provider = readString21(body, "provider") ?? readString21(body, "provider_key") ?? readString21(body, "providerKey");
|
|
34997
|
+
const baseUrl = readString21(body, "base_url") ?? readString21(body, "baseUrl");
|
|
34000
34998
|
if (!id || !provider || !baseUrl) {
|
|
34001
34999
|
throw new LinkHttpError(
|
|
34002
35000
|
400,
|
|
@@ -34006,22 +35004,22 @@ function readModelConfigInput(body) {
|
|
|
34006
35004
|
}
|
|
34007
35005
|
return {
|
|
34008
35006
|
id,
|
|
34009
|
-
originalModelId:
|
|
34010
|
-
originalProvider:
|
|
34011
|
-
originalBaseUrl:
|
|
34012
|
-
originalApiMode:
|
|
35007
|
+
originalModelId: readString21(body, "original_model_id") ?? readString21(body, "originalModelId") ?? readString21(body, "original_id") ?? void 0,
|
|
35008
|
+
originalProvider: readString21(body, "original_provider") ?? readString21(body, "originalProvider") ?? readString21(body, "original_provider_key") ?? readString21(body, "originalProviderKey") ?? void 0,
|
|
35009
|
+
originalBaseUrl: readString21(body, "original_base_url") ?? readString21(body, "originalBaseUrl") ?? void 0,
|
|
35010
|
+
originalApiMode: readString21(body, "original_api_mode") ?? readString21(body, "originalApiMode") ?? void 0,
|
|
34013
35011
|
provider,
|
|
34014
|
-
providerName:
|
|
35012
|
+
providerName: readString21(body, "provider_name") ?? readString21(body, "providerName") ?? void 0,
|
|
34015
35013
|
baseUrl,
|
|
34016
|
-
apiKey:
|
|
34017
|
-
apiMode:
|
|
35014
|
+
apiKey: readString21(body, "api_key") ?? readString21(body, "apiKey") ?? void 0,
|
|
35015
|
+
apiMode: readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? void 0,
|
|
34018
35016
|
contextLength: readPositiveInteger2(
|
|
34019
35017
|
body.context_length ?? body.contextLength
|
|
34020
35018
|
),
|
|
34021
|
-
keyEnv:
|
|
35019
|
+
keyEnv: readString21(body, "key_env") ?? readString21(body, "keyEnv") ?? void 0,
|
|
34022
35020
|
setDefault: readBoolean3(body.set_default ?? body.setDefault),
|
|
34023
|
-
reasoningEffort:
|
|
34024
|
-
reasoningSupportPolicy:
|
|
35021
|
+
reasoningEffort: readString21(body, "reasoning_effort") ?? readString21(body, "reasoningEffort") ?? void 0,
|
|
35022
|
+
reasoningSupportPolicy: readString21(body, "reasoning_support_policy") ?? readString21(body, "reasoningSupportPolicy") ?? readString21(body, "reasoning_support") ?? readString21(body, "reasoningSupport") ?? void 0,
|
|
34025
35023
|
supportsVision: readNullableBoolean2(
|
|
34026
35024
|
body.supports_vision ?? body.supportsVision
|
|
34027
35025
|
)
|
|
@@ -34029,28 +35027,28 @@ function readModelConfigInput(body) {
|
|
|
34029
35027
|
}
|
|
34030
35028
|
function readModelDefaultsInput(body) {
|
|
34031
35029
|
return {
|
|
34032
|
-
taskModelId:
|
|
34033
|
-
taskModelProvider:
|
|
34034
|
-
taskModelBaseUrl:
|
|
34035
|
-
taskModelApiMode:
|
|
34036
|
-
compressionModelId:
|
|
34037
|
-
compressionModelProvider:
|
|
34038
|
-
compressionModelBaseUrl:
|
|
34039
|
-
compressionModelApiMode:
|
|
34040
|
-
reasoningEffort:
|
|
34041
|
-
imageInputMode:
|
|
35030
|
+
taskModelId: readString21(body, "task_model_id") ?? readString21(body, "taskModelId") ?? readString21(body, "default_model_id") ?? readString21(body, "defaultModelId") ?? void 0,
|
|
35031
|
+
taskModelProvider: readString21(body, "task_model_provider") ?? readString21(body, "taskModelProvider") ?? readString21(body, "default_model_provider") ?? readString21(body, "defaultModelProvider") ?? void 0,
|
|
35032
|
+
taskModelBaseUrl: readString21(body, "task_model_base_url") ?? readString21(body, "taskModelBaseUrl") ?? readString21(body, "default_model_base_url") ?? readString21(body, "defaultModelBaseUrl") ?? void 0,
|
|
35033
|
+
taskModelApiMode: readString21(body, "task_model_api_mode") ?? readString21(body, "taskModelApiMode") ?? readString21(body, "default_model_api_mode") ?? readString21(body, "defaultModelApiMode") ?? void 0,
|
|
35034
|
+
compressionModelId: readString21(body, "compression_model_id") ?? readString21(body, "compressionModelId") ?? void 0,
|
|
35035
|
+
compressionModelProvider: readString21(body, "compression_model_provider") ?? readString21(body, "compressionModelProvider") ?? void 0,
|
|
35036
|
+
compressionModelBaseUrl: readString21(body, "compression_model_base_url") ?? readString21(body, "compressionModelBaseUrl") ?? void 0,
|
|
35037
|
+
compressionModelApiMode: readString21(body, "compression_model_api_mode") ?? readString21(body, "compressionModelApiMode") ?? void 0,
|
|
35038
|
+
reasoningEffort: readString21(body, "reasoning_effort") ?? readString21(body, "reasoningEffort") ?? readString21(body, "default_reasoning_effort") ?? readString21(body, "defaultReasoningEffort") ?? void 0,
|
|
35039
|
+
imageInputMode: readString21(body, "image_input_mode") ?? readString21(body, "imageInputMode") ?? void 0
|
|
34042
35040
|
};
|
|
34043
35041
|
}
|
|
34044
35042
|
function readModelDeleteInput(body) {
|
|
34045
|
-
const id =
|
|
35043
|
+
const id = readString21(body, "model_id") ?? readString21(body, "modelId");
|
|
34046
35044
|
if (!id) {
|
|
34047
35045
|
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
34048
35046
|
}
|
|
34049
35047
|
return {
|
|
34050
35048
|
id,
|
|
34051
|
-
provider:
|
|
34052
|
-
baseUrl:
|
|
34053
|
-
apiMode:
|
|
35049
|
+
provider: readString21(body, "provider") ?? readString21(body, "provider_key") ?? readString21(body, "providerKey") ?? void 0,
|
|
35050
|
+
baseUrl: readString21(body, "base_url") ?? readString21(body, "baseUrl") ?? void 0,
|
|
35051
|
+
apiMode: readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? void 0
|
|
34054
35052
|
};
|
|
34055
35053
|
}
|
|
34056
35054
|
function readNullableBoolean2(value) {
|
|
@@ -34073,8 +35071,8 @@ function readNullableBoolean2(value) {
|
|
|
34073
35071
|
return void 0;
|
|
34074
35072
|
}
|
|
34075
35073
|
function readModelConfigImportInput(body) {
|
|
34076
|
-
const sourceProfileName =
|
|
34077
|
-
const modelId =
|
|
35074
|
+
const sourceProfileName = readString21(body, "source_profile") ?? readString21(body, "sourceProfile") ?? readString21(body, "source_profile_name") ?? readString21(body, "sourceProfileName");
|
|
35075
|
+
const modelId = readString21(body, "model_id") ?? readString21(body, "modelId") ?? readString21(body, "id");
|
|
34078
35076
|
if (!sourceProfileName || !modelId) {
|
|
34079
35077
|
throw new LinkHttpError(
|
|
34080
35078
|
400,
|
|
@@ -34085,9 +35083,9 @@ function readModelConfigImportInput(body) {
|
|
|
34085
35083
|
return {
|
|
34086
35084
|
sourceProfileName,
|
|
34087
35085
|
modelId,
|
|
34088
|
-
provider:
|
|
34089
|
-
baseUrl:
|
|
34090
|
-
apiMode:
|
|
35086
|
+
provider: readString21(body, "provider") ?? readString21(body, "provider_key") ?? readString21(body, "providerKey") ?? void 0,
|
|
35087
|
+
baseUrl: readString21(body, "base_url") ?? readString21(body, "baseUrl") ?? void 0,
|
|
35088
|
+
apiMode: readString21(body, "api_mode") ?? readString21(body, "apiMode") ?? void 0,
|
|
34091
35089
|
setDefault: readBoolean3(body.set_default ?? body.setDefault)
|
|
34092
35090
|
};
|
|
34093
35091
|
}
|
|
@@ -35392,16 +36390,16 @@ function readProfilePermissionsInput(body) {
|
|
|
35392
36390
|
const approvals = readOptionalObject(body, "approvals");
|
|
35393
36391
|
if (approvals) {
|
|
35394
36392
|
input.approvals = {
|
|
35395
|
-
mode:
|
|
36393
|
+
mode: readString21(approvals, "mode") ?? readString21(approvals, "approval_mode") ?? readString21(approvals, "approvalMode") ?? void 0,
|
|
35396
36394
|
timeout: readPositiveInteger2(approvals.timeout),
|
|
35397
|
-
cronMode:
|
|
36395
|
+
cronMode: readString21(approvals, "cron_mode") ?? readString21(approvals, "cronMode") ?? void 0
|
|
35398
36396
|
};
|
|
35399
36397
|
}
|
|
35400
36398
|
const terminal = readOptionalObject(body, "terminal");
|
|
35401
36399
|
if (terminal) {
|
|
35402
36400
|
input.terminal = {
|
|
35403
|
-
backend:
|
|
35404
|
-
cwd:
|
|
36401
|
+
backend: readString21(terminal, "backend") ?? void 0,
|
|
36402
|
+
cwd: readString21(terminal, "cwd") ?? void 0,
|
|
35405
36403
|
containerCpu: readPositiveInteger2(
|
|
35406
36404
|
terminal.container_cpu ?? terminal.containerCpu
|
|
35407
36405
|
),
|
|
@@ -35732,9 +36730,9 @@ async function testHindsightProviderSettings(profileName, patch) {
|
|
|
35732
36730
|
const mode = normalizeHindsightMode(
|
|
35733
36731
|
patch.mode ?? config.mode ?? env.HINDSIGHT_MODE
|
|
35734
36732
|
);
|
|
35735
|
-
const apiUrl =
|
|
35736
|
-
const bankId =
|
|
35737
|
-
const apiKey =
|
|
36733
|
+
const apiUrl = readString23(patch.apiUrl) ?? readString23(config.api_url) ?? env.HINDSIGHT_API_URL ?? (mode === "cloud" ? HINDSIGHT_DEFAULT_API_URL : HINDSIGHT_DEFAULT_LOCAL_URL);
|
|
36734
|
+
const bankId = readString23(patch.bankId) ?? readString23(config.bank_id) ?? "hermes";
|
|
36735
|
+
const apiKey = readString23(patch.apiKey) ?? env.HINDSIGHT_API_KEY ?? readString23(config.apiKey) ?? readString23(config.api_key);
|
|
35738
36736
|
const baseUrl = normalizeHttpUrl2(apiUrl);
|
|
35739
36737
|
if (!baseUrl) {
|
|
35740
36738
|
return {
|
|
@@ -36268,7 +37266,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36268
37266
|
const config2 = await readJsonObject(
|
|
36269
37267
|
memoryProviderConfigPath(profileName, "honcho") ?? ""
|
|
36270
37268
|
);
|
|
36271
|
-
return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(
|
|
37269
|
+
return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString23(config2.apiKey)) || isConfiguredEnvValue(readString23(config2.api_key)) || isConfiguredEnvValue(readString23(config2.baseUrl)) ? { configured: true, issue: null } : {
|
|
36272
37270
|
configured: false,
|
|
36273
37271
|
issue: "Honcho \u9700\u8981\u5148\u586B\u5199 API Key\uFF0C\u6216\u5728 honcho.json \u914D\u7F6E self-hosted baseUrl\u3002"
|
|
36274
37272
|
};
|
|
@@ -36277,7 +37275,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36277
37275
|
const config2 = await readJsonObject(
|
|
36278
37276
|
memoryProviderConfigPath(profileName, "mem0") ?? ""
|
|
36279
37277
|
);
|
|
36280
|
-
return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(
|
|
37278
|
+
return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString23(config2.api_key)) ? { configured: true, issue: null } : {
|
|
36281
37279
|
configured: false,
|
|
36282
37280
|
issue: "Mem0 \u9700\u8981\u5148\u5728\u672C\u9875\u586B\u5199 API Key\uFF0CLink \u4F1A\u5199\u5165\u5F53\u524D Profile \u7684 .env\u3002"
|
|
36283
37281
|
};
|
|
@@ -36319,7 +37317,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36319
37317
|
memoryProviderConfigPath(profileName, provider) ?? ""
|
|
36320
37318
|
);
|
|
36321
37319
|
const mode = normalizeHindsightMode(config.mode ?? env.HINDSIGHT_MODE);
|
|
36322
|
-
const apiKey =
|
|
37320
|
+
const apiKey = readString23(config.apiKey) ?? readString23(config.api_key) ?? env.HINDSIGHT_API_KEY;
|
|
36323
37321
|
if (mode === "cloud") {
|
|
36324
37322
|
return isConfiguredEnvValue(apiKey) ? { configured: true, issue: null } : {
|
|
36325
37323
|
configured: false,
|
|
@@ -36327,15 +37325,15 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36327
37325
|
};
|
|
36328
37326
|
}
|
|
36329
37327
|
if (mode === "local_external") {
|
|
36330
|
-
const apiUrl =
|
|
37328
|
+
const apiUrl = readString23(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
|
|
36331
37329
|
return isConfiguredEnvValue(apiUrl) ? { configured: true, issue: null } : {
|
|
36332
37330
|
configured: false,
|
|
36333
37331
|
issue: "Hindsight local_external \u9700\u8981\u914D\u7F6E\u53EF\u8BBF\u95EE\u7684 API URL\u3002"
|
|
36334
37332
|
};
|
|
36335
37333
|
}
|
|
36336
37334
|
if (mode === "local_embedded") {
|
|
36337
|
-
const llmProvider =
|
|
36338
|
-
const llmModel =
|
|
37335
|
+
const llmProvider = readString23(config.llm_provider) ?? "openai";
|
|
37336
|
+
const llmModel = readString23(config.llm_model);
|
|
36339
37337
|
if (!llmModel) {
|
|
36340
37338
|
return {
|
|
36341
37339
|
configured: false,
|
|
@@ -36343,7 +37341,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36343
37341
|
};
|
|
36344
37342
|
}
|
|
36345
37343
|
if (llmProvider === "openai_compatible" && !isConfiguredEnvValue(
|
|
36346
|
-
|
|
37344
|
+
readString23(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
|
|
36347
37345
|
)) {
|
|
36348
37346
|
return {
|
|
36349
37347
|
configured: false,
|
|
@@ -36351,7 +37349,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
36351
37349
|
};
|
|
36352
37350
|
}
|
|
36353
37351
|
if (!["ollama", "lmstudio", "openai_compatible"].includes(llmProvider) && !isConfiguredEnvValue(
|
|
36354
|
-
|
|
37352
|
+
readString23(config.llmApiKey) ?? readString23(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
|
|
36355
37353
|
)) {
|
|
36356
37354
|
return {
|
|
36357
37355
|
configured: false,
|
|
@@ -36407,8 +37405,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
36407
37405
|
secretSetting(
|
|
36408
37406
|
"apiKey",
|
|
36409
37407
|
"API Key",
|
|
36410
|
-
env.HONCHO_API_KEY ??
|
|
36411
|
-
isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(
|
|
37408
|
+
env.HONCHO_API_KEY ?? readString23(config.apiKey) ?? readString23(config.api_key),
|
|
37409
|
+
isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString23(config.apiKey)) || isConfiguredEnvValue(readString23(config.api_key))
|
|
36412
37410
|
),
|
|
36413
37411
|
stringSetting("workspace", "Workspace", config.workspace ?? "hermes"),
|
|
36414
37412
|
stringSetting("peerName", "\u7528\u6237 Peer", config.peerName ?? ""),
|
|
@@ -36450,8 +37448,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
36450
37448
|
secretSetting(
|
|
36451
37449
|
"apiKey",
|
|
36452
37450
|
"API Key",
|
|
36453
|
-
env.MEM0_API_KEY ??
|
|
36454
|
-
isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(
|
|
37451
|
+
env.MEM0_API_KEY ?? readString23(config.apiKey) ?? readString23(config.api_key),
|
|
37452
|
+
isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString23(config.apiKey)) || isConfiguredEnvValue(readString23(config.api_key))
|
|
36455
37453
|
),
|
|
36456
37454
|
stringSetting("userId", "User ID", config.user_id ?? "hermes-user"),
|
|
36457
37455
|
stringSetting("agentId", "Agent ID", config.agent_id ?? "hermes"),
|
|
@@ -36536,8 +37534,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
36536
37534
|
secretSetting(
|
|
36537
37535
|
"apiKey",
|
|
36538
37536
|
"Hindsight API Key",
|
|
36539
|
-
env.HINDSIGHT_API_KEY ??
|
|
36540
|
-
isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(
|
|
37537
|
+
env.HINDSIGHT_API_KEY ?? readString23(config.apiKey) ?? readString23(config.api_key),
|
|
37538
|
+
isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(readString23(config.apiKey)) || isConfiguredEnvValue(readString23(config.api_key))
|
|
36541
37539
|
),
|
|
36542
37540
|
stringSetting(
|
|
36543
37541
|
"bankId",
|
|
@@ -36559,8 +37557,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
36559
37557
|
secretSetting(
|
|
36560
37558
|
"llmApiKey",
|
|
36561
37559
|
"LLM API Key",
|
|
36562
|
-
env.HINDSIGHT_LLM_API_KEY ??
|
|
36563
|
-
isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(
|
|
37560
|
+
env.HINDSIGHT_LLM_API_KEY ?? readString23(config.llmApiKey) ?? readString23(config.llm_api_key),
|
|
37561
|
+
isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(readString23(config.llmApiKey)) || isConfiguredEnvValue(readString23(config.llm_api_key))
|
|
36564
37562
|
),
|
|
36565
37563
|
booleanSetting("autoRecall", "\u81EA\u52A8\u56DE\u5FC6", config.auto_recall ?? true),
|
|
36566
37564
|
booleanSetting("autoRetain", "\u81EA\u52A8\u6C89\u6DC0", config.auto_retain ?? true),
|
|
@@ -36679,11 +37677,11 @@ async function readCustomProviderRegistry(profileName) {
|
|
|
36679
37677
|
return { id: id2, label: id2, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" };
|
|
36680
37678
|
}
|
|
36681
37679
|
const record = toRecord21(item);
|
|
36682
|
-
const id = normalizeCustomProviderId(
|
|
37680
|
+
const id = normalizeCustomProviderId(readString23(record.id) ?? "");
|
|
36683
37681
|
return {
|
|
36684
37682
|
id,
|
|
36685
|
-
label:
|
|
36686
|
-
description:
|
|
37683
|
+
label: readString23(record.label) ?? id,
|
|
37684
|
+
description: readString23(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
|
|
36687
37685
|
};
|
|
36688
37686
|
}).filter((item) => item.id);
|
|
36689
37687
|
} catch {
|
|
@@ -36732,8 +37730,8 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
|
36732
37730
|
const meta = await readPluginMetadata(providerDir);
|
|
36733
37731
|
descriptors.push({
|
|
36734
37732
|
id: providerId,
|
|
36735
|
-
label:
|
|
36736
|
-
description:
|
|
37733
|
+
label: readString23(meta.name) ?? providerId,
|
|
37734
|
+
description: readString23(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
|
|
36737
37735
|
});
|
|
36738
37736
|
}
|
|
36739
37737
|
return descriptors;
|
|
@@ -36895,7 +37893,7 @@ function isMemoryEnvKeyWritable(key) {
|
|
|
36895
37893
|
].includes(key);
|
|
36896
37894
|
}
|
|
36897
37895
|
function normalizeHindsightMode(value) {
|
|
36898
|
-
const mode =
|
|
37896
|
+
const mode = readString23(value) ?? "cloud";
|
|
36899
37897
|
return mode === "local" ? "local_embedded" : mode;
|
|
36900
37898
|
}
|
|
36901
37899
|
function normalizeHttpUrl2(value) {
|
|
@@ -36964,27 +37962,27 @@ function parseJsonObject2(text) {
|
|
|
36964
37962
|
}
|
|
36965
37963
|
}
|
|
36966
37964
|
function readHindsightError(json) {
|
|
36967
|
-
const detail =
|
|
37965
|
+
const detail = readString23(json.detail) ?? readString23(json.error);
|
|
36968
37966
|
return detail ? `\uFF1A${detail}` : "";
|
|
36969
37967
|
}
|
|
36970
37968
|
function hindsightSemanticIssue(pathName, json) {
|
|
36971
37969
|
if (pathName === "/health") {
|
|
36972
|
-
const status =
|
|
37970
|
+
const status = readString23(json.status);
|
|
36973
37971
|
return status && ["healthy", "ok"].includes(status.toLowerCase()) ? null : `\u5065\u5EB7\u72B6\u6001\u5F02\u5E38\uFF1A${status ?? "unknown"}`;
|
|
36974
37972
|
}
|
|
36975
37973
|
return null;
|
|
36976
37974
|
}
|
|
36977
37975
|
function summarizeHindsightProbe(pathName, json) {
|
|
36978
37976
|
if (pathName === "/health") {
|
|
36979
|
-
const status =
|
|
36980
|
-
const database =
|
|
37977
|
+
const status = readString23(json.status) ?? "ok";
|
|
37978
|
+
const database = readString23(json.database);
|
|
36981
37979
|
return database ? `${status}, database ${database}` : status;
|
|
36982
37980
|
}
|
|
36983
37981
|
if (pathName === "/version") {
|
|
36984
|
-
const version =
|
|
37982
|
+
const version = readString23(json.api_version);
|
|
36985
37983
|
return version ? `API ${version}` : "version endpoint reachable";
|
|
36986
37984
|
}
|
|
36987
|
-
const bankId =
|
|
37985
|
+
const bankId = readString23(json.bank_id);
|
|
36988
37986
|
return bankId ? `bank ${bankId} reachable` : "bank config reachable";
|
|
36989
37987
|
}
|
|
36990
37988
|
async function readActiveMemoryProvider(profileName) {
|
|
@@ -36999,7 +37997,7 @@ async function readActiveMemoryProvider(profileName) {
|
|
|
36999
37997
|
});
|
|
37000
37998
|
const config = raw ? toRecord21(YAML6.parse(raw)) : {};
|
|
37001
37999
|
const memory = toRecord21(config.memory);
|
|
37002
|
-
const provider =
|
|
38000
|
+
const provider = readString23(memory.provider);
|
|
37003
38001
|
if (!provider || provider === "built-in" || provider === "builtin" || provider === "built_in") {
|
|
37004
38002
|
return null;
|
|
37005
38003
|
}
|
|
@@ -37056,7 +38054,7 @@ function stringSetting(key, label, value, editable = true) {
|
|
|
37056
38054
|
return {
|
|
37057
38055
|
key,
|
|
37058
38056
|
label,
|
|
37059
|
-
value:
|
|
38057
|
+
value: readString23(value) ?? "",
|
|
37060
38058
|
editable,
|
|
37061
38059
|
kind: "string"
|
|
37062
38060
|
};
|
|
@@ -37068,7 +38066,7 @@ function secretSetting(key, label, value, configured) {
|
|
|
37068
38066
|
value: "",
|
|
37069
38067
|
editable: true,
|
|
37070
38068
|
kind: "secret",
|
|
37071
|
-
configured: configured || isConfiguredEnvValue(
|
|
38069
|
+
configured: configured || isConfiguredEnvValue(readString23(value))
|
|
37072
38070
|
};
|
|
37073
38071
|
}
|
|
37074
38072
|
function textSetting(key, label, value, editable = true) {
|
|
@@ -37081,7 +38079,7 @@ function textSetting(key, label, value, editable = true) {
|
|
|
37081
38079
|
};
|
|
37082
38080
|
}
|
|
37083
38081
|
function selectSetting(key, label, value, options, editable = true) {
|
|
37084
|
-
const stringValue =
|
|
38082
|
+
const stringValue = readString23(value) ?? options[0] ?? null;
|
|
37085
38083
|
return { key, label, value: stringValue, editable, kind: "select", options };
|
|
37086
38084
|
}
|
|
37087
38085
|
async function readMemoryLimits(profileName) {
|
|
@@ -37154,7 +38152,7 @@ function hashString(value) {
|
|
|
37154
38152
|
function toRecord21(value) {
|
|
37155
38153
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
37156
38154
|
}
|
|
37157
|
-
function
|
|
38155
|
+
function readString23(value) {
|
|
37158
38156
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
37159
38157
|
}
|
|
37160
38158
|
function readPositiveInteger4(value) {
|
|
@@ -37313,7 +38311,7 @@ function registerProfileMemoryRoutes(router, options) {
|
|
|
37313
38311
|
);
|
|
37314
38312
|
}
|
|
37315
38313
|
function readMemoryTarget(body) {
|
|
37316
|
-
const raw =
|
|
38314
|
+
const raw = readString21(body, "target");
|
|
37317
38315
|
if (raw === "memory" || raw === "user") {
|
|
37318
38316
|
return raw;
|
|
37319
38317
|
}
|
|
@@ -37324,7 +38322,7 @@ function readMemoryTarget(body) {
|
|
|
37324
38322
|
);
|
|
37325
38323
|
}
|
|
37326
38324
|
function readMemoryResetTarget(body) {
|
|
37327
|
-
const raw =
|
|
38325
|
+
const raw = readString21(body, "target") ?? "all";
|
|
37328
38326
|
if (raw === "all" || raw === "memory" || raw === "user") {
|
|
37329
38327
|
return raw;
|
|
37330
38328
|
}
|
|
@@ -37335,7 +38333,7 @@ function readMemoryResetTarget(body) {
|
|
|
37335
38333
|
);
|
|
37336
38334
|
}
|
|
37337
38335
|
function readRequiredMemoryContent(body) {
|
|
37338
|
-
const content =
|
|
38336
|
+
const content = readString21(body, "content") ?? readString21(body, "text");
|
|
37339
38337
|
if (!content) {
|
|
37340
38338
|
throw new LinkHttpError(
|
|
37341
38339
|
400,
|
|
@@ -37346,7 +38344,7 @@ function readRequiredMemoryContent(body) {
|
|
|
37346
38344
|
return content;
|
|
37347
38345
|
}
|
|
37348
38346
|
function readRequiredMemoryMatch(body) {
|
|
37349
|
-
const oldText =
|
|
38347
|
+
const oldText = readString21(body, "old_text") ?? readString21(body, "oldText") ?? readString21(body, "match");
|
|
37350
38348
|
if (!oldText) {
|
|
37351
38349
|
throw new LinkHttpError(
|
|
37352
38350
|
400,
|
|
@@ -37357,7 +38355,7 @@ function readRequiredMemoryMatch(body) {
|
|
|
37357
38355
|
return oldText;
|
|
37358
38356
|
}
|
|
37359
38357
|
function readRequiredMemoryProvider(body) {
|
|
37360
|
-
const provider =
|
|
38358
|
+
const provider = readString21(body, "provider") ?? readString21(body, "provider_id") ?? readString21(body, "providerId");
|
|
37361
38359
|
if (!provider) {
|
|
37362
38360
|
throw new LinkHttpError(
|
|
37363
38361
|
400,
|
|
@@ -37387,7 +38385,7 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37387
38385
|
input.userCharLimit = userCharLimit;
|
|
37388
38386
|
}
|
|
37389
38387
|
}
|
|
37390
|
-
const mode =
|
|
38388
|
+
const mode = readString21(body, "mode");
|
|
37391
38389
|
if (mode) {
|
|
37392
38390
|
input.mode = mode;
|
|
37393
38391
|
}
|
|
@@ -37403,7 +38401,7 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37403
38401
|
if (bankId !== void 0) {
|
|
37404
38402
|
input.bankId = bankId;
|
|
37405
38403
|
}
|
|
37406
|
-
const llmProvider =
|
|
38404
|
+
const llmProvider = readString21(body, "llm_provider") ?? readString21(body, "llmProvider");
|
|
37407
38405
|
if (llmProvider) {
|
|
37408
38406
|
input.llmProvider = llmProvider;
|
|
37409
38407
|
}
|
|
@@ -37439,11 +38437,11 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37439
38437
|
if (autoRetain !== void 0) {
|
|
37440
38438
|
input.autoRetain = autoRetain;
|
|
37441
38439
|
}
|
|
37442
|
-
const memoryMode =
|
|
38440
|
+
const memoryMode = readString21(body, "memory_mode") ?? readString21(body, "memoryMode");
|
|
37443
38441
|
if (memoryMode) {
|
|
37444
38442
|
input.memoryMode = memoryMode;
|
|
37445
38443
|
}
|
|
37446
|
-
const recallBudget =
|
|
38444
|
+
const recallBudget = readString21(body, "recall_budget") ?? readString21(body, "recallBudget");
|
|
37447
38445
|
if (recallBudget) {
|
|
37448
38446
|
input.recallBudget = recallBudget;
|
|
37449
38447
|
}
|
|
@@ -37459,11 +38457,11 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37459
38457
|
if (profileFrequency !== void 0) {
|
|
37460
38458
|
input.profileFrequency = profileFrequency;
|
|
37461
38459
|
}
|
|
37462
|
-
const captureMode =
|
|
38460
|
+
const captureMode = readString21(body, "capture_mode") ?? readString21(body, "captureMode");
|
|
37463
38461
|
if (captureMode) {
|
|
37464
38462
|
input.captureMode = captureMode;
|
|
37465
38463
|
}
|
|
37466
|
-
const searchMode =
|
|
38464
|
+
const searchMode = readString21(body, "search_mode") ?? readString21(body, "searchMode");
|
|
37467
38465
|
if (searchMode) {
|
|
37468
38466
|
input.searchMode = searchMode;
|
|
37469
38467
|
}
|
|
@@ -37497,11 +38495,11 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37497
38495
|
if (aiPeer !== void 0) {
|
|
37498
38496
|
input.aiPeer = aiPeer;
|
|
37499
38497
|
}
|
|
37500
|
-
const recallMode =
|
|
38498
|
+
const recallMode = readString21(body, "recall_mode") ?? readString21(body, "recallMode");
|
|
37501
38499
|
if (recallMode) {
|
|
37502
38500
|
input.recallMode = recallMode;
|
|
37503
38501
|
}
|
|
37504
|
-
const writeFrequency =
|
|
38502
|
+
const writeFrequency = readString21(body, "write_frequency") ?? readString21(body, "writeFrequency");
|
|
37505
38503
|
if (writeFrequency) {
|
|
37506
38504
|
input.writeFrequency = writeFrequency;
|
|
37507
38505
|
}
|
|
@@ -37509,7 +38507,7 @@ function readMemorySettingsPatch(body, options = {}) {
|
|
|
37509
38507
|
if (saveMessages !== void 0) {
|
|
37510
38508
|
input.saveMessages = saveMessages;
|
|
37511
38509
|
}
|
|
37512
|
-
const sessionStrategy =
|
|
38510
|
+
const sessionStrategy = readString21(body, "session_strategy") ?? readString21(body, "sessionStrategy");
|
|
37513
38511
|
if (sessionStrategy) {
|
|
37514
38512
|
input.sessionStrategy = sessionStrategy;
|
|
37515
38513
|
}
|
|
@@ -37789,13 +38787,13 @@ async function readSkillMetadata(input) {
|
|
|
37789
38787
|
const skillDir = path32.dirname(input.skillFile);
|
|
37790
38788
|
const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
|
|
37791
38789
|
const name = normalizeSkillName(
|
|
37792
|
-
|
|
38790
|
+
readString24(frontmatter.name) ?? path32.basename(skillDir)
|
|
37793
38791
|
);
|
|
37794
38792
|
if (!name) {
|
|
37795
38793
|
return null;
|
|
37796
38794
|
}
|
|
37797
38795
|
const description = normalizeDescription(
|
|
37798
|
-
|
|
38796
|
+
readString24(frontmatter.description) ?? firstBodyDescription(body)
|
|
37799
38797
|
);
|
|
37800
38798
|
const provenance = input.provenance.get(name) ?? {
|
|
37801
38799
|
source: "local",
|
|
@@ -37922,8 +38920,8 @@ async function readHubInstalledSkills(root) {
|
|
|
37922
38920
|
for (const [name, rawEntry] of Object.entries(installed2)) {
|
|
37923
38921
|
const entry = toRecord22(rawEntry);
|
|
37924
38922
|
result.set(normalizeSkillName(name), {
|
|
37925
|
-
source:
|
|
37926
|
-
trust:
|
|
38923
|
+
source: readString24(entry.source) ?? "hub",
|
|
38924
|
+
trust: readString24(entry.trust_level) ?? null
|
|
37927
38925
|
});
|
|
37928
38926
|
}
|
|
37929
38927
|
return result;
|
|
@@ -38007,7 +39005,7 @@ function readStringList6(value) {
|
|
|
38007
39005
|
}
|
|
38008
39006
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
38009
39007
|
}
|
|
38010
|
-
function
|
|
39008
|
+
function readString24(value) {
|
|
38011
39009
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
38012
39010
|
}
|
|
38013
39011
|
function toRecord22(value) {
|
|
@@ -38379,7 +39377,7 @@ function registerRunRoutes(router, options) {
|
|
|
38379
39377
|
await authenticateRequest(ctx, paths);
|
|
38380
39378
|
const language = readPreferredLanguage(ctx);
|
|
38381
39379
|
const body = await readJsonBody(ctx.req);
|
|
38382
|
-
const input =
|
|
39380
|
+
const input = readString21(body, "input");
|
|
38383
39381
|
if (!input) {
|
|
38384
39382
|
throw new LinkHttpError(400, "run_input_required", "input is required");
|
|
38385
39383
|
}
|
|
@@ -38387,12 +39385,12 @@ function registerRunRoutes(router, options) {
|
|
|
38387
39385
|
ctx.body = await createHermesRun(
|
|
38388
39386
|
{
|
|
38389
39387
|
input,
|
|
38390
|
-
instructions:
|
|
39388
|
+
instructions: readString21(body, "instructions") ?? void 0,
|
|
38391
39389
|
conversation_history: readConversationHistory(
|
|
38392
39390
|
body.conversation_history ?? body.conversationHistory
|
|
38393
39391
|
),
|
|
38394
|
-
session_id:
|
|
38395
|
-
session_key:
|
|
39392
|
+
session_id: readString21(body, "session_id") ?? readString21(body, "sessionId") ?? void 0,
|
|
39393
|
+
session_key: readString21(body, "session_key") ?? readString21(body, "sessionKey") ?? void 0
|
|
38396
39394
|
},
|
|
38397
39395
|
{ logger, profileName: readOptionalProfileName(body), language }
|
|
38398
39396
|
);
|
|
@@ -38805,20 +39803,20 @@ function normalizeServerReleaseSnapshot(payload) {
|
|
|
38805
39803
|
const remote = toNullableRecord(snapshot.remote);
|
|
38806
39804
|
return {
|
|
38807
39805
|
remote: remote ? normalizeServerRelease(remote) : null,
|
|
38808
|
-
cacheState:
|
|
38809
|
-
issue:
|
|
39806
|
+
cacheState: readString25(snapshot, "cache_state") ?? readString25(snapshot, "cacheState"),
|
|
39807
|
+
issue: readString25(snapshot, "issue")
|
|
38810
39808
|
};
|
|
38811
39809
|
}
|
|
38812
39810
|
function normalizeServerRelease(payload) {
|
|
38813
|
-
const tag =
|
|
38814
|
-
const name =
|
|
39811
|
+
const tag = readString25(payload, "tag");
|
|
39812
|
+
const name = readString25(payload, "name");
|
|
38815
39813
|
return {
|
|
38816
|
-
version:
|
|
39814
|
+
version: readString25(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
|
|
38817
39815
|
tag,
|
|
38818
39816
|
name,
|
|
38819
|
-
releaseUrl:
|
|
38820
|
-
publishedAt:
|
|
38821
|
-
fetchedAt:
|
|
39817
|
+
releaseUrl: readString25(payload, "releaseUrl") ?? readString25(payload, "release_url"),
|
|
39818
|
+
publishedAt: readString25(payload, "publishedAt") ?? readString25(payload, "published_at"),
|
|
39819
|
+
fetchedAt: readString25(payload, "fetchedAt") ?? readString25(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
38822
39820
|
};
|
|
38823
39821
|
}
|
|
38824
39822
|
async function readReleaseCache(paths) {
|
|
@@ -38944,7 +39942,7 @@ function isRecentRunningState2(state) {
|
|
|
38944
39942
|
const startedAt = Date.parse(state.started_at);
|
|
38945
39943
|
return Number.isFinite(startedAt) && Date.now() - startedAt < 3e4;
|
|
38946
39944
|
}
|
|
38947
|
-
function
|
|
39945
|
+
function readString25(payload, key) {
|
|
38948
39946
|
const value = payload[key];
|
|
38949
39947
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
38950
39948
|
}
|
|
@@ -39119,12 +40117,12 @@ async function fetchRelayStreamBatchPolicy(serverBaseUrl, options = {}) {
|
|
|
39119
40117
|
}
|
|
39120
40118
|
}
|
|
39121
40119
|
function readRelayStreamBatchPolicy(input) {
|
|
39122
|
-
const record =
|
|
39123
|
-
const body =
|
|
40120
|
+
const record = readRecord2(input);
|
|
40121
|
+
const body = readRecord2(record?.policy) ?? readRecord2(record?.stream_batching) ?? record;
|
|
39124
40122
|
return normalizeRelayStreamBatchPolicy(body);
|
|
39125
40123
|
}
|
|
39126
40124
|
function normalizeRelayStreamBatchPolicy(input) {
|
|
39127
|
-
const record =
|
|
40125
|
+
const record = readRecord2(input);
|
|
39128
40126
|
if (!record) {
|
|
39129
40127
|
return null;
|
|
39130
40128
|
}
|
|
@@ -39138,7 +40136,7 @@ function normalizeRelayStreamBatchPolicy(input) {
|
|
|
39138
40136
|
flushBytes
|
|
39139
40137
|
};
|
|
39140
40138
|
}
|
|
39141
|
-
function
|
|
40139
|
+
function readRecord2(value) {
|
|
39142
40140
|
return value && typeof value === "object" ? value : null;
|
|
39143
40141
|
}
|
|
39144
40142
|
function readInteger5(value) {
|
|
@@ -40142,7 +41140,7 @@ async function reportLinkStatusToServer(options = {}) {
|
|
|
40142
41140
|
public_ipv6s: routes.publicIpv6s,
|
|
40143
41141
|
reported_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
40144
41142
|
};
|
|
40145
|
-
const signature = signIdentityPayload(identity,
|
|
41143
|
+
const signature = signIdentityPayload(identity, canonicalJson3(payload));
|
|
40146
41144
|
const fetcher = options.fetchImpl ?? fetch;
|
|
40147
41145
|
const response = await fetcher(
|
|
40148
41146
|
`${config.serverBaseUrl.replace(/\/+$/u, "")}/api/v1/links/${encodeURIComponent(identity.link_id)}/report`,
|
|
@@ -40161,30 +41159,30 @@ async function reportLinkStatusToServer(options = {}) {
|
|
|
40161
41159
|
);
|
|
40162
41160
|
const body = await response.json().catch(() => null);
|
|
40163
41161
|
if (!response.ok || !body) {
|
|
40164
|
-
const message =
|
|
41162
|
+
const message = readErrorMessage5(body) ?? `HermesPilot Server request failed with HTTP ${response.status}`;
|
|
40165
41163
|
throw new LinkHttpError(response.status, "server_request_failed", message);
|
|
40166
41164
|
}
|
|
40167
41165
|
await markNetworkStatusReported(paths, routes);
|
|
40168
41166
|
return body;
|
|
40169
41167
|
}
|
|
40170
|
-
function
|
|
40171
|
-
return JSON.stringify(
|
|
41168
|
+
function canonicalJson3(value) {
|
|
41169
|
+
return JSON.stringify(sortJsonValue3(value));
|
|
40172
41170
|
}
|
|
40173
|
-
function
|
|
41171
|
+
function sortJsonValue3(value) {
|
|
40174
41172
|
if (Array.isArray(value)) {
|
|
40175
|
-
return value.map(
|
|
41173
|
+
return value.map(sortJsonValue3);
|
|
40176
41174
|
}
|
|
40177
41175
|
if (value && typeof value === "object") {
|
|
40178
41176
|
const record = value;
|
|
40179
41177
|
const sorted = {};
|
|
40180
41178
|
for (const key of Object.keys(record).sort()) {
|
|
40181
|
-
sorted[key] =
|
|
41179
|
+
sorted[key] = sortJsonValue3(record[key]);
|
|
40182
41180
|
}
|
|
40183
41181
|
return sorted;
|
|
40184
41182
|
}
|
|
40185
41183
|
return value;
|
|
40186
41184
|
}
|
|
40187
|
-
function
|
|
41185
|
+
function readErrorMessage5(payload) {
|
|
40188
41186
|
if (typeof payload !== "object" || payload === null) {
|
|
40189
41187
|
return null;
|
|
40190
41188
|
}
|
|
@@ -40204,20 +41202,23 @@ function startLanIpMonitor(options) {
|
|
|
40204
41202
|
let running = false;
|
|
40205
41203
|
let closed = false;
|
|
40206
41204
|
let current = Promise.resolve();
|
|
40207
|
-
const check =
|
|
41205
|
+
const check = (context = {}) => {
|
|
40208
41206
|
if (running || closed) {
|
|
40209
|
-
return;
|
|
41207
|
+
return current;
|
|
40210
41208
|
}
|
|
40211
41209
|
running = true;
|
|
40212
|
-
|
|
40213
|
-
|
|
40214
|
-
|
|
40215
|
-
|
|
40216
|
-
|
|
40217
|
-
|
|
40218
|
-
|
|
40219
|
-
|
|
40220
|
-
|
|
41210
|
+
current = (async () => {
|
|
41211
|
+
try {
|
|
41212
|
+
await checkLanIpChange(options, context);
|
|
41213
|
+
} catch (error) {
|
|
41214
|
+
void options.logger.warn("lan_ip_monitor_failed", {
|
|
41215
|
+
error: error instanceof Error ? error.message : String(error)
|
|
41216
|
+
});
|
|
41217
|
+
} finally {
|
|
41218
|
+
running = false;
|
|
41219
|
+
}
|
|
41220
|
+
})();
|
|
41221
|
+
return current;
|
|
40221
41222
|
};
|
|
40222
41223
|
current = check({ forceReport: true, publishToRelay: true, observePublicRoute: true });
|
|
40223
41224
|
const timer = setInterval(() => {
|
|
@@ -40931,7 +41932,8 @@ async function startDaemonProcess(paths = resolveRuntimePaths()) {
|
|
|
40931
41932
|
const child = spawn5(process.execPath, [scriptPath, "daemon-supervisor"], {
|
|
40932
41933
|
detached: true,
|
|
40933
41934
|
stdio: "ignore",
|
|
40934
|
-
env: process.env
|
|
41935
|
+
env: process.env,
|
|
41936
|
+
windowsHide: true
|
|
40935
41937
|
});
|
|
40936
41938
|
child.unref();
|
|
40937
41939
|
for (let index = 0; index < 12; index += 1) {
|
|
@@ -40984,7 +41986,8 @@ async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
|
|
|
40984
41986
|
const startedAt = Date.now();
|
|
40985
41987
|
child = spawn5(process.execPath, [scriptPath, "daemon", "--foreground"], {
|
|
40986
41988
|
stdio: ["ignore", "pipe", "pipe"],
|
|
40987
|
-
env: process.env
|
|
41989
|
+
env: process.env,
|
|
41990
|
+
windowsHide: true
|
|
40988
41991
|
});
|
|
40989
41992
|
const childPid = child.pid ?? null;
|
|
40990
41993
|
child.stdout?.on("data", write);
|
|
@@ -41725,16 +42728,16 @@ function normalizeServerSnapshot(payload) {
|
|
|
41725
42728
|
if (!policy) {
|
|
41726
42729
|
return {
|
|
41727
42730
|
remote: null,
|
|
41728
|
-
issue:
|
|
42731
|
+
issue: readString26(snapshot, "issue")
|
|
41729
42732
|
};
|
|
41730
42733
|
}
|
|
41731
42734
|
const release = toNullableRecord2(snapshot.release);
|
|
41732
|
-
const currentVersion =
|
|
41733
|
-
const minSafeVersion =
|
|
42735
|
+
const currentVersion = readString26(policy, "current_version") ?? readString26(policy, "currentVersion");
|
|
42736
|
+
const minSafeVersion = readString26(policy, "min_safe_version") ?? readString26(policy, "minSafeVersion");
|
|
41734
42737
|
if (!currentVersion) {
|
|
41735
42738
|
return {
|
|
41736
42739
|
remote: null,
|
|
41737
|
-
issue:
|
|
42740
|
+
issue: readString26(snapshot, "issue")
|
|
41738
42741
|
};
|
|
41739
42742
|
}
|
|
41740
42743
|
return {
|
|
@@ -41742,10 +42745,10 @@ function normalizeServerSnapshot(payload) {
|
|
|
41742
42745
|
current_version: currentVersion,
|
|
41743
42746
|
min_safe_version: minSafeVersion,
|
|
41744
42747
|
target_version: currentVersion,
|
|
41745
|
-
release_url: release ?
|
|
41746
|
-
published_at: release ?
|
|
42748
|
+
release_url: release ? readString26(release, "release_url") ?? readString26(release, "releaseUrl") : null,
|
|
42749
|
+
published_at: release ? readString26(release, "published_at") ?? readString26(release, "publishedAt") : null
|
|
41747
42750
|
},
|
|
41748
|
-
issue:
|
|
42751
|
+
issue: readString26(snapshot, "issue")
|
|
41749
42752
|
};
|
|
41750
42753
|
}
|
|
41751
42754
|
async function fetchCurrentLinkReleaseFromServer(options, fetcher, channel) {
|
|
@@ -42159,7 +43162,7 @@ function toRecord25(value) {
|
|
|
42159
43162
|
function toNullableRecord2(value) {
|
|
42160
43163
|
return typeof value === "object" && value !== null ? value : null;
|
|
42161
43164
|
}
|
|
42162
|
-
function
|
|
43165
|
+
function readString26(payload, key) {
|
|
42163
43166
|
const value = payload[key];
|
|
42164
43167
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
42165
43168
|
}
|
|
@@ -42239,7 +43242,7 @@ async function postJson(fetcher, url, token, body) {
|
|
|
42239
43242
|
}
|
|
42240
43243
|
const payload = await response.json().catch(() => null);
|
|
42241
43244
|
if (!response.ok) {
|
|
42242
|
-
const message =
|
|
43245
|
+
const message = readErrorMessage6(payload) ?? `Relay request failed with HTTP ${response.status}`;
|
|
42243
43246
|
throw new Error(message);
|
|
42244
43247
|
}
|
|
42245
43248
|
if (!payload) {
|
|
@@ -42247,7 +43250,7 @@ async function postJson(fetcher, url, token, body) {
|
|
|
42247
43250
|
}
|
|
42248
43251
|
return payload;
|
|
42249
43252
|
}
|
|
42250
|
-
function
|
|
43253
|
+
function readErrorMessage6(payload) {
|
|
42251
43254
|
if (typeof payload !== "object" || payload === null) {
|
|
42252
43255
|
return null;
|
|
42253
43256
|
}
|
|
@@ -42581,12 +43584,12 @@ async function patchServerJson(serverBaseUrl, path37, token, body, options) {
|
|
|
42581
43584
|
async function readJsonResponse2(response) {
|
|
42582
43585
|
const payload = await response.json().catch(() => null);
|
|
42583
43586
|
if (!response.ok || !payload) {
|
|
42584
|
-
const message =
|
|
43587
|
+
const message = readErrorMessage7(payload) ?? `HermesPilot Server request failed with HTTP ${response.status}`;
|
|
42585
43588
|
throw new LinkHttpError(response.status, "server_request_failed", message);
|
|
42586
43589
|
}
|
|
42587
43590
|
return payload;
|
|
42588
43591
|
}
|
|
42589
|
-
function
|
|
43592
|
+
function readErrorMessage7(payload) {
|
|
42590
43593
|
if (typeof payload !== "object" || payload === null) {
|
|
42591
43594
|
return null;
|
|
42592
43595
|
}
|
|
@@ -42705,14 +43708,15 @@ function registerSystemRoutes(router, options) {
|
|
|
42705
43708
|
profile_skills: true,
|
|
42706
43709
|
profile_memory: true,
|
|
42707
43710
|
hermes_updates: true,
|
|
42708
|
-
app_push_notification_events: true
|
|
43711
|
+
app_push_notification_events: true,
|
|
43712
|
+
live_activity_progress_events: true
|
|
42709
43713
|
}
|
|
42710
43714
|
};
|
|
42711
43715
|
});
|
|
42712
43716
|
router.post("/api/v1/pairing/claim", async (ctx) => {
|
|
42713
43717
|
const body = await readJsonBody(ctx.req);
|
|
42714
|
-
const sessionId =
|
|
42715
|
-
const claimToken =
|
|
43718
|
+
const sessionId = readString21(body, "session_id") ?? readString21(body, "sessionId");
|
|
43719
|
+
const claimToken = readString21(body, "claim_token") ?? readString21(body, "claimToken");
|
|
42716
43720
|
if (!sessionId || !claimToken) {
|
|
42717
43721
|
throw new LinkHttpError(
|
|
42718
43722
|
400,
|
|
@@ -42723,10 +43727,10 @@ function registerSystemRoutes(router, options) {
|
|
|
42723
43727
|
const claimed = await claimPairing({
|
|
42724
43728
|
sessionId,
|
|
42725
43729
|
claimToken,
|
|
42726
|
-
deviceLabel:
|
|
42727
|
-
devicePlatform:
|
|
42728
|
-
deviceModel:
|
|
42729
|
-
appInstanceId:
|
|
43730
|
+
deviceLabel: readString21(body, "device_label") ?? readString21(body, "deviceLabel") ?? "HermesPilot App",
|
|
43731
|
+
devicePlatform: readString21(body, "device_platform") ?? readString21(body, "devicePlatform") ?? "unknown",
|
|
43732
|
+
deviceModel: readString21(body, "device_model") ?? readString21(body, "deviceModel"),
|
|
43733
|
+
appInstanceId: readString21(body, "app_instance_id") ?? readString21(body, "appInstanceId"),
|
|
42730
43734
|
paths
|
|
42731
43735
|
});
|
|
42732
43736
|
ctx.body = claimed;
|
|
@@ -42806,9 +43810,9 @@ function registerSystemRoutes(router, options) {
|
|
|
42806
43810
|
const body = await readJsonBody(ctx.req);
|
|
42807
43811
|
const session = await createDeviceSession(
|
|
42808
43812
|
{
|
|
42809
|
-
label:
|
|
42810
|
-
platform:
|
|
42811
|
-
model:
|
|
43813
|
+
label: readString21(body, "device_label") ?? readString21(body, "deviceLabel") ?? "HermesPilot App",
|
|
43814
|
+
platform: readString21(body, "device_platform") ?? readString21(body, "devicePlatform") ?? "unknown",
|
|
43815
|
+
model: readString21(body, "device_model") ?? readString21(body, "deviceModel"),
|
|
42812
43816
|
appInstanceId: auth.appInstanceId
|
|
42813
43817
|
},
|
|
42814
43818
|
paths
|
|
@@ -42837,7 +43841,7 @@ function registerSystemRoutes(router, options) {
|
|
|
42837
43841
|
});
|
|
42838
43842
|
router.post("/api/v1/auth/refresh", async (ctx) => {
|
|
42839
43843
|
const body = await readJsonBody(ctx.req);
|
|
42840
|
-
const refreshToken =
|
|
43844
|
+
const refreshToken = readString21(body, "refresh_token") ?? readString21(body, "refreshToken");
|
|
42841
43845
|
if (!refreshToken) {
|
|
42842
43846
|
throw new LinkHttpError(
|
|
42843
43847
|
400,
|
|
@@ -42848,10 +43852,10 @@ function registerSystemRoutes(router, options) {
|
|
|
42848
43852
|
const session = await refreshDeviceSession(
|
|
42849
43853
|
refreshToken,
|
|
42850
43854
|
{
|
|
42851
|
-
appInstanceId:
|
|
42852
|
-
label:
|
|
42853
|
-
platform:
|
|
42854
|
-
model:
|
|
43855
|
+
appInstanceId: readString21(body, "app_instance_id") ?? readString21(body, "appInstanceId"),
|
|
43856
|
+
label: readString21(body, "device_label") ?? readString21(body, "deviceLabel"),
|
|
43857
|
+
platform: readString21(body, "device_platform") ?? readString21(body, "devicePlatform"),
|
|
43858
|
+
model: readString21(body, "device_model") ?? readString21(body, "deviceModel")
|
|
42855
43859
|
},
|
|
42856
43860
|
paths
|
|
42857
43861
|
);
|
|
@@ -42870,7 +43874,7 @@ function registerSystemRoutes(router, options) {
|
|
|
42870
43874
|
});
|
|
42871
43875
|
router.post("/api/v1/auth/logout", async (ctx) => {
|
|
42872
43876
|
const body = await readJsonBody(ctx.req);
|
|
42873
|
-
const refreshToken =
|
|
43877
|
+
const refreshToken = readString21(body, "refresh_token") ?? readString21(body, "refreshToken");
|
|
42874
43878
|
if (refreshToken) {
|
|
42875
43879
|
await revokeDeviceRefreshToken(refreshToken, paths);
|
|
42876
43880
|
}
|
|
@@ -43111,7 +44115,7 @@ function registerSystemRoutes(router, options) {
|
|
|
43111
44115
|
router.patch("/api/v1/devices/:deviceId", async (ctx) => {
|
|
43112
44116
|
const auth = await authenticateRequest(ctx, paths);
|
|
43113
44117
|
const body = await readJsonBody(ctx.req);
|
|
43114
|
-
const label =
|
|
44118
|
+
const label = readString21(body, "label") ?? readString21(body, "device_label");
|
|
43115
44119
|
if (!label) {
|
|
43116
44120
|
throw new LinkHttpError(
|
|
43117
44121
|
400,
|
|
@@ -43155,7 +44159,7 @@ function isActiveCronJob(job) {
|
|
|
43155
44159
|
if (!enabled) {
|
|
43156
44160
|
return false;
|
|
43157
44161
|
}
|
|
43158
|
-
const state =
|
|
44162
|
+
const state = readString21(job, "state")?.toLowerCase();
|
|
43159
44163
|
return !["paused", "disabled", "completed", "deleted"].includes(state ?? "");
|
|
43160
44164
|
}
|
|
43161
44165
|
function filterLogsWithinHours(logs, hours, now = Date.now()) {
|
|
@@ -43199,8 +44203,8 @@ function registerWorkspaceRoutes(router, options) {
|
|
|
43199
44203
|
ctx.body = {
|
|
43200
44204
|
ok: true,
|
|
43201
44205
|
workspace: await conversations.createWorkspace({
|
|
43202
|
-
name:
|
|
43203
|
-
icon:
|
|
44206
|
+
name: readString21(body, "name") ?? "",
|
|
44207
|
+
icon: readString21(body, "icon") ?? void 0
|
|
43204
44208
|
})
|
|
43205
44209
|
};
|
|
43206
44210
|
});
|
|
@@ -43210,8 +44214,8 @@ function registerWorkspaceRoutes(router, options) {
|
|
|
43210
44214
|
ctx.body = {
|
|
43211
44215
|
ok: true,
|
|
43212
44216
|
workspace: await conversations.renameWorkspace(ctx.params.workspaceId, {
|
|
43213
|
-
name:
|
|
43214
|
-
icon:
|
|
44217
|
+
name: readString21(body, "name") ?? "",
|
|
44218
|
+
icon: readString21(body, "icon") ?? void 0
|
|
43215
44219
|
})
|
|
43216
44220
|
};
|
|
43217
44221
|
});
|
|
@@ -43294,8 +44298,8 @@ function registerLinkUpdateRoutes(router, options) {
|
|
|
43294
44298
|
ctx.body = await startLinkUpdate({
|
|
43295
44299
|
paths,
|
|
43296
44300
|
logger,
|
|
43297
|
-
channel:
|
|
43298
|
-
targetVersion:
|
|
44301
|
+
channel: readString21(body, "channel"),
|
|
44302
|
+
targetVersion: readString21(body, "target_version") ?? readString21(body, "targetVersion")
|
|
43299
44303
|
});
|
|
43300
44304
|
});
|
|
43301
44305
|
router.get("/api/v1/link/update/events", async (ctx) => {
|
|
@@ -43325,7 +44329,7 @@ import QRCode from "qrcode";
|
|
|
43325
44329
|
function registerPairingRoutes(router, options) {
|
|
43326
44330
|
const { paths } = options;
|
|
43327
44331
|
router.get("/pair", async (ctx) => {
|
|
43328
|
-
const sessionId =
|
|
44332
|
+
const sessionId = readString21(ctx.query, "session_id");
|
|
43329
44333
|
if (!sessionId) {
|
|
43330
44334
|
throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
|
|
43331
44335
|
}
|
|
@@ -43350,7 +44354,7 @@ function registerPairingRoutes(router, options) {
|
|
|
43350
44354
|
ctx.body = page;
|
|
43351
44355
|
});
|
|
43352
44356
|
router.get("/api/v1/pairing/session", async (ctx) => {
|
|
43353
|
-
const sessionId =
|
|
44357
|
+
const sessionId = readString21(ctx.query, "session_id");
|
|
43354
44358
|
if (!sessionId) {
|
|
43355
44359
|
throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
|
|
43356
44360
|
}
|
|
@@ -43820,7 +44824,7 @@ function registerInternalRoutes(router, options) {
|
|
|
43820
44824
|
router.post("/internal/deliver", async (ctx) => {
|
|
43821
44825
|
assertLoopbackRequest(ctx.req);
|
|
43822
44826
|
const body = await readJsonBody(ctx.req);
|
|
43823
|
-
const stagingDir =
|
|
44827
|
+
const stagingDir = readString21(body, "staging_dir") ?? readString21(body, "stagingDir");
|
|
43824
44828
|
if (!stagingDir) {
|
|
43825
44829
|
throw new LinkHttpError(
|
|
43826
44830
|
400,
|
|
@@ -43839,9 +44843,9 @@ function registerInternalRoutes(router, options) {
|
|
|
43839
44843
|
ctx.body = {
|
|
43840
44844
|
ok: true,
|
|
43841
44845
|
...await options.conversations.deliverFilesFromTool({
|
|
43842
|
-
profile:
|
|
43843
|
-
taskId:
|
|
43844
|
-
sessionId:
|
|
44846
|
+
profile: readString21(body, "profile") ?? readString21(body, "profile_name") ?? readString21(body, "profileName") ?? void 0,
|
|
44847
|
+
taskId: readString21(body, "task_id") ?? readString21(body, "taskId") ?? void 0,
|
|
44848
|
+
sessionId: readString21(body, "session_id") ?? readString21(body, "sessionId") ?? void 0,
|
|
43845
44849
|
files: body.files ?? body.file ?? body.path
|
|
43846
44850
|
})
|
|
43847
44851
|
};
|
|
@@ -43859,6 +44863,178 @@ function assertLoopbackRequest(request) {
|
|
|
43859
44863
|
);
|
|
43860
44864
|
}
|
|
43861
44865
|
|
|
44866
|
+
// src/http/routes/live-activities.ts
|
|
44867
|
+
var APP_INSTANCE_ID_PATTERN = /^appi_[A-Za-z0-9_-]{16,96}$/u;
|
|
44868
|
+
var LINK_ID_PATTERN = /^link_[A-Za-z0-9_-]{8,128}$/u;
|
|
44869
|
+
var CONVERSATION_ID_PATTERN2 = /^conv_[A-Za-z0-9_-]{8,128}$/u;
|
|
44870
|
+
var ACTIVITY_ID_PATTERN = /^[A-Za-z0-9._:-]{3,128}$/u;
|
|
44871
|
+
var TARGET_ID_PATTERN = /^[A-Za-z0-9._:-]{3,128}$/u;
|
|
44872
|
+
var RUN_ID_PATTERN = /^run_[A-Za-z0-9_-]{8,128}$/u;
|
|
44873
|
+
var OPERATION_ID_PATTERN = /^[A-Za-z0-9._:-]{3,128}$/u;
|
|
44874
|
+
var APNS_TOKEN_PATTERN = /^[0-9a-fA-F]{32,512}$/u;
|
|
44875
|
+
function registerLiveActivityRoutes(router, options) {
|
|
44876
|
+
const { paths } = options;
|
|
44877
|
+
router.get("/api/v1/live-activities/restore-state", async (ctx) => {
|
|
44878
|
+
const auth = await authenticateRequest(ctx, paths);
|
|
44879
|
+
const query = ctx.query;
|
|
44880
|
+
const targetKind = readTargetKindValue(
|
|
44881
|
+
readQueryValue(query, "target_kind") ?? readQueryValue(query, "targetKind")
|
|
44882
|
+
);
|
|
44883
|
+
const appInstanceId = auth.appInstanceId ?? readRequiredQueryPattern(query, ["app_instance_id", "appInstanceId"], APP_INSTANCE_ID_PATTERN, "app_instance_id_invalid");
|
|
44884
|
+
const state = await findLiveActivityRestoreState(paths, {
|
|
44885
|
+
accountId: auth.accountId ?? null,
|
|
44886
|
+
appInstanceId,
|
|
44887
|
+
conversationId: readRequiredQueryPattern(query, ["conversation_id", "conversationId"], CONVERSATION_ID_PATTERN2, "conversation_id_invalid"),
|
|
44888
|
+
targetKind,
|
|
44889
|
+
targetId: readRequiredQueryPattern(query, ["target_id", "targetId"], TARGET_ID_PATTERN, "target_id_invalid")
|
|
44890
|
+
});
|
|
44891
|
+
ctx.body = {
|
|
44892
|
+
ok: true,
|
|
44893
|
+
state: state ? {
|
|
44894
|
+
phase: state.phase,
|
|
44895
|
+
status_label: state.statusLabel,
|
|
44896
|
+
progress_text: state.progressText,
|
|
44897
|
+
detail_text: state.detailText ?? null,
|
|
44898
|
+
updated_at: state.updatedAt ?? null
|
|
44899
|
+
} : null
|
|
44900
|
+
};
|
|
44901
|
+
});
|
|
44902
|
+
router.post("/api/v1/live-activities", async (ctx) => {
|
|
44903
|
+
const auth = await authenticateRequest(ctx, paths);
|
|
44904
|
+
const body = await readJsonBody(ctx.req);
|
|
44905
|
+
const targetKind = readTargetKind(body);
|
|
44906
|
+
const runId = normalizePattern(readString21(body, "run_id") ?? readString21(body, "runId"), RUN_ID_PATTERN);
|
|
44907
|
+
const operationId = normalizePattern(
|
|
44908
|
+
readString21(body, "operation_id") ?? readString21(body, "operationId"),
|
|
44909
|
+
OPERATION_ID_PATTERN
|
|
44910
|
+
);
|
|
44911
|
+
if (targetKind === "run" && !runId) {
|
|
44912
|
+
throw new LinkHttpError(400, "run_id_required", "run_id is required for run Live Activity");
|
|
44913
|
+
}
|
|
44914
|
+
if (targetKind === "context_compression" && !operationId) {
|
|
44915
|
+
throw new LinkHttpError(400, "operation_id_required", "operation_id is required for context compression Live Activity");
|
|
44916
|
+
}
|
|
44917
|
+
const activity = await upsertLiveActivity(paths, {
|
|
44918
|
+
activityId: readRequiredPattern(body, ["activity_id", "activityId"], ACTIVITY_ID_PATTERN, "activity_id_invalid"),
|
|
44919
|
+
activityToken: readRequiredPattern(body, ["activity_token", "activityToken"], APNS_TOKEN_PATTERN, "activity_token_invalid").toLowerCase(),
|
|
44920
|
+
apnsEnvironment: readApnsEnvironment(body),
|
|
44921
|
+
apnsTopic: readRequiredString(body, ["apns_topic", "apnsTopic"], "apns_topic_required").slice(0, 160),
|
|
44922
|
+
linkId: readRequiredPattern(body, ["link_id", "linkId"], LINK_ID_PATTERN, "link_id_invalid"),
|
|
44923
|
+
accountId: auth.accountId ?? null,
|
|
44924
|
+
appInstanceId: auth.appInstanceId ?? readRequiredPattern(body, ["app_instance_id", "appInstanceId"], APP_INSTANCE_ID_PATTERN, "app_instance_id_invalid"),
|
|
44925
|
+
conversationId: readRequiredPattern(body, ["conversation_id", "conversationId"], CONVERSATION_ID_PATTERN2, "conversation_id_invalid"),
|
|
44926
|
+
conversationTitle: readOptionalString2(body, ["conversation_title", "conversationTitle", "title"], 80),
|
|
44927
|
+
targetKind,
|
|
44928
|
+
targetId: readRequiredPattern(body, ["target_id", "targetId"], TARGET_ID_PATTERN, "target_id_invalid"),
|
|
44929
|
+
runId: targetKind === "run" ? runId : null,
|
|
44930
|
+
operationId: targetKind === "context_compression" ? operationId : null,
|
|
44931
|
+
language: readLanguage2(body),
|
|
44932
|
+
privacyLevel: readPrivacyLevel(body),
|
|
44933
|
+
startedAt: readIso(body, ["started_at", "startedAt"]) ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
44934
|
+
});
|
|
44935
|
+
ctx.status = 201;
|
|
44936
|
+
ctx.body = {
|
|
44937
|
+
ok: true,
|
|
44938
|
+
activity_id: activity.activityId,
|
|
44939
|
+
status: activity.status
|
|
44940
|
+
};
|
|
44941
|
+
});
|
|
44942
|
+
router.post("/api/v1/live-activities/:activityId/end", async (ctx) => {
|
|
44943
|
+
await authenticateRequest(ctx, paths);
|
|
44944
|
+
const found = await endLiveActivity(paths, ctx.params.activityId);
|
|
44945
|
+
ctx.status = found ? 200 : 404;
|
|
44946
|
+
ctx.body = {
|
|
44947
|
+
ok: found,
|
|
44948
|
+
activity_id: ctx.params.activityId,
|
|
44949
|
+
status: found ? "ended" : "not_found"
|
|
44950
|
+
};
|
|
44951
|
+
});
|
|
44952
|
+
}
|
|
44953
|
+
function readTargetKind(body) {
|
|
44954
|
+
const value = readString21(body, "target_kind") ?? readString21(body, "targetKind");
|
|
44955
|
+
return readTargetKindValue(value);
|
|
44956
|
+
}
|
|
44957
|
+
function readTargetKindValue(value) {
|
|
44958
|
+
if (value === "run" || value === "context_compression") {
|
|
44959
|
+
return value;
|
|
44960
|
+
}
|
|
44961
|
+
throw new LinkHttpError(400, "target_kind_invalid", "target_kind must be run or context_compression");
|
|
44962
|
+
}
|
|
44963
|
+
function readRequiredQueryPattern(query, keys, pattern, code) {
|
|
44964
|
+
for (const key of keys) {
|
|
44965
|
+
const value = readQueryValue(query, key);
|
|
44966
|
+
if (value && pattern.test(value)) {
|
|
44967
|
+
return value;
|
|
44968
|
+
}
|
|
44969
|
+
}
|
|
44970
|
+
throw new LinkHttpError(400, code, `${keys[0]} is invalid`);
|
|
44971
|
+
}
|
|
44972
|
+
function readQueryValue(query, key) {
|
|
44973
|
+
return readQueryString(query[key]) ?? null;
|
|
44974
|
+
}
|
|
44975
|
+
function readApnsEnvironment(body) {
|
|
44976
|
+
const value = readString21(body, "apns_environment") ?? readString21(body, "apnsEnvironment");
|
|
44977
|
+
if (value === "sandbox" || value === "production") {
|
|
44978
|
+
return value;
|
|
44979
|
+
}
|
|
44980
|
+
throw new LinkHttpError(400, "apns_environment_invalid", "apns_environment must be sandbox or production");
|
|
44981
|
+
}
|
|
44982
|
+
function readLanguage2(body) {
|
|
44983
|
+
const value = readString21(body, "language") ?? readString21(body, "preferred_language") ?? readString21(body, "preferredLanguage");
|
|
44984
|
+
if (!value) {
|
|
44985
|
+
return null;
|
|
44986
|
+
}
|
|
44987
|
+
return value.toLowerCase().startsWith("zh") ? "zh" : "en";
|
|
44988
|
+
}
|
|
44989
|
+
function readPrivacyLevel(body) {
|
|
44990
|
+
const value = readString21(body, "privacy_level") ?? readString21(body, "privacyLevel");
|
|
44991
|
+
if (value === "minimal" || value === "detailed") {
|
|
44992
|
+
return value;
|
|
44993
|
+
}
|
|
44994
|
+
return "summary";
|
|
44995
|
+
}
|
|
44996
|
+
function readRequiredString(body, keys, code) {
|
|
44997
|
+
for (const key of keys) {
|
|
44998
|
+
const value = readString21(body, key);
|
|
44999
|
+
if (value) {
|
|
45000
|
+
return value;
|
|
45001
|
+
}
|
|
45002
|
+
}
|
|
45003
|
+
throw new LinkHttpError(400, code, `${keys[0]} is required`);
|
|
45004
|
+
}
|
|
45005
|
+
function readRequiredPattern(body, keys, pattern, code) {
|
|
45006
|
+
const value = readRequiredString(body, keys, code);
|
|
45007
|
+
if (!pattern.test(value)) {
|
|
45008
|
+
throw new LinkHttpError(400, code, `${keys[0]} is invalid`);
|
|
45009
|
+
}
|
|
45010
|
+
return value;
|
|
45011
|
+
}
|
|
45012
|
+
function readOptionalString2(body, keys, maxLength) {
|
|
45013
|
+
for (const key of keys) {
|
|
45014
|
+
const value = readString21(body, key);
|
|
45015
|
+
if (value) {
|
|
45016
|
+
return value.slice(0, maxLength);
|
|
45017
|
+
}
|
|
45018
|
+
}
|
|
45019
|
+
return null;
|
|
45020
|
+
}
|
|
45021
|
+
function normalizePattern(value, pattern) {
|
|
45022
|
+
return value && pattern.test(value) ? value : null;
|
|
45023
|
+
}
|
|
45024
|
+
function readIso(body, keys) {
|
|
45025
|
+
for (const key of keys) {
|
|
45026
|
+
const value = readString21(body, key);
|
|
45027
|
+
if (!value) {
|
|
45028
|
+
continue;
|
|
45029
|
+
}
|
|
45030
|
+
const timestamp = Date.parse(value);
|
|
45031
|
+
if (Number.isFinite(timestamp)) {
|
|
45032
|
+
return new Date(timestamp).toISOString();
|
|
45033
|
+
}
|
|
45034
|
+
}
|
|
45035
|
+
return null;
|
|
45036
|
+
}
|
|
45037
|
+
|
|
43862
45038
|
// src/http/app.ts
|
|
43863
45039
|
async function createApp(options = {}) {
|
|
43864
45040
|
const paths = options.paths ?? resolveRuntimePaths();
|
|
@@ -43916,6 +45092,7 @@ async function createApp(options = {}) {
|
|
|
43916
45092
|
syncCronDeliveries
|
|
43917
45093
|
});
|
|
43918
45094
|
registerWorkspaceRoutes(router, { paths, conversations });
|
|
45095
|
+
registerLiveActivityRoutes(router, { paths });
|
|
43919
45096
|
registerConversationRoutes(router, { paths, logger, conversations });
|
|
43920
45097
|
registerRunRoutes(router, { paths, logger, conversations });
|
|
43921
45098
|
registerProfileRoutes(router, { paths, logger, conversations });
|