@hermespilot/link 0.5.8 → 0.6.0

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.
@@ -4425,7 +4425,7 @@ async function listCronOutputFiles(profileName, jobId) {
4425
4425
  mtimeMs: fileStat.mtimeMs
4426
4426
  });
4427
4427
  }
4428
- return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path: path27, mtime }) => ({ path: path27, mtime }));
4428
+ return files.sort((left, right) => left.mtimeMs - right.mtimeMs).map(({ path: path28, mtime }) => ({ path: path28, mtime }));
4429
4429
  }
4430
4430
  async function readCronOutput(outputPath) {
4431
4431
  const content = await readFile3(outputPath, "utf8");
@@ -4502,7 +4502,7 @@ import os2 from "os";
4502
4502
  import path5 from "path";
4503
4503
 
4504
4504
  // src/constants.ts
4505
- var LINK_VERSION = "0.5.8";
4505
+ var LINK_VERSION = "0.6.0";
4506
4506
  var LINK_COMMAND = "hermeslink";
4507
4507
  var LINK_DEFAULT_PORT = 52379;
4508
4508
  var LINK_RUNTIME_DIR_NAME = ".hermeslink";
@@ -6375,6 +6375,27 @@ function estimateContextUsage(input) {
6375
6375
  context_source: "estimated"
6376
6376
  };
6377
6377
  }
6378
+ function resolveRuntimeContextUsage(input) {
6379
+ const usage = input.usage;
6380
+ const contextWindow = input.contextWindow ?? usage?.context_window;
6381
+ if (!usage) {
6382
+ return { source: "unknown", contextWindow };
6383
+ }
6384
+ const explicitContextTokens = usage.context_tokens !== void 0 && usage.context_source !== "estimated" ? usage.context_tokens : void 0;
6385
+ const estimatedContextTokens = usage.context_tokens !== void 0 && usage.context_source === "estimated" ? usage.context_tokens : void 0;
6386
+ const contextTokens = explicitContextTokens ?? (usage.total_tokens > 0 ? usage.total_tokens : void 0) ?? estimatedContextTokens;
6387
+ if (contextTokens === void 0) {
6388
+ return { source: "unknown", contextWindow };
6389
+ }
6390
+ const source = explicitContextTokens !== void 0 || usage.total_tokens > 0 ? "explicit" : "estimated";
6391
+ const computedPercent = contextWindow && contextWindow > 0 ? Math.min(100, Math.round(contextTokens / contextWindow * 100)) : void 0;
6392
+ return {
6393
+ contextTokens,
6394
+ contextWindow,
6395
+ source,
6396
+ usagePercent: explicitContextTokens !== void 0 || source === "estimated" ? usage.usage_percent ?? computedPercent : computedPercent
6397
+ };
6398
+ }
6378
6399
  function isAgentRun(run) {
6379
6400
  return run.kind !== "command";
6380
6401
  }
@@ -7116,9 +7137,12 @@ async function buildConversationRuntimeMetadata(paths, manifest, snapshot) {
7116
7137
  output_tokens: 0,
7117
7138
  total_tokens: 0
7118
7139
  };
7119
- const contextWindow = current.contextWindow ?? usage.context_window ?? usageRun?.context_window;
7120
- const contextTokens = usage.context_tokens;
7121
- const contextSource = contextTokens === void 0 ? "unknown" : usage.context_source ?? "explicit";
7140
+ const runtimeContext = resolveRuntimeContextUsage({
7141
+ usage: usageRun?.usage,
7142
+ contextWindow: current.contextWindow ?? usage.context_window ?? usageRun?.context_window
7143
+ });
7144
+ const contextTokens = runtimeContext.contextTokens;
7145
+ const contextWindow = runtimeContext.contextWindow;
7122
7146
  const provider = current.provider ?? usageRun?.provider;
7123
7147
  const reasoningEffort = current.reasoningEffort;
7124
7148
  return {
@@ -7141,13 +7165,8 @@ async function buildConversationRuntimeMetadata(paths, manifest, snapshot) {
7141
7165
  ...contextWindow ? { context_window: contextWindow } : {},
7142
7166
  ...contextTokens !== void 0 ? { used_tokens: contextTokens } : {},
7143
7167
  ...contextWindow ? { window_tokens: contextWindow } : {},
7144
- source: contextSource,
7145
- ...contextWindow && contextTokens !== void 0 ? {
7146
- usage_percent: Math.min(
7147
- 100,
7148
- usage.usage_percent ?? Math.round(contextTokens / contextWindow * 100)
7149
- )
7150
- } : {},
7168
+ source: runtimeContext.source,
7169
+ ...runtimeContext.usagePercent !== void 0 ? { usage_percent: runtimeContext.usagePercent } : {},
7151
7170
  ...usageRun?.completed_at ? { updated_at: usageRun.completed_at } : {}
7152
7171
  }
7153
7172
  };
@@ -9998,10 +10017,12 @@ function upsertAgentEventProjection(events, next) {
9998
10017
  next.subtitle,
9999
10018
  next.title
10000
10019
  );
10020
+ const status = next.status === "running" && previous.status !== "running" ? previous.status : next.status;
10001
10021
  const merged = {
10002
10022
  ...previous,
10003
10023
  ...next,
10004
10024
  id: previous.id,
10025
+ status,
10005
10026
  title: isGenericToolTitle(next.title) ? previous.title : next.title,
10006
10027
  created_at: earliestTimestamp(previous.created_at, next.created_at),
10007
10028
  subtitle: nextSubtitleIsFallback ? previous.subtitle ?? next.subtitle : next.subtitle ?? previous.subtitle,
@@ -12629,7 +12650,7 @@ function isNodeError11(error, code) {
12629
12650
  }
12630
12651
 
12631
12652
  // src/conversations/run-lifecycle.ts
12632
- import { createHash as createHash4 } from "crypto";
12653
+ import { createHash as createHash5 } from "crypto";
12633
12654
  import { readdir as readdir8 } from "fs/promises";
12634
12655
 
12635
12656
  // src/hermes/api-server.ts
@@ -12755,16 +12776,38 @@ async function runHermesCronJobAction(jobId, action, options = {}) {
12755
12776
  }
12756
12777
  async function createHermesRun(input, options = {}) {
12757
12778
  const headers = new Headers({ "content-type": "application/json" });
12758
- await applySessionKeyHeader(headers, input.session_key, options);
12759
- const response = await callHermesApi(
12779
+ const sessionKeyHeader = await applySessionKeyHeader(
12780
+ headers,
12781
+ input.session_key,
12782
+ options
12783
+ );
12784
+ const requestBody = buildHermesRunRequestBody(input);
12785
+ let response = await callHermesApi(
12760
12786
  "/v1/runs",
12761
12787
  {
12762
12788
  method: "POST",
12763
- body: JSON.stringify(input),
12764
- headers
12789
+ body: JSON.stringify(requestBody),
12790
+ headers,
12791
+ signal: options.signal
12765
12792
  },
12766
12793
  options
12767
12794
  );
12795
+ if (response.status === 403 && sessionKeyHeader && await isSessionKeyRejected(response.clone())) {
12796
+ void options.logger?.warn("hermes_session_key_rejected_downgrading", {
12797
+ profile: options.profileName ?? "default"
12798
+ });
12799
+ headers.delete(sessionKeyHeader);
12800
+ response = await callHermesApi(
12801
+ "/v1/runs",
12802
+ {
12803
+ method: "POST",
12804
+ body: JSON.stringify(requestBody),
12805
+ headers,
12806
+ signal: options.signal
12807
+ },
12808
+ options
12809
+ );
12810
+ }
12768
12811
  if (response.status === 404 || response.status === 503) {
12769
12812
  assertHermesRunsApiSupported(
12770
12813
  await readHermesVersion({ logger: options.logger }).catch(() => null),
@@ -12787,6 +12830,53 @@ async function createHermesRun(input, options = {}) {
12787
12830
  }
12788
12831
  return { run_id: runId, fallback: false };
12789
12832
  }
12833
+ function buildHermesRunRequestBody(input) {
12834
+ return {
12835
+ input: input.input,
12836
+ ...input.instructions ? { instructions: input.instructions } : {},
12837
+ ...input.conversation_history && input.conversation_history.length > 0 ? { conversation_history: input.conversation_history } : {},
12838
+ ...input.session_id ? { session_id: input.session_id } : {},
12839
+ ...input.model ? { model: input.model } : {}
12840
+ };
12841
+ }
12842
+ async function readHermesRunStatus(runId, options = {}) {
12843
+ const response = await callHermesApi(
12844
+ `/v1/runs/${encodeURIComponent(runId)}`,
12845
+ { method: "GET", signal: options.signal },
12846
+ options
12847
+ );
12848
+ if (response.status === 404) {
12849
+ return null;
12850
+ }
12851
+ assertHermesRunsApiSupported(
12852
+ await readHermesVersion({ logger: options.logger }).catch(() => null),
12853
+ response.status
12854
+ );
12855
+ const payload = await readJsonResponse(response);
12856
+ const status = readString10(payload, "status");
12857
+ const resolvedRunId = readString10(payload, "run_id") ?? readString10(payload, "runId") ?? runId;
12858
+ if (!status) {
12859
+ throw new LinkHttpError(
12860
+ 502,
12861
+ "hermes_run_status_invalid",
12862
+ "Hermes API Server did not return a run status"
12863
+ );
12864
+ }
12865
+ return {
12866
+ object: readString10(payload, "object") ?? void 0,
12867
+ run_id: resolvedRunId,
12868
+ status,
12869
+ output: payload.output,
12870
+ usage: payload.usage,
12871
+ error: payload.error,
12872
+ last_event: readString10(payload, "last_event") ?? void 0,
12873
+ session_id: readString10(payload, "session_id") ?? void 0,
12874
+ model: readString10(payload, "model") ?? void 0,
12875
+ created_at: payload.created_at,
12876
+ updated_at: payload.updated_at,
12877
+ raw: payload
12878
+ };
12879
+ }
12790
12880
  async function streamHermesRunEvents(runId, options = {}) {
12791
12881
  const response = await callHermesApi(
12792
12882
  `/v1/runs/${encodeURIComponent(runId)}/events`,
@@ -12995,10 +13085,10 @@ function parseHermesApiCapabilities(payload) {
12995
13085
  sessionKeyHeader: readString10(features, "session_key_header")
12996
13086
  };
12997
13087
  }
12998
- async function callHermesApi(path27, init, options) {
13088
+ async function callHermesApi(path28, init, options) {
12999
13089
  const method = init.method ?? "GET";
13000
13090
  const startedAt = Date.now();
13001
- void options.logger?.debug("hermes_api_request_started", { method, path: path27 });
13091
+ void options.logger?.debug("hermes_api_request_started", { method, path: path28 });
13002
13092
  const availability = await ensureHermesApiServerAvailable({
13003
13093
  fetchImpl: options.fetchImpl,
13004
13094
  logger: options.logger,
@@ -13006,7 +13096,7 @@ async function callHermesApi(path27, init, options) {
13006
13096
  });
13007
13097
  let config = availability.configResult.apiServer;
13008
13098
  const fetcher = options.fetchImpl ?? fetch;
13009
- const request = () => fetchHermesApi(fetcher, config, path27, init, options);
13099
+ const request = () => fetchHermesApi(fetcher, config, path28, init, options);
13010
13100
  let response;
13011
13101
  try {
13012
13102
  response = await request();
@@ -13014,7 +13104,7 @@ async function callHermesApi(path27, init, options) {
13014
13104
  logHermesApiError(
13015
13105
  options.logger,
13016
13106
  method,
13017
- path27,
13107
+ path28,
13018
13108
  options.profileName,
13019
13109
  startedAt,
13020
13110
  error
@@ -13025,7 +13115,7 @@ async function callHermesApi(path27, init, options) {
13025
13115
  logHermesApiResponse(
13026
13116
  options.logger,
13027
13117
  method,
13028
- path27,
13118
+ path28,
13029
13119
  options.profileName,
13030
13120
  startedAt,
13031
13121
  response
@@ -13034,7 +13124,7 @@ async function callHermesApi(path27, init, options) {
13034
13124
  }
13035
13125
  void options.logger?.warn("hermes_api_request_retrying_after_401", {
13036
13126
  method,
13037
- path: path27,
13127
+ path: path28,
13038
13128
  profile: options.profileName ?? "default",
13039
13129
  port: config.port ?? null,
13040
13130
  duration_ms: Date.now() - startedAt
@@ -13052,7 +13142,7 @@ async function callHermesApi(path27, init, options) {
13052
13142
  logHermesApiError(
13053
13143
  options.logger,
13054
13144
  method,
13055
- path27,
13145
+ path28,
13056
13146
  options.profileName,
13057
13147
  startedAt,
13058
13148
  error
@@ -13062,7 +13152,7 @@ async function callHermesApi(path27, init, options) {
13062
13152
  logHermesApiResponse(
13063
13153
  options.logger,
13064
13154
  method,
13065
- path27,
13155
+ path28,
13066
13156
  options.profileName,
13067
13157
  startedAt,
13068
13158
  response
@@ -13072,7 +13162,7 @@ async function callHermesApi(path27, init, options) {
13072
13162
  }
13073
13163
  void options.logger?.warn("hermes_api_request_repairing_after_401", {
13074
13164
  method,
13075
- path: path27,
13165
+ path: path28,
13076
13166
  profile: options.profileName ?? "default",
13077
13167
  port: config.port ?? null,
13078
13168
  duration_ms: Date.now() - startedAt
@@ -13092,7 +13182,7 @@ async function callHermesApi(path27, init, options) {
13092
13182
  logHermesApiError(
13093
13183
  options.logger,
13094
13184
  method,
13095
- path27,
13185
+ path28,
13096
13186
  options.profileName,
13097
13187
  startedAt,
13098
13188
  error
@@ -13102,21 +13192,21 @@ async function callHermesApi(path27, init, options) {
13102
13192
  logHermesApiResponse(
13103
13193
  options.logger,
13104
13194
  method,
13105
- path27,
13195
+ path28,
13106
13196
  options.profileName,
13107
13197
  startedAt,
13108
13198
  response
13109
13199
  );
13110
13200
  return response;
13111
13201
  }
13112
- async function fetchHermesApi(fetcher, config, path27, init, options) {
13202
+ async function fetchHermesApi(fetcher, config, path28, init, options) {
13113
13203
  const headers = new Headers(init.headers);
13114
13204
  headers.set("accept", headers.get("accept") ?? "application/json");
13115
13205
  if (config.key) {
13116
13206
  headers.set("x-api-key", config.key);
13117
13207
  headers.set("authorization", `Bearer ${config.key}`);
13118
13208
  }
13119
- return await fetcher(`http://127.0.0.1:${config.port}${path27}`, {
13209
+ return await fetcher(`http://127.0.0.1:${config.port}${path28}`, {
13120
13210
  ...init,
13121
13211
  headers
13122
13212
  }).catch((error) => {
@@ -13125,10 +13215,10 @@ async function fetchHermesApi(fetcher, config, path27, init, options) {
13125
13215
  }
13126
13216
  void options.logger?.warn("hermes_api_server_connect_failed", {
13127
13217
  method: String(init.method ?? "GET").toUpperCase(),
13128
- path: path27,
13218
+ path: path28,
13129
13219
  profile: options.profileName ?? "default",
13130
13220
  port: config.port ?? null,
13131
- url: `http://127.0.0.1:${config.port}${path27}`,
13221
+ url: `http://127.0.0.1:${config.port}${path28}`,
13132
13222
  error: error instanceof Error ? error.message : String(error)
13133
13223
  });
13134
13224
  throw new LinkHttpError(
@@ -13138,10 +13228,10 @@ async function fetchHermesApi(fetcher, config, path27, init, options) {
13138
13228
  );
13139
13229
  });
13140
13230
  }
13141
- function logHermesApiResponse(logger, method, path27, profileName, startedAt, response) {
13231
+ function logHermesApiResponse(logger, method, path28, profileName, startedAt, response) {
13142
13232
  const fields = {
13143
13233
  method,
13144
- path: path27,
13234
+ path: path28,
13145
13235
  profile: profileName ?? "default",
13146
13236
  status: response.status,
13147
13237
  duration_ms: Date.now() - startedAt
@@ -13162,10 +13252,10 @@ async function logHermesApiFailureResponse(logger, fields, response) {
13162
13252
  ...upstreamError ? { upstream_error: upstreamError } : {}
13163
13253
  });
13164
13254
  }
13165
- function logHermesApiError(logger, method, path27, profileName, startedAt, error) {
13255
+ function logHermesApiError(logger, method, path28, profileName, startedAt, error) {
13166
13256
  void logger?.warn("hermes_api_request_failed", {
13167
13257
  method,
13168
- path: path27,
13258
+ path: path28,
13169
13259
  profile: profileName ?? "default",
13170
13260
  duration_ms: Date.now() - startedAt,
13171
13261
  ...error instanceof LinkHttpError ? { status: error.status, code: error.code } : {},
@@ -13263,6 +13353,17 @@ async function buildConversationHistory(input) {
13263
13353
  )
13264
13354
  };
13265
13355
  }
13356
+ if (snapshotHistory.length > 0) {
13357
+ return {
13358
+ messages: snapshotHistory,
13359
+ source: "link_snapshot",
13360
+ diagnostics: createHistoryDiagnostics(
13361
+ snapshotHistory,
13362
+ "link_snapshot_authoritative",
13363
+ { snapshot_message_count: snapshotHistory.length }
13364
+ )
13365
+ };
13366
+ }
13266
13367
  const hermesHistory = await readHermesTranscriptHistory(
13267
13368
  input.hermesSessionId,
13268
13369
  input.profileName
@@ -13306,11 +13407,16 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
13306
13407
  }));
13307
13408
  const [dbHistory, jsonlHistory] = await Promise.all([
13308
13409
  readHermesStateDbHistory(dbPath, normalizedSessionId),
13309
- readHermesJsonlHistory(sessionsDirConfig.sessionsDir, normalizedSessionId)
13410
+ readHermesTranscriptFilesHistory(
13411
+ sessionsDirConfig.sessionsDir,
13412
+ normalizedSessionId
13413
+ )
13310
13414
  ]);
13311
13415
  const diagnosticCounts = {
13312
13416
  state_db_message_count: dbHistory.length,
13313
- jsonl_message_count: jsonlHistory.messages.length,
13417
+ transcript_message_count: jsonlHistory.messages.length,
13418
+ session_json_message_count: jsonlHistory.sessionJsonMessageCount,
13419
+ jsonl_message_count: jsonlHistory.jsonlMessageCount,
13314
13420
  jsonl_byte_count: jsonlHistory.byteCount,
13315
13421
  jsonl_line_count: jsonlHistory.lineCount,
13316
13422
  jsonl_skipped_line_count: jsonlHistory.skippedLineCount,
@@ -13323,7 +13429,7 @@ async function readHermesTranscriptHistory(sessionId, profileName) {
13323
13429
  source: "hermes_transcript",
13324
13430
  diagnostics: createHistoryDiagnostics(
13325
13431
  jsonlHistory.messages,
13326
- "jsonl_has_more_messages",
13432
+ "transcript_has_more_messages",
13327
13433
  diagnosticCounts
13328
13434
  )
13329
13435
  };
@@ -13358,13 +13464,9 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
13358
13464
  if (!isValidSessionFileStem(sessionId)) {
13359
13465
  return empty;
13360
13466
  }
13361
- const transcriptPath = path17.join(sessionsDir, `${sessionId}.jsonl`);
13362
- const raw = await readFile10(transcriptPath, "utf8").catch((error) => {
13363
- if (isNodeError12(error, "ENOENT")) {
13364
- return "";
13365
- }
13366
- throw error;
13367
- });
13467
+ const raw = await readFirstExistingFile(
13468
+ candidateTranscriptPaths(sessionsDir, sessionId, "jsonl")
13469
+ );
13368
13470
  if (!raw.trim()) {
13369
13471
  return empty;
13370
13472
  }
@@ -13392,6 +13494,93 @@ async function readHermesJsonlHistory(sessionsDir, sessionId) {
13392
13494
  skippedLineCount
13393
13495
  };
13394
13496
  }
13497
+ async function readHermesSessionJsonHistory(sessionsDir, sessionId) {
13498
+ const empty = {
13499
+ messages: [],
13500
+ byteCount: 0,
13501
+ skippedMessageCount: 0
13502
+ };
13503
+ if (!isValidSessionFileStem(sessionId)) {
13504
+ return empty;
13505
+ }
13506
+ const raw = await readFirstExistingFile(
13507
+ candidateTranscriptPaths(sessionsDir, sessionId, "json")
13508
+ );
13509
+ if (!raw.trim()) {
13510
+ return empty;
13511
+ }
13512
+ let payload;
13513
+ try {
13514
+ payload = JSON.parse(raw);
13515
+ } catch {
13516
+ return {
13517
+ messages: [],
13518
+ byteCount: Buffer.byteLength(raw, "utf8"),
13519
+ skippedMessageCount: 1
13520
+ };
13521
+ }
13522
+ const records = Array.isArray(payload) ? payload : isRecord2(payload) && Array.isArray(payload.messages) ? payload.messages : [];
13523
+ const messages = [];
13524
+ let skippedMessageCount = 0;
13525
+ for (const record of records) {
13526
+ if (!isRecord2(record)) {
13527
+ skippedMessageCount += 1;
13528
+ continue;
13529
+ }
13530
+ const message = normalizeHistoryRecord(record);
13531
+ if (message) {
13532
+ messages.push(message);
13533
+ } else {
13534
+ skippedMessageCount += 1;
13535
+ }
13536
+ }
13537
+ return {
13538
+ messages,
13539
+ byteCount: Buffer.byteLength(raw, "utf8"),
13540
+ skippedMessageCount
13541
+ };
13542
+ }
13543
+ async function readHermesTranscriptFilesHistory(sessionsDir, sessionId) {
13544
+ const [jsonHistory, jsonlHistory] = await Promise.all([
13545
+ readHermesSessionJsonHistory(sessionsDir, sessionId),
13546
+ readHermesJsonlHistory(sessionsDir, sessionId)
13547
+ ]);
13548
+ if (jsonHistory.messages.length > jsonlHistory.messages.length) {
13549
+ return {
13550
+ messages: jsonHistory.messages,
13551
+ byteCount: jsonHistory.byteCount,
13552
+ lineCount: 0,
13553
+ skippedLineCount: jsonHistory.skippedMessageCount,
13554
+ sessionJsonMessageCount: jsonHistory.messages.length,
13555
+ jsonlMessageCount: jsonlHistory.messages.length
13556
+ };
13557
+ }
13558
+ return {
13559
+ ...jsonlHistory,
13560
+ sessionJsonMessageCount: jsonHistory.messages.length,
13561
+ jsonlMessageCount: jsonlHistory.messages.length
13562
+ };
13563
+ }
13564
+ async function readFirstExistingFile(paths) {
13565
+ for (const filePath of paths) {
13566
+ const raw = await readFile10(filePath, "utf8").catch((error) => {
13567
+ if (isNodeError12(error, "ENOENT")) {
13568
+ return null;
13569
+ }
13570
+ throw error;
13571
+ });
13572
+ if (raw !== null) {
13573
+ return raw;
13574
+ }
13575
+ }
13576
+ return "";
13577
+ }
13578
+ function candidateTranscriptPaths(sessionsDir, sessionId, extension) {
13579
+ return [
13580
+ path17.join(sessionsDir, `session_${sessionId}.${extension}`),
13581
+ path17.join(sessionsDir, `${sessionId}.${extension}`)
13582
+ ];
13583
+ }
13395
13584
  function readHistoryRows(dbPath, sessionId) {
13396
13585
  let db = null;
13397
13586
  try {
@@ -13444,6 +13633,8 @@ function createHistoryDiagnostics(messages, sourceReason, counts = {}) {
13444
13633
  return {
13445
13634
  source_reason: sourceReason,
13446
13635
  state_db_message_count: counts.state_db_message_count ?? 0,
13636
+ transcript_message_count: counts.transcript_message_count ?? 0,
13637
+ session_json_message_count: counts.session_json_message_count ?? 0,
13447
13638
  jsonl_message_count: counts.jsonl_message_count ?? 0,
13448
13639
  snapshot_message_count: counts.snapshot_message_count ?? 0,
13449
13640
  selected_message_count: messages.length,
@@ -13460,6 +13651,8 @@ function createHistoryDiagnostics(messages, sourceReason, counts = {}) {
13460
13651
  function pickHermesDiagnosticCounts(diagnostics) {
13461
13652
  return {
13462
13653
  state_db_message_count: diagnostics.state_db_message_count,
13654
+ transcript_message_count: diagnostics.transcript_message_count,
13655
+ session_json_message_count: diagnostics.session_json_message_count,
13463
13656
  jsonl_message_count: diagnostics.jsonl_message_count,
13464
13657
  jsonl_byte_count: diagnostics.jsonl_byte_count,
13465
13658
  jsonl_line_count: diagnostics.jsonl_line_count,
@@ -13468,6 +13661,9 @@ function pickHermesDiagnosticCounts(diagnostics) {
13468
13661
  jsonl_sessions_dir_config_error: diagnostics.jsonl_sessions_dir_config_error
13469
13662
  };
13470
13663
  }
13664
+ function isRecord2(value) {
13665
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13666
+ }
13471
13667
  function countReplayMetadata(messages) {
13472
13668
  let toolMessageCount = 0;
13473
13669
  let toolCallMessageCount = 0;
@@ -13943,126 +14139,707 @@ function toRecord9(value) {
13943
14139
  return typeof value === "object" && value !== null ? value : {};
13944
14140
  }
13945
14141
 
13946
- // src/conversations/stream-events.ts
13947
- function normalizeHermesStreamEvent(event) {
13948
- const responseEvent = normalizeHermesResponseEvent(event);
13949
- if (responseEvent || isHermesResponseEvent(event)) {
13950
- return responseEvent;
13951
- }
13952
- if (isTopLevelErrorEvent(event)) {
13953
- return {
13954
- ...event,
13955
- payloadType: "run.failed",
13956
- payload: {
13957
- ...event.payload,
13958
- type: "run.failed",
13959
- error: {
13960
- message: readErrorMessage2(event.payload) ?? readDelta(event.payload) ?? "Hermes run failed"
13961
- }
13962
- }
13963
- };
14142
+ // src/conversations/run-backend.ts
14143
+ var RUNS_BACKEND_VALUES = /* @__PURE__ */ new Set(["run", "runs", "v1/runs", "/v1/runs"]);
14144
+ var RESPONSES_BACKEND_VALUES = /* @__PURE__ */ new Set([
14145
+ "response",
14146
+ "responses",
14147
+ "v1/responses",
14148
+ "/v1/responses"
14149
+ ]);
14150
+ function resolveConversationRunBackend(env = process.env) {
14151
+ const raw = (env.HERMESLINK_CONVERSATION_BACKEND ?? env.HERMESLINK_CHAT_BACKEND ?? "").trim().toLowerCase();
14152
+ if (RESPONSES_BACKEND_VALUES.has(raw)) {
14153
+ return "responses";
13964
14154
  }
13965
- if (event.eventName === "hermes.tool.progress") {
13966
- const toolName = readString12(event.payload, "tool") ?? readString12(event.payload, "name") ?? "tool";
13967
- const preview = readString12(event.payload, "label") ?? readString12(event.payload, "preview") ?? toolName;
13968
- return {
13969
- ...event,
13970
- payloadType: "tool.started",
13971
- payload: {
13972
- ...event.payload,
13973
- type: "tool.started",
13974
- tool: toolName,
13975
- tool_name: toolName,
13976
- preview
13977
- }
13978
- };
14155
+ if (RUNS_BACKEND_VALUES.has(raw)) {
14156
+ return "runs";
13979
14157
  }
13980
- if (event.payloadType !== "chat.completion.chunk") {
13981
- return event;
14158
+ return "runs";
14159
+ }
14160
+ function isRunToolResultCompensationEnabled(env = process.env) {
14161
+ const raw = env.HERMESLINK_RUN_TOOL_RESULT_COMPENSATION?.trim().toLowerCase();
14162
+ return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
14163
+ }
14164
+
14165
+ // src/conversations/run-transcript-enrichment.ts
14166
+ import { readFile as readFile12, stat as stat12 } from "fs/promises";
14167
+ import path19 from "path";
14168
+ var MESSAGE_COLUMNS2 = [
14169
+ "id",
14170
+ "session_id",
14171
+ "role",
14172
+ "content",
14173
+ "tool_call_id",
14174
+ "tool_calls",
14175
+ "tool_name",
14176
+ "timestamp"
14177
+ ];
14178
+ async function buildRunTranscriptEvents(input) {
14179
+ const sessionId = input.hermesSessionId.trim();
14180
+ if (!sessionId) {
14181
+ return [];
13982
14182
  }
13983
- const delta = readChatCompletionDelta(event.payload);
13984
- if (delta) {
13985
- return {
13986
- ...event,
13987
- payloadType: "message.delta",
13988
- payload: { type: "message.delta", delta }
13989
- };
14183
+ const profileName = isValidProfileName3(input.profileName) ? input.profileName : "default";
14184
+ const rows = await readHermesTranscriptRows(profileName, sessionId);
14185
+ if (rows.length === 0) {
14186
+ return [];
13990
14187
  }
13991
- const finishReason = readChatCompletionFinishReason(event.payload);
13992
- const usage = readChatCompletionUsage(event.payload);
13993
- if (finishReason || usage) {
13994
- return {
13995
- ...event,
13996
- payloadType: "run.completed",
13997
- payload: {
13998
- type: "run.completed",
13999
- ...finishReason ? { finish_reason: finishReason } : {},
14000
- ...usage ? { usage } : {}
14188
+ const lowerBoundSeconds = runStartedLowerBoundSeconds(input.runStartedAt);
14189
+ const reusableEventIds = groupReusableToolEventIds(
14190
+ input.assistant?.agent_events ?? []
14191
+ );
14192
+ const events = [];
14193
+ const pendingToolCalls = [];
14194
+ const toolCallsById = /* @__PURE__ */ new Map();
14195
+ for (const row of rows) {
14196
+ if (!isRunRow(row, lowerBoundSeconds)) {
14197
+ continue;
14198
+ }
14199
+ const role = normalizeRole(row.role);
14200
+ if (role === "assistant") {
14201
+ for (const toolCall of readHermesToolCalls2(row)) {
14202
+ const pending = { toolCall };
14203
+ pendingToolCalls.push(pending);
14204
+ if (toolCall.id) {
14205
+ toolCallsById.set(toolCall.id, pending);
14206
+ }
14001
14207
  }
14002
- };
14208
+ continue;
14209
+ }
14210
+ if (role === "tool") {
14211
+ const pending = consumePendingToolCall2({
14212
+ toolMessage: row,
14213
+ pendingToolCalls,
14214
+ toolCallsById
14215
+ });
14216
+ if (!pending) {
14217
+ continue;
14218
+ }
14219
+ events.push(
14220
+ toolCompletedEvent(
14221
+ row,
14222
+ pending,
14223
+ consumeReusableToolEventId(reusableEventIds, pending, row)
14224
+ )
14225
+ );
14226
+ }
14003
14227
  }
14004
- return null;
14228
+ return events;
14005
14229
  }
14006
- function isHermesResponseEvent(event) {
14007
- return event.payloadType.startsWith("response.") || event.eventName.startsWith("response.");
14230
+ async function readHermesTranscriptRows(profileName, sessionId) {
14231
+ const profileDir = resolveHermesProfileDir(profileName);
14232
+ const dbPath = path19.join(profileDir, "state.db");
14233
+ const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() => path19.join(profileDir, "sessions"));
14234
+ const [dbRows, jsonlRows] = await Promise.all([
14235
+ readStateDbMessages2(dbPath, sessionId),
14236
+ readJsonlMessages2(sessionsDir, sessionId)
14237
+ ]);
14238
+ return selectTranscriptRows(dbRows, jsonlRows);
14008
14239
  }
14009
- function normalizeHermesResponseEvent(event) {
14010
- switch (event.payloadType) {
14011
- case "response.output_text.delta": {
14012
- const delta = readDelta(event.payload);
14013
- return delta ? {
14014
- ...event,
14015
- payloadType: "message.delta",
14016
- payload: { type: "message.delta", delta }
14017
- } : null;
14018
- }
14019
- case "response.output_item.added":
14020
- return normalizeResponseOutputItemAdded(event);
14021
- case "response.output_item.done":
14022
- return normalizeResponseOutputItemDone(event);
14023
- case "response.completed":
14024
- return normalizeResponseCompleted(event);
14025
- case "response.failed":
14026
- return normalizeResponseFailed(event);
14027
- case "response.output_text.done": {
14028
- const delta = readDelta(event.payload);
14029
- return delta ? {
14030
- ...event,
14031
- payloadType: "message.delta",
14032
- payload: { type: "message.delta", delta }
14033
- } : null;
14034
- }
14035
- case "response.created":
14036
- return null;
14037
- default:
14038
- return null;
14240
+ function selectTranscriptRows(dbRows, jsonlRows) {
14241
+ if (jsonlRows.length === 0) {
14242
+ return dbRows;
14243
+ }
14244
+ if (dbRows.length === 0) {
14245
+ return jsonlRows;
14039
14246
  }
14247
+ if (jsonlRows.length <= dbRows.length) {
14248
+ return dbRows;
14249
+ }
14250
+ const jsonlTimestampedRows = jsonlRows.filter(
14251
+ (row) => hasUsableTimestamp(row.timestamp)
14252
+ ).length;
14253
+ const dbTimestampedRows = dbRows.filter(
14254
+ (row) => hasUsableTimestamp(row.timestamp)
14255
+ ).length;
14256
+ if (jsonlTimestampedRows === 0 && dbTimestampedRows > 0) {
14257
+ return dbRows;
14258
+ }
14259
+ return jsonlRows;
14040
14260
  }
14041
- function normalizeResponseOutputItemAdded(event) {
14042
- const item = toRecord10(event.payload.item);
14043
- if (readString12(item, "type") !== "function_call") {
14044
- return null;
14261
+ async function readStateDbMessages2(dbPath, sessionId) {
14262
+ if (!await isFile2(dbPath)) {
14263
+ return [];
14045
14264
  }
14046
- const toolName = readString12(item, "name") ?? "tool";
14047
- const argumentsValue = parseJsonValue2(item.arguments) ?? item.arguments;
14048
- return {
14049
- ...event,
14050
- payloadType: "tool.started",
14265
+ let db = null;
14266
+ try {
14267
+ db = openSqliteDatabase(dbPath, {
14268
+ readonly: true,
14269
+ timeout: 1e3
14270
+ });
14271
+ const columns = readTableColumns3(db, "messages");
14272
+ if (!columns.has("session_id") || !columns.has("role")) {
14273
+ return [];
14274
+ }
14275
+ const selectColumns = MESSAGE_COLUMNS2.map(
14276
+ (column) => columns.has(column) ? quoteIdentifier2(column) : `NULL AS ${column}`
14277
+ ).join(", ");
14278
+ return db.prepare(
14279
+ `
14280
+ SELECT ${selectColumns}
14281
+ FROM messages
14282
+ WHERE session_id = ?
14283
+ ORDER BY timestamp, id
14284
+ `
14285
+ ).all(sessionId);
14286
+ } catch {
14287
+ return [];
14288
+ } finally {
14289
+ db?.close();
14290
+ }
14291
+ }
14292
+ async function readJsonlMessages2(sessionsDir, sessionId) {
14293
+ if (!/^[A-Za-z0-9._:-]{1,160}$/u.test(sessionId)) {
14294
+ return [];
14295
+ }
14296
+ const transcriptPath = path19.join(sessionsDir, `${sessionId}.jsonl`);
14297
+ const raw = await readFile12(transcriptPath, "utf8").catch((error) => {
14298
+ if (isNodeError13(error, "ENOENT")) {
14299
+ return "";
14300
+ }
14301
+ throw error;
14302
+ });
14303
+ if (!raw.trim()) {
14304
+ return [];
14305
+ }
14306
+ const rows = [];
14307
+ for (const line of raw.split(/\r?\n/u)) {
14308
+ if (!line.trim()) {
14309
+ continue;
14310
+ }
14311
+ try {
14312
+ const parsed = JSON.parse(line);
14313
+ const role = readString12(parsed, "role");
14314
+ if (!role) {
14315
+ continue;
14316
+ }
14317
+ rows.push({
14318
+ ...parsed,
14319
+ role,
14320
+ content: normalizeContent3(parsed.content),
14321
+ timestamp: readNumber3(parsed.timestamp) ?? readNumber3(parsed.created_at) ?? readNumber3(parsed.createdAt) ?? void 0
14322
+ });
14323
+ } catch {
14324
+ continue;
14325
+ }
14326
+ }
14327
+ return rows;
14328
+ }
14329
+ function readHermesToolCalls2(row) {
14330
+ const decoded = parseJsonValue2(row.tool_calls) ?? row.tool_calls;
14331
+ const values = Array.isArray(decoded) ? decoded : decoded ? [decoded] : [];
14332
+ return values.map((value) => normalizeHermesToolCall2(value)).filter(
14333
+ (toolCall) => Boolean(toolCall)
14334
+ );
14335
+ }
14336
+ function normalizeHermesToolCall2(value) {
14337
+ const record = toRecord10(value);
14338
+ if (Object.keys(record).length === 0) {
14339
+ return null;
14340
+ }
14341
+ const fn = toRecord10(record.function);
14342
+ const id = readString12(record, "id") ?? readString12(record, "call_id") ?? readString12(record, "tool_call_id") ?? readString12(fn, "id") ?? void 0;
14343
+ const name = readString12(fn, "name") ?? readString12(record, "name") ?? readString12(record, "tool_name") ?? readString12(record, "tool") ?? "tool";
14344
+ const rawArguments = fn.arguments ?? record.arguments ?? record.args ?? record.input;
14345
+ return {
14346
+ ...id ? { id } : {},
14347
+ name,
14348
+ ...rawArguments === void 0 ? {} : { arguments: parseJsonValue2(rawArguments) ?? rawArguments },
14349
+ raw: value
14350
+ };
14351
+ }
14352
+ function consumePendingToolCall2(input) {
14353
+ const toolCallId = readString12(input.toolMessage, "tool_call_id");
14354
+ const toolName = readString12(input.toolMessage, "tool_name");
14355
+ let pending = toolCallId ? input.toolCallsById.get(toolCallId) : void 0;
14356
+ if (!pending && toolName) {
14357
+ pending = input.pendingToolCalls.find(
14358
+ (item) => item.toolCall.name === toolName
14359
+ );
14360
+ }
14361
+ pending ??= input.pendingToolCalls[0];
14362
+ if (!pending) {
14363
+ return void 0;
14364
+ }
14365
+ const index = input.pendingToolCalls.indexOf(pending);
14366
+ if (index >= 0) {
14367
+ input.pendingToolCalls.splice(index, 1);
14368
+ }
14369
+ if (pending.toolCall.id) {
14370
+ input.toolCallsById.delete(pending.toolCall.id);
14371
+ }
14372
+ return pending;
14373
+ }
14374
+ function toolCompletedEvent(row, pending, existingEventId) {
14375
+ const output = normalizeContent3(row.content);
14376
+ const parsedOutput = parseJsonValue2(output);
14377
+ const toolCallId = readString12(row, "tool_call_id") ?? pending?.toolCall.id;
14378
+ const toolName = readString12(row, "tool_name") ?? pending?.toolCall.name ?? "tool";
14379
+ const payload = {
14380
+ type: "tool.completed",
14381
+ event: "tool.completed",
14382
+ tool: toolName,
14383
+ tool_name: toolName,
14384
+ name: toolName,
14385
+ ...existingEventId ? {
14386
+ id: existingEventId,
14387
+ ...toolCallId ? { hermes_tool_call_id: toolCallId } : {}
14388
+ } : toolCallId ? { tool_call_id: toolCallId, id: toolCallId } : {},
14389
+ ...pending?.toolCall.arguments === void 0 ? {} : { arguments: pending.toolCall.arguments },
14390
+ output,
14391
+ content: output,
14392
+ result: parsedOutput ?? output,
14393
+ ...pending ? { tool_call: pending.toolCall.raw } : {},
14394
+ timestamp: row.timestamp
14395
+ };
14396
+ return {
14397
+ eventName: "tool.completed",
14398
+ payloadType: "tool.completed",
14399
+ payload,
14400
+ rawPayload: {
14401
+ format: "hermes-message",
14402
+ message: row,
14403
+ ...pending ? { tool_call: pending.toolCall.raw } : {}
14404
+ }
14405
+ };
14406
+ }
14407
+ function groupReusableToolEventIds(events) {
14408
+ const grouped = /* @__PURE__ */ new Map();
14409
+ for (const event of events) {
14410
+ if (event.kind && event.kind !== "tool") {
14411
+ continue;
14412
+ }
14413
+ const key = normalizeToolTitle(event.title);
14414
+ if (!key) {
14415
+ continue;
14416
+ }
14417
+ grouped.set(key, [...grouped.get(key) ?? [], event.id]);
14418
+ }
14419
+ return grouped;
14420
+ }
14421
+ function consumeReusableToolEventId(grouped, pending, row) {
14422
+ const toolName = pending?.toolCall.name ?? readString12(row, "tool_name") ?? "tool";
14423
+ const key = normalizeToolTitle(humanizeToolName2(toolName));
14424
+ const ids = grouped.get(key);
14425
+ const id = ids?.shift();
14426
+ if (ids && ids.length === 0) {
14427
+ grouped.delete(key);
14428
+ }
14429
+ return id;
14430
+ }
14431
+ function humanizeToolName2(value) {
14432
+ const normalized = value.trim().replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").replace(/\s+/gu, " ");
14433
+ if (!normalized) {
14434
+ return "\u5DE5\u5177\u8C03\u7528";
14435
+ }
14436
+ return normalized.split(" ").map(
14437
+ (part) => part ? `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}` : part
14438
+ ).join(" ");
14439
+ }
14440
+ function normalizeToolTitle(value) {
14441
+ return value.trim().toLowerCase().replace(/[\s_-]+/gu, "");
14442
+ }
14443
+ function isRunRow(row, lowerBoundSeconds) {
14444
+ if (lowerBoundSeconds === null) {
14445
+ return true;
14446
+ }
14447
+ const timestamp = readNumber3(row.timestamp);
14448
+ if (!timestamp) {
14449
+ return false;
14450
+ }
14451
+ const seconds = timestamp > 1e10 ? timestamp / 1e3 : timestamp;
14452
+ return seconds >= lowerBoundSeconds;
14453
+ }
14454
+ function hasUsableTimestamp(value) {
14455
+ return readNumber3(value) !== null;
14456
+ }
14457
+ function runStartedLowerBoundSeconds(value) {
14458
+ const millis = Date.parse(value);
14459
+ if (Number.isNaN(millis)) {
14460
+ return null;
14461
+ }
14462
+ return millis / 1e3 - 1;
14463
+ }
14464
+ function normalizeRole(value) {
14465
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
14466
+ }
14467
+ function normalizeContent3(value) {
14468
+ if (typeof value === "string") {
14469
+ return value;
14470
+ }
14471
+ if (Array.isArray(value)) {
14472
+ return value.map((item) => {
14473
+ if (typeof item === "string") {
14474
+ return item;
14475
+ }
14476
+ if (typeof item === "object" && item !== null) {
14477
+ return readString12(item, "text") ?? "";
14478
+ }
14479
+ return "";
14480
+ }).filter(Boolean).join("");
14481
+ }
14482
+ return "";
14483
+ }
14484
+ function parseJsonValue2(value) {
14485
+ if (typeof value !== "string") {
14486
+ return void 0;
14487
+ }
14488
+ const trimmed = value.trim();
14489
+ if (!trimmed) {
14490
+ return void 0;
14491
+ }
14492
+ try {
14493
+ return JSON.parse(trimmed);
14494
+ } catch {
14495
+ return void 0;
14496
+ }
14497
+ }
14498
+ function readTableColumns3(db, tableName) {
14499
+ try {
14500
+ const rows = db.prepare(`PRAGMA table_info(${quoteIdentifier2(tableName)})`).all();
14501
+ return new Set(
14502
+ rows.map((row) => typeof row.name === "string" ? row.name : "").filter(Boolean)
14503
+ );
14504
+ } catch {
14505
+ return /* @__PURE__ */ new Set();
14506
+ }
14507
+ }
14508
+ function quoteIdentifier2(value) {
14509
+ return `"${value.replaceAll('"', '""')}"`;
14510
+ }
14511
+ async function isFile2(filePath) {
14512
+ return stat12(filePath).then((value) => value.isFile()).catch((error) => {
14513
+ if (isNodeError13(error, "ENOENT")) {
14514
+ return false;
14515
+ }
14516
+ throw error;
14517
+ });
14518
+ }
14519
+ function isValidProfileName3(value) {
14520
+ return typeof value === "string" && /^[a-zA-Z0-9._-]{1,64}$/u.test(value);
14521
+ }
14522
+ function readString12(payload, key) {
14523
+ const value = payload[key];
14524
+ return typeof value === "string" && value.trim() ? value.trim() : null;
14525
+ }
14526
+ function readNumber3(value) {
14527
+ if (typeof value === "number" && Number.isFinite(value)) {
14528
+ return value;
14529
+ }
14530
+ if (typeof value !== "string" || !value.trim()) {
14531
+ return null;
14532
+ }
14533
+ const numeric = Number(value);
14534
+ if (Number.isFinite(numeric)) {
14535
+ return numeric;
14536
+ }
14537
+ const millis = Date.parse(value);
14538
+ return Number.isNaN(millis) ? null : millis;
14539
+ }
14540
+ function toRecord10(value) {
14541
+ return typeof value === "object" && value !== null ? value : {};
14542
+ }
14543
+ function isNodeError13(error, code) {
14544
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
14545
+ }
14546
+
14547
+ // src/conversations/run-tool-event-ids.ts
14548
+ import { createHash as createHash4 } from "crypto";
14549
+ var RunToolEventIdCoalescer = class {
14550
+ scope;
14551
+ ordinal = 0;
14552
+ pendingByToolKey = /* @__PURE__ */ new Map();
14553
+ startedByFingerprint = /* @__PURE__ */ new Map();
14554
+ completedByFingerprint = /* @__PURE__ */ new Map();
14555
+ constructor(options) {
14556
+ this.scope = `${options.runId}:${options.hermesRunId ?? ""}`;
14557
+ }
14558
+ normalize(event) {
14559
+ const type = readToolEventType(event);
14560
+ if (!type || hasStableToolEventId(event.payload)) {
14561
+ return event;
14562
+ }
14563
+ const toolKey = normalizeToolKey(readToolName(event.payload));
14564
+ if (type === "tool.started") {
14565
+ return withGeneratedToolEventId(
14566
+ event,
14567
+ this.idForStartedToolEvent(toolKey, event.payload)
14568
+ );
14569
+ }
14570
+ if (isTerminalToolEvent(type)) {
14571
+ return withGeneratedToolEventId(
14572
+ event,
14573
+ this.idForTerminalToolEvent(type, toolKey, event.payload)
14574
+ );
14575
+ }
14576
+ return event;
14577
+ }
14578
+ idForStartedToolEvent(toolKey, payload) {
14579
+ const fingerprint = startedToolEventFingerprint(toolKey, payload);
14580
+ if (fingerprint) {
14581
+ const existing = this.startedByFingerprint.get(fingerprint);
14582
+ if (existing) {
14583
+ return existing.id;
14584
+ }
14585
+ }
14586
+ const pending = {
14587
+ id: this.nextId(toolKey),
14588
+ toolKey
14589
+ };
14590
+ const pendingForTool = this.pendingByToolKey.get(toolKey) ?? [];
14591
+ pendingForTool.push(pending);
14592
+ this.pendingByToolKey.set(toolKey, pendingForTool);
14593
+ if (fingerprint) {
14594
+ this.startedByFingerprint.set(fingerprint, pending);
14595
+ }
14596
+ return pending.id;
14597
+ }
14598
+ idForTerminalToolEvent(type, toolKey, payload) {
14599
+ const pending = this.shiftPendingToolEvent(toolKey);
14600
+ const fingerprint = terminalToolEventFingerprint(type, toolKey, payload);
14601
+ if (pending) {
14602
+ this.completedByFingerprint.set(fingerprint, pending.id);
14603
+ return pending.id;
14604
+ }
14605
+ const existing = this.completedByFingerprint.get(fingerprint);
14606
+ if (existing) {
14607
+ return existing;
14608
+ }
14609
+ const id = this.nextId(toolKey);
14610
+ this.completedByFingerprint.set(fingerprint, id);
14611
+ return id;
14612
+ }
14613
+ shiftPendingToolEvent(toolKey) {
14614
+ const exact = this.shiftPendingByToolKey(toolKey);
14615
+ if (exact) {
14616
+ return exact;
14617
+ }
14618
+ for (const [candidateToolKey] of this.pendingByToolKey) {
14619
+ const pending = this.shiftPendingByToolKey(candidateToolKey);
14620
+ if (pending) {
14621
+ return pending;
14622
+ }
14623
+ }
14624
+ return void 0;
14625
+ }
14626
+ shiftPendingByToolKey(toolKey) {
14627
+ const pendingForTool = this.pendingByToolKey.get(toolKey);
14628
+ const pending = pendingForTool?.shift();
14629
+ if (pendingForTool && pendingForTool.length === 0) {
14630
+ this.pendingByToolKey.delete(toolKey);
14631
+ }
14632
+ return pending;
14633
+ }
14634
+ nextId(toolKey) {
14635
+ this.ordinal += 1;
14636
+ return `tool_${hashStableValue(`${this.scope}:${this.ordinal}:${toolKey}`)}`;
14637
+ }
14638
+ };
14639
+ function readToolEventType(event) {
14640
+ const type = readString13(event.payload, "type") ?? readString13(event.payload, "event") ?? event.payloadType;
14641
+ return type.startsWith("tool.") ? type : null;
14642
+ }
14643
+ function isTerminalToolEvent(type) {
14644
+ return type === "tool.completed" || type === "tool.failed" || type === "tool.error";
14645
+ }
14646
+ function hasStableToolEventId(payload) {
14647
+ const tool = toRecord11(payload.tool);
14648
+ const call = toRecord11(payload.tool_call ?? payload.toolCall);
14649
+ const fn = toRecord11(call.function ?? payload.function);
14650
+ return Boolean(
14651
+ readString13(payload, "tool_call_id") ?? readString13(payload, "toolCallId") ?? readString13(payload, "call_id") ?? readString13(payload, "id") ?? readString13(tool, "id") ?? readString13(call, "id") ?? readString13(fn, "id")
14652
+ );
14653
+ }
14654
+ function readToolName(payload) {
14655
+ const tool = toRecord11(payload.tool);
14656
+ const call = toRecord11(payload.tool_call ?? payload.toolCall);
14657
+ const fn = toRecord11(call.function ?? payload.function);
14658
+ return readString13(payload, "tool_name") ?? readString13(payload, "toolName") ?? readString13(payload, "name") ?? readString13(payload, "tool") ?? readString13(tool, "name") ?? readString13(call, "name") ?? readString13(fn, "name") ?? "tool";
14659
+ }
14660
+ function withGeneratedToolEventId(event, id) {
14661
+ return {
14662
+ ...event,
14663
+ payload: {
14664
+ ...event.payload,
14665
+ id,
14666
+ link_tool_event_id: id,
14667
+ link_generated_tool_event_id: true
14668
+ }
14669
+ };
14670
+ }
14671
+ function startedToolEventFingerprint(toolKey, payload) {
14672
+ const timestamp = payload.timestamp ?? payload.started_at ?? payload.created_at;
14673
+ if (timestamp === void 0 || timestamp === null) {
14674
+ return null;
14675
+ }
14676
+ return stableStringify2({
14677
+ toolKey,
14678
+ timestamp,
14679
+ preview: payload.preview,
14680
+ arguments: payload.arguments ?? payload.args ?? payload.input
14681
+ });
14682
+ }
14683
+ function terminalToolEventFingerprint(type, toolKey, payload) {
14684
+ return stableStringify2({
14685
+ type,
14686
+ toolKey,
14687
+ timestamp: payload.timestamp ?? payload.completed_at ?? payload.created_at,
14688
+ duration: payload.duration,
14689
+ error: payload.error,
14690
+ output: payload.output ?? payload.content ?? payload.result ?? payload.message ?? null
14691
+ });
14692
+ }
14693
+ function normalizeToolKey(value) {
14694
+ return value.trim().toLowerCase().replace(/[\s-]+/gu, "_") || "tool";
14695
+ }
14696
+ function stableStringify2(value) {
14697
+ try {
14698
+ return JSON.stringify(value, (_key, data) => {
14699
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
14700
+ return data;
14701
+ }
14702
+ return Object.fromEntries(
14703
+ Object.entries(data).sort(
14704
+ ([left], [right]) => left.localeCompare(right)
14705
+ )
14706
+ );
14707
+ });
14708
+ } catch {
14709
+ return String(value);
14710
+ }
14711
+ }
14712
+ function hashStableValue(value) {
14713
+ return createHash4("sha256").update(value).digest("hex").slice(0, 16);
14714
+ }
14715
+ function readString13(payload, key) {
14716
+ const value = payload[key];
14717
+ return typeof value === "string" && value.trim() ? value.trim() : null;
14718
+ }
14719
+ function toRecord11(value) {
14720
+ return typeof value === "object" && value !== null ? value : {};
14721
+ }
14722
+
14723
+ // src/conversations/stream-events.ts
14724
+ function normalizeHermesStreamEvent(event) {
14725
+ const responseEvent = normalizeHermesResponseEvent(event);
14726
+ if (responseEvent || isHermesResponseEvent(event)) {
14727
+ return responseEvent;
14728
+ }
14729
+ if (isTopLevelErrorEvent(event)) {
14730
+ return {
14731
+ ...event,
14732
+ payloadType: "run.failed",
14733
+ payload: {
14734
+ ...event.payload,
14735
+ type: "run.failed",
14736
+ error: {
14737
+ message: readErrorMessage2(event.payload) ?? readDelta(event.payload) ?? "Hermes run failed"
14738
+ }
14739
+ }
14740
+ };
14741
+ }
14742
+ if (event.eventName === "hermes.tool.progress") {
14743
+ const toolName = readString14(event.payload, "tool") ?? readString14(event.payload, "name") ?? "tool";
14744
+ const preview = readString14(event.payload, "label") ?? readString14(event.payload, "preview") ?? toolName;
14745
+ return {
14746
+ ...event,
14747
+ payloadType: "tool.started",
14748
+ payload: {
14749
+ ...event.payload,
14750
+ type: "tool.started",
14751
+ tool: toolName,
14752
+ tool_name: toolName,
14753
+ preview
14754
+ }
14755
+ };
14756
+ }
14757
+ if (event.payloadType !== "chat.completion.chunk") {
14758
+ return event;
14759
+ }
14760
+ const delta = readChatCompletionDelta(event.payload);
14761
+ if (delta) {
14762
+ return {
14763
+ ...event,
14764
+ payloadType: "message.delta",
14765
+ payload: { type: "message.delta", delta }
14766
+ };
14767
+ }
14768
+ const finishReason = readChatCompletionFinishReason(event.payload);
14769
+ const usage = readChatCompletionUsage(event.payload);
14770
+ if (finishReason || usage) {
14771
+ return {
14772
+ ...event,
14773
+ payloadType: "run.completed",
14774
+ payload: {
14775
+ type: "run.completed",
14776
+ ...finishReason ? { finish_reason: finishReason } : {},
14777
+ ...usage ? { usage } : {}
14778
+ }
14779
+ };
14780
+ }
14781
+ return null;
14782
+ }
14783
+ function isHermesResponseEvent(event) {
14784
+ return event.payloadType.startsWith("response.") || event.eventName.startsWith("response.");
14785
+ }
14786
+ function normalizeHermesResponseEvent(event) {
14787
+ switch (event.payloadType) {
14788
+ case "response.output_text.delta": {
14789
+ const delta = readDelta(event.payload);
14790
+ return delta ? {
14791
+ ...event,
14792
+ payloadType: "message.delta",
14793
+ payload: { type: "message.delta", delta }
14794
+ } : null;
14795
+ }
14796
+ case "response.output_item.added":
14797
+ return normalizeResponseOutputItemAdded(event);
14798
+ case "response.output_item.done":
14799
+ return normalizeResponseOutputItemDone(event);
14800
+ case "response.completed":
14801
+ return normalizeResponseCompleted(event);
14802
+ case "response.failed":
14803
+ return normalizeResponseFailed(event);
14804
+ case "response.output_text.done": {
14805
+ const delta = readDelta(event.payload);
14806
+ return delta ? {
14807
+ ...event,
14808
+ payloadType: "message.delta",
14809
+ payload: { type: "message.delta", delta }
14810
+ } : null;
14811
+ }
14812
+ case "response.created":
14813
+ return null;
14814
+ default:
14815
+ return null;
14816
+ }
14817
+ }
14818
+ function normalizeResponseOutputItemAdded(event) {
14819
+ const item = toRecord12(event.payload.item);
14820
+ if (readString14(item, "type") !== "function_call") {
14821
+ return null;
14822
+ }
14823
+ const toolName = readString14(item, "name") ?? "tool";
14824
+ const argumentsValue = parseJsonValue3(item.arguments) ?? item.arguments;
14825
+ return {
14826
+ ...event,
14827
+ payloadType: "tool.started",
14051
14828
  payload: {
14052
14829
  type: "tool.started",
14053
14830
  tool: toolName,
14054
14831
  tool_name: toolName,
14055
14832
  name: toolName,
14056
- tool_call_id: readString12(item, "call_id") ?? readString12(item, "id"),
14833
+ tool_call_id: readString14(item, "call_id") ?? readString14(item, "id"),
14057
14834
  arguments: argumentsValue,
14058
14835
  preview: toolName,
14059
- response_item_id: readString12(item, "id") ?? void 0
14836
+ response_item_id: readString14(item, "id") ?? void 0
14060
14837
  }
14061
14838
  };
14062
14839
  }
14063
14840
  function normalizeResponseOutputItemDone(event) {
14064
- const item = toRecord10(event.payload.item);
14065
- if (readString12(item, "type") === "message") {
14841
+ const item = toRecord12(event.payload.item);
14842
+ if (readString14(item, "type") === "message") {
14066
14843
  const delta = extractResponseAssistantText({ output: [item] });
14067
14844
  return delta ? {
14068
14845
  ...event,
@@ -14070,51 +14847,51 @@ function normalizeResponseOutputItemDone(event) {
14070
14847
  payload: { type: "message.delta", delta }
14071
14848
  } : null;
14072
14849
  }
14073
- if (readString12(item, "type") !== "function_call_output") {
14850
+ if (readString14(item, "type") !== "function_call_output") {
14074
14851
  return null;
14075
14852
  }
14076
14853
  const output = readResponseItemOutput(item.output);
14077
- const parsedOutput = parseJsonValue2(output);
14854
+ const parsedOutput = parseJsonValue3(output);
14078
14855
  return {
14079
14856
  ...event,
14080
14857
  payloadType: "tool.completed",
14081
14858
  payload: {
14082
14859
  type: "tool.completed",
14083
- tool_call_id: readString12(item, "call_id") ?? readString12(item, "id"),
14084
- status: readString12(item, "status") ?? "completed",
14860
+ tool_call_id: readString14(item, "call_id") ?? readString14(item, "id"),
14861
+ status: readString14(item, "status") ?? "completed",
14085
14862
  output,
14086
14863
  content: output,
14087
14864
  result: parsedOutput ?? output,
14088
- response_item_id: readString12(item, "id") ?? void 0
14865
+ response_item_id: readString14(item, "id") ?? void 0
14089
14866
  }
14090
14867
  };
14091
14868
  }
14092
14869
  function normalizeResponseCompleted(event) {
14093
- const response = toRecord10(event.payload.response);
14870
+ const response = toRecord12(event.payload.response);
14094
14871
  return {
14095
14872
  ...event,
14096
14873
  payloadType: "run.completed",
14097
14874
  payload: {
14098
14875
  type: "run.completed",
14099
- response_id: readString12(response, "id") ?? readString12(event.payload, "id"),
14100
- usage: toRecord10(response.usage),
14876
+ response_id: readString14(response, "id") ?? readString14(event.payload, "id"),
14877
+ usage: toRecord12(response.usage),
14101
14878
  response
14102
14879
  }
14103
14880
  };
14104
14881
  }
14105
14882
  function normalizeResponseFailed(event) {
14106
- const response = toRecord10(event.payload.response);
14107
- const error = toRecord10(response.error);
14883
+ const response = toRecord12(event.payload.response);
14884
+ const error = toRecord12(response.error);
14108
14885
  return {
14109
14886
  ...event,
14110
14887
  payloadType: "run.failed",
14111
14888
  payload: {
14112
14889
  type: "run.failed",
14113
- response_id: readString12(response, "id") ?? readString12(event.payload, "id"),
14890
+ response_id: readString14(response, "id") ?? readString14(event.payload, "id"),
14114
14891
  error: {
14115
- message: readString12(error, "message") ?? readString12(event.payload, "message") ?? "Hermes run failed"
14892
+ message: readString14(error, "message") ?? readString14(event.payload, "message") ?? "Hermes run failed"
14116
14893
  },
14117
- usage: toRecord10(response.usage),
14894
+ usage: toRecord12(response.usage),
14118
14895
  response
14119
14896
  }
14120
14897
  };
@@ -14138,8 +14915,8 @@ function readErrorMessage2(payload) {
14138
14915
  if (typeof payload.error === "string" && payload.error.trim()) {
14139
14916
  return payload.error.trim();
14140
14917
  }
14141
- const error = toRecord10(payload.error);
14142
- return readString12(error, "message") ?? readString12(payload, "message");
14918
+ const error = toRecord12(payload.error);
14919
+ return readString14(error, "message") ?? readString14(payload, "message");
14143
14920
  }
14144
14921
  function readDelta(payload) {
14145
14922
  return readText2(payload, "delta") ?? readText2(payload, "text") ?? readText2(payload, "content");
@@ -14148,8 +14925,12 @@ function extractResponseAssistantText(value) {
14148
14925
  if (typeof value === "string") {
14149
14926
  return value.trim().length > 0 ? value : null;
14150
14927
  }
14151
- const payload = toRecord10(value);
14152
- const response = toRecord10(payload.response ?? value);
14928
+ const payload = toRecord12(value);
14929
+ const response = toRecord12(payload.response ?? value);
14930
+ const directOutput = readText2(response, "output");
14931
+ if (directOutput?.trim()) {
14932
+ return directOutput;
14933
+ }
14153
14934
  const directText = readText2(response, "output_text");
14154
14935
  if (directText?.trim()) {
14155
14936
  return directText;
@@ -14198,15 +14979,15 @@ function isTopLevelErrorEvent(event) {
14198
14979
  }
14199
14980
  function readChatCompletionDelta(payload) {
14200
14981
  const choice = readFirstChoice(payload);
14201
- const delta = toRecord10(choice.delta);
14982
+ const delta = toRecord12(choice.delta);
14202
14983
  return readText2(delta, "content");
14203
14984
  }
14204
14985
  function readChatCompletionFinishReason(payload) {
14205
14986
  const choice = readFirstChoice(payload);
14206
- return readString12(choice, "finish_reason") ?? readString12(choice, "finishReason");
14987
+ return readString14(choice, "finish_reason") ?? readString14(choice, "finishReason");
14207
14988
  }
14208
14989
  function readChatCompletionUsage(payload) {
14209
- const usage = toRecord10(payload.usage);
14990
+ const usage = toRecord12(payload.usage);
14210
14991
  const input = readInteger2(usage, "prompt_tokens") ?? readInteger2(usage, "input_tokens");
14211
14992
  const output = readInteger2(usage, "completion_tokens") ?? readInteger2(usage, "output_tokens");
14212
14993
  const total = readInteger2(usage, "total_tokens");
@@ -14235,15 +15016,15 @@ function readFirstChoice(payload) {
14235
15016
  if (!Array.isArray(choices)) {
14236
15017
  return {};
14237
15018
  }
14238
- return toRecord10(choices[0]);
15019
+ return toRecord12(choices[0]);
14239
15020
  }
14240
15021
  function readAssistantTextFromChoices(payload) {
14241
15022
  const choices = payload.choices;
14242
15023
  if (!Array.isArray(choices)) {
14243
15024
  return null;
14244
15025
  }
14245
- const messages = choices.map(toRecord10).map((choice) => toRecord10(choice.message ?? choice.delta)).filter((message) => {
14246
- const role = readString12(message, "role");
15026
+ const messages = choices.map(toRecord12).map((choice) => toRecord12(choice.message ?? choice.delta)).filter((message) => {
15027
+ const role = readString14(message, "role");
14247
15028
  return !role || role === "assistant";
14248
15029
  }).map(readResponseMessageText).filter((text) => Boolean(text?.trim()));
14249
15030
  return messages.length > 0 ? messages.join("\n\n") : null;
@@ -14259,7 +15040,7 @@ function readInteger2(payload, key) {
14259
15040
  }
14260
15041
  return void 0;
14261
15042
  }
14262
- function readString12(payload, key) {
15043
+ function readString14(payload, key) {
14263
15044
  const value = payload[key];
14264
15045
  return typeof value === "string" && value.trim() ? value.trim() : null;
14265
15046
  }
@@ -14271,9 +15052,9 @@ function readResponseOutputItemText(value) {
14271
15052
  if (typeof value === "string") {
14272
15053
  return value;
14273
15054
  }
14274
- const item = toRecord10(value);
14275
- const type = readString12(item, "type");
14276
- const role = readString12(item, "role");
15055
+ const item = toRecord12(value);
15056
+ const type = readString14(item, "type");
15057
+ const role = readString14(item, "role");
14277
15058
  if (type && type !== "message" && type !== "output_text" && type !== "text") {
14278
15059
  return null;
14279
15060
  }
@@ -14291,15 +15072,15 @@ function readResponseContentText(value) {
14291
15072
  return value;
14292
15073
  }
14293
15074
  if (!Array.isArray(value)) {
14294
- const record = toRecord10(value);
15075
+ const record = toRecord12(value);
14295
15076
  return readText2(record, "text") ?? readText2(record, "content") ?? readText2(record, "output_text") ?? readText2(record, "refusal");
14296
15077
  }
14297
15078
  const chunks = value.map((partValue) => {
14298
15079
  if (typeof partValue === "string") {
14299
15080
  return partValue;
14300
15081
  }
14301
- const part = toRecord10(partValue);
14302
- const type = readString12(part, "type");
15082
+ const part = toRecord12(partValue);
15083
+ const type = readString14(part, "type");
14303
15084
  if (type && !isVisibleResponseTextPart(type)) {
14304
15085
  return null;
14305
15086
  }
@@ -14318,10 +15099,10 @@ function readResponseItemOutput(value) {
14318
15099
  if (!Array.isArray(value)) {
14319
15100
  return stringifyJsonValue(value);
14320
15101
  }
14321
- const text = value.map(toRecord10).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
15102
+ const text = value.map(toRecord12).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
14322
15103
  return text || stringifyJsonValue(value);
14323
15104
  }
14324
- function parseJsonValue2(value) {
15105
+ function parseJsonValue3(value) {
14325
15106
  if (typeof value !== "string" || !value.trim()) {
14326
15107
  return null;
14327
15108
  }
@@ -14344,11 +15125,14 @@ function stringifyJsonValue(value) {
14344
15125
  return String(value);
14345
15126
  }
14346
15127
  }
14347
- function toRecord10(value) {
15128
+ function toRecord12(value) {
14348
15129
  return typeof value === "object" && value !== null ? value : {};
14349
15130
  }
14350
15131
 
14351
15132
  // src/conversations/run-lifecycle.ts
15133
+ var RUN_STATUS_RECOVERY_TIMEOUT_MS = 10 * 60 * 1e3;
15134
+ var RUN_STATUS_RECOVERY_INITIAL_DELAY_MS = 500;
15135
+ var RUN_STATUS_RECOVERY_MAX_DELAY_MS = 2500;
14352
15136
  var ConversationRunLifecycle = class {
14353
15137
  constructor(deps) {
14354
15138
  this.deps = deps;
@@ -14363,6 +15147,7 @@ var ConversationRunLifecycle = class {
14363
15147
  const controller = new AbortController();
14364
15148
  this.deps.activeRunControllers.set(runId, { conversationId, controller });
14365
15149
  try {
15150
+ const backend = resolveConversationRunBackend();
14366
15151
  const hermesSessionId = await readHermesCompressionTip(
14367
15152
  run.hermes_session_id,
14368
15153
  this.deps.paths,
@@ -14407,7 +15192,7 @@ var ConversationRunLifecycle = class {
14407
15192
  fallbackInput: input,
14408
15193
  snapshot
14409
15194
  });
14410
- const previousResponseId = findPreviousHermesResponseId(snapshot, run);
15195
+ const previousResponseId = backend === "responses" ? findPreviousHermesResponseId(snapshot, run) : void 0;
14411
15196
  if (previousResponseId) {
14412
15197
  await this.updateRun(conversationId, runId, {
14413
15198
  previous_response_id: previousResponseId
@@ -14435,99 +15220,98 @@ var ConversationRunLifecycle = class {
14435
15220
  if (estimatedUsage) {
14436
15221
  await this.updateRun(conversationId, runId, { usage: estimatedUsage });
14437
15222
  }
14438
- const response = await streamHermesResponses(
14439
- {
14440
- input: resolvedInput,
14441
- instructions,
14442
- session_id: hermesSessionId,
14443
- session_key: await this.buildHermesSessionKey(
14444
- conversationId,
14445
- run.profile ?? "default"
14446
- ),
14447
- model: run.model,
14448
- ...previousResponseId ? { previous_response_id: previousResponseId } : {},
14449
- ...conversationHistory.messages.length > 0 ? { conversation_history: conversationHistory.messages } : {}
14450
- },
14451
- {
14452
- logger: this.deps.logger,
14453
- profileName: run.profile,
14454
- signal: controller.signal
14455
- }
15223
+ const sessionKey = await this.buildHermesSessionKey(
15224
+ conversationId,
15225
+ run.profile ?? "default"
14456
15226
  );
14457
- const responseSessionId = response.headers.get("x-hermes-session-id")?.trim();
14458
- if (responseSessionId) {
14459
- await this.rememberRunHermesSessionId(
14460
- conversationId,
14461
- runId,
14462
- responseSessionId
15227
+ if (backend === "responses") {
15228
+ const response = await streamHermesResponses(
15229
+ {
15230
+ input: resolvedInput,
15231
+ instructions,
15232
+ session_id: hermesSessionId,
15233
+ session_key: sessionKey,
15234
+ model: run.model,
15235
+ ...previousResponseId ? { previous_response_id: previousResponseId } : {},
15236
+ ...conversationHistory.messages.length > 0 ? { conversation_history: conversationHistory.messages } : {}
15237
+ },
15238
+ {
15239
+ logger: this.deps.logger,
15240
+ profileName: run.profile,
15241
+ signal: controller.signal
15242
+ }
14463
15243
  );
14464
- }
14465
- for await (const rawEvent of parseSseResponse(response)) {
14466
- if (controller.signal.aborted) {
14467
- await this.deps.withConversationLock(
15244
+ const responseSessionId = response.headers.get("x-hermes-session-id")?.trim();
15245
+ if (responseSessionId) {
15246
+ await this.rememberRunHermesSessionId(
14468
15247
  conversationId,
14469
- () => this.cancelRunLocked(conversationId, runId, {
14470
- abortUpstream: false,
14471
- reason: "cancelled by app"
14472
- })
15248
+ runId,
15249
+ responseSessionId
14473
15250
  );
14474
- return;
14475
- }
14476
- if (!await this.deps.isConversationRunnable(conversationId)) {
14477
- return;
14478
15251
  }
14479
- const event = normalizeHermesStreamEvent(rawEvent);
14480
- if (!event) {
14481
- continue;
14482
- }
14483
- if (event.payloadType === "run.completed") {
14484
- if (cronJobIdsBeforeRun) {
14485
- await this.bindNewCronJobsCreatedByRun({
14486
- profileName: run.profile,
14487
- conversationId,
14488
- beforeJobIds: cronJobIdsBeforeRun
14489
- });
15252
+ await this.consumeHermesEventStream({
15253
+ backend,
15254
+ conversationId,
15255
+ runId,
15256
+ response,
15257
+ controller,
15258
+ profileName: run.profile,
15259
+ cronJobIdsBeforeRun
15260
+ });
15261
+ } else {
15262
+ const hermesRun = await createHermesRun(
15263
+ {
15264
+ input: resolvedInput,
15265
+ instructions,
15266
+ session_id: hermesSessionId,
15267
+ session_key: sessionKey,
15268
+ model: run.model,
15269
+ ...conversationHistory.messages.length > 0 ? { conversation_history: conversationHistory.messages } : {}
15270
+ },
15271
+ {
15272
+ logger: this.deps.logger,
15273
+ profileName: run.profile,
15274
+ signal: controller.signal
14490
15275
  }
14491
- await this.deps.syncCronDeliveries().catch((error) => {
14492
- void this.deps.logger.warn("cron_link_delivery_sync_failed", {
14493
- conversation_id: conversationId,
14494
- run_id: runId,
14495
- error: error instanceof Error ? error.message : String(error)
14496
- });
14497
- });
14498
- await this.appendAssistantTextFromCompletedResponse(
14499
- conversationId,
14500
- runId,
14501
- event
14502
- );
14503
- await this.importMediaReferencesForEvent(conversationId, runId, event);
14504
- if (!await this.runHasAssistantOutput(conversationId, runId)) {
14505
- await this.failRun(
14506
- conversationId,
14507
- runId,
14508
- await this.buildEmptyHermesResponseMessage({
14509
- source: "final-empty-response"
14510
- }),
14511
- event
14512
- );
14513
- return;
15276
+ );
15277
+ await this.updateRun(conversationId, runId, {
15278
+ hermes_run_id: hermesRun.run_id
15279
+ });
15280
+ const response = await streamHermesRunEvents(hermesRun.run_id, {
15281
+ logger: this.deps.logger,
15282
+ profileName: run.profile,
15283
+ signal: controller.signal
15284
+ }).catch(async (error) => {
15285
+ if (controller.signal.aborted) {
15286
+ throw error;
14514
15287
  }
14515
- await this.completeRun(conversationId, runId, event);
14516
- this.deps.scheduleTitleRefresh(conversationId);
14517
- return;
14518
- }
14519
- if (event.payloadType === "run.failed") {
14520
- await this.importMediaReferencesForEvent(conversationId, runId, event);
14521
- await this.failRun(
15288
+ await this.recoverRunAfterEventStreamOpenFailure({
15289
+ backend,
14522
15290
  conversationId,
14523
15291
  runId,
14524
- readErrorMessage2(event.payload) ?? "Hermes run failed",
14525
- event
14526
- );
15292
+ hermesRunId: hermesRun.run_id,
15293
+ controller,
15294
+ profileName: run.profile,
15295
+ cronJobIdsBeforeRun,
15296
+ error
15297
+ });
15298
+ return null;
15299
+ });
15300
+ if (!response) {
14527
15301
  return;
14528
15302
  }
14529
- await this.persistHermesEvent(conversationId, runId, event);
15303
+ await this.consumeHermesEventStream({
15304
+ backend,
15305
+ conversationId,
15306
+ runId,
15307
+ response,
15308
+ controller,
15309
+ profileName: run.profile,
15310
+ hermesRunId: hermesRun.run_id,
15311
+ cronJobIdsBeforeRun
15312
+ });
14530
15313
  }
15314
+ } catch (error) {
14531
15315
  if (controller.signal.aborted) {
14532
15316
  await this.deps.withConversationLock(
14533
15317
  conversationId,
@@ -14538,60 +15322,381 @@ var ConversationRunLifecycle = class {
14538
15322
  );
14539
15323
  return;
14540
15324
  }
14541
- if (await this.runHasAssistantOutput(conversationId, runId)) {
14542
- await this.completeRun(conversationId, runId);
14543
- } else {
15325
+ throw error;
15326
+ } finally {
15327
+ if (this.deps.activeRunControllers.get(runId)?.controller === controller) {
15328
+ this.deps.activeRunControllers.delete(runId);
15329
+ }
15330
+ }
15331
+ }
15332
+ async cancelRun(conversationId, runId, options) {
15333
+ return this.deps.withConversationLock(
15334
+ conversationId,
15335
+ () => this.cancelRunLocked(conversationId, runId, options)
15336
+ );
15337
+ }
15338
+ async failRun(conversationId, runId, message, source) {
15339
+ return this.deps.withConversationLock(
15340
+ conversationId,
15341
+ () => this.failRunLocked(conversationId, runId, message, source)
15342
+ );
15343
+ }
15344
+ async findConversationIdForRun(runId) {
15345
+ const entries = await readdirWithDirs(this.deps.paths.conversationsDir);
15346
+ for (const entry of entries) {
15347
+ if (!entry.isDirectory()) {
15348
+ continue;
15349
+ }
15350
+ const snapshot = await this.deps.readSnapshot(entry.name).catch(() => null);
15351
+ if (snapshot?.runs.some((run) => run.id === runId)) {
15352
+ return entry.name;
15353
+ }
15354
+ }
15355
+ return void 0;
15356
+ }
15357
+ async consumeHermesEventStream(input) {
15358
+ let streamError;
15359
+ const iterator = parseSseResponse(input.response)[Symbol.asyncIterator]();
15360
+ const toolEventIds = input.backend === "runs" ? new RunToolEventIdCoalescer({
15361
+ runId: input.runId,
15362
+ hermesRunId: input.hermesRunId
15363
+ }) : null;
15364
+ while (true) {
15365
+ let next;
15366
+ try {
15367
+ next = await iterator.next();
15368
+ } catch (error) {
15369
+ if (input.controller.signal.aborted) {
15370
+ await this.cancelRunAfterAbort(input.conversationId, input.runId);
15371
+ return;
15372
+ }
15373
+ streamError = error;
15374
+ await this.deps.logger.warn("hermes_event_stream_interrupted", {
15375
+ backend: input.backend,
15376
+ conversation_id: input.conversationId,
15377
+ run_id: input.runId,
15378
+ ...input.hermesRunId ? { hermes_run_id: input.hermesRunId } : {},
15379
+ error: error instanceof Error ? error.message : String(error)
15380
+ });
15381
+ break;
15382
+ }
15383
+ if (next.done) {
15384
+ break;
15385
+ }
15386
+ if (input.controller.signal.aborted) {
15387
+ await closeSseIterator(iterator);
15388
+ await this.cancelRunAfterAbort(input.conversationId, input.runId);
15389
+ return;
15390
+ }
15391
+ if (!await this.deps.isConversationRunnable(input.conversationId)) {
15392
+ await closeSseIterator(iterator);
15393
+ return;
15394
+ }
15395
+ const event = normalizeHermesStreamEvent(next.value);
15396
+ if (!event) {
15397
+ continue;
15398
+ }
15399
+ const normalizedEvent = toolEventIds?.normalize(event) ?? event;
15400
+ const handled = await this.handleNormalizedHermesEvent({
15401
+ ...input,
15402
+ event: normalizedEvent
15403
+ });
15404
+ if (handled) {
15405
+ await closeSseIterator(iterator);
15406
+ return;
15407
+ }
15408
+ }
15409
+ if (input.controller.signal.aborted) {
15410
+ await this.cancelRunAfterAbort(input.conversationId, input.runId);
15411
+ return;
15412
+ }
15413
+ if (!await this.deps.isConversationRunnable(input.conversationId)) {
15414
+ return;
15415
+ }
15416
+ const recoveredEvent = input.backend === "runs" && input.hermesRunId ? await this.recoverRunTerminalEvent({
15417
+ conversationId: input.conversationId,
15418
+ runId: input.runId,
15419
+ hermesRunId: input.hermesRunId,
15420
+ profileName: input.profileName,
15421
+ signal: input.controller.signal
15422
+ }) : null;
15423
+ if (recoveredEvent) {
15424
+ const handled = await this.handleNormalizedHermesEvent({
15425
+ ...input,
15426
+ event: recoveredEvent
15427
+ });
15428
+ if (handled) {
15429
+ return;
15430
+ }
15431
+ }
15432
+ if (input.controller.signal.aborted) {
15433
+ await this.cancelRunAfterAbort(input.conversationId, input.runId);
15434
+ return;
15435
+ }
15436
+ if (input.backend === "responses" && !streamError && await this.runHasAssistantOutput(input.conversationId, input.runId)) {
15437
+ await this.completeRun(input.conversationId, input.runId);
15438
+ } else {
15439
+ await this.failRun(
15440
+ input.conversationId,
15441
+ input.runId,
15442
+ await this.buildEmptyHermesResponseMessage({
15443
+ source: streamError ? "stream-error" : "stream-ended-without-terminal-event",
15444
+ ...streamError ? { eventError: formatUnknownErrorMessage(streamError) } : {}
15445
+ })
15446
+ );
15447
+ }
15448
+ this.deps.scheduleTitleRefresh(input.conversationId);
15449
+ }
15450
+ async handleNormalizedHermesEvent(input) {
15451
+ if (input.event.payloadType === "run.completed") {
15452
+ if (input.cronJobIdsBeforeRun) {
15453
+ await this.bindNewCronJobsCreatedByRun({
15454
+ profileName: input.profileName,
15455
+ conversationId: input.conversationId,
15456
+ beforeJobIds: input.cronJobIdsBeforeRun
15457
+ });
15458
+ }
15459
+ await this.deps.syncCronDeliveries().catch((error) => {
15460
+ void this.deps.logger.warn("cron_link_delivery_sync_failed", {
15461
+ conversation_id: input.conversationId,
15462
+ run_id: input.runId,
15463
+ error: error instanceof Error ? error.message : String(error)
15464
+ });
15465
+ });
15466
+ if (input.backend === "runs" && isRunToolResultCompensationEnabled()) {
15467
+ await this.enrichRunFromHermesTranscript({
15468
+ conversationId: input.conversationId,
15469
+ runId: input.runId,
15470
+ profileName: input.profileName
15471
+ });
15472
+ }
15473
+ await this.appendAssistantTextFromCompletedResponse(
15474
+ input.conversationId,
15475
+ input.runId,
15476
+ input.event
15477
+ );
15478
+ await this.importMediaReferencesForEvent(
15479
+ input.conversationId,
15480
+ input.runId,
15481
+ input.event
15482
+ );
15483
+ if (!await this.runHasAssistantOutput(input.conversationId, input.runId)) {
14544
15484
  await this.failRun(
14545
- conversationId,
14546
- runId,
15485
+ input.conversationId,
15486
+ input.runId,
14547
15487
  await this.buildEmptyHermesResponseMessage({
14548
- source: "stream-ended-without-terminal-event"
14549
- })
15488
+ source: "final-empty-response"
15489
+ }),
15490
+ input.event
14550
15491
  );
15492
+ return true;
14551
15493
  }
14552
- this.deps.scheduleTitleRefresh(conversationId);
14553
- } catch (error) {
14554
- if (controller.signal.aborted) {
14555
- await this.deps.withConversationLock(
14556
- conversationId,
14557
- () => this.cancelRunLocked(conversationId, runId, {
14558
- abortUpstream: false,
14559
- reason: "cancelled by app"
14560
- })
14561
- );
14562
- return;
15494
+ await this.completeRun(input.conversationId, input.runId, input.event);
15495
+ this.deps.scheduleTitleRefresh(input.conversationId);
15496
+ return true;
15497
+ }
15498
+ if (input.event.payloadType === "run.failed") {
15499
+ if (input.backend === "runs" && isRunToolResultCompensationEnabled()) {
15500
+ await this.enrichRunFromHermesTranscript({
15501
+ conversationId: input.conversationId,
15502
+ runId: input.runId,
15503
+ profileName: input.profileName
15504
+ });
14563
15505
  }
14564
- throw error;
14565
- } finally {
14566
- if (this.deps.activeRunControllers.get(runId)?.controller === controller) {
14567
- this.deps.activeRunControllers.delete(runId);
15506
+ await this.importMediaReferencesForEvent(
15507
+ input.conversationId,
15508
+ input.runId,
15509
+ input.event
15510
+ );
15511
+ await this.failRun(
15512
+ input.conversationId,
15513
+ input.runId,
15514
+ readErrorMessage2(input.event.payload) ?? "Hermes run failed",
15515
+ input.event
15516
+ );
15517
+ return true;
15518
+ }
15519
+ if (input.event.payloadType === "run.cancelled") {
15520
+ await this.completeCancelledRun(input.conversationId, input.runId);
15521
+ return true;
15522
+ }
15523
+ await this.persistHermesEvent(input.conversationId, input.runId, input.event);
15524
+ return false;
15525
+ }
15526
+ async recoverRunAfterEventStreamOpenFailure(input) {
15527
+ await this.deps.logger.warn("hermes_event_stream_open_failed", {
15528
+ backend: input.backend,
15529
+ conversation_id: input.conversationId,
15530
+ run_id: input.runId,
15531
+ hermes_run_id: input.hermesRunId,
15532
+ error: input.error instanceof Error ? input.error.message : String(input.error)
15533
+ });
15534
+ const recoveredEvent = await this.recoverRunTerminalEvent({
15535
+ conversationId: input.conversationId,
15536
+ runId: input.runId,
15537
+ hermesRunId: input.hermesRunId,
15538
+ profileName: input.profileName,
15539
+ signal: input.controller.signal
15540
+ });
15541
+ if (recoveredEvent) {
15542
+ const handled = await this.handleNormalizedHermesEvent({
15543
+ backend: input.backend,
15544
+ conversationId: input.conversationId,
15545
+ runId: input.runId,
15546
+ event: recoveredEvent,
15547
+ profileName: input.profileName,
15548
+ cronJobIdsBeforeRun: input.cronJobIdsBeforeRun
15549
+ });
15550
+ if (handled) {
15551
+ return;
14568
15552
  }
14569
15553
  }
15554
+ if (input.controller.signal.aborted) {
15555
+ await this.cancelRunAfterAbort(input.conversationId, input.runId);
15556
+ return;
15557
+ }
15558
+ await this.failRun(
15559
+ input.conversationId,
15560
+ input.runId,
15561
+ await this.buildEmptyHermesResponseMessage({
15562
+ source: "stream-error",
15563
+ eventError: formatUnknownErrorMessage(input.error)
15564
+ })
15565
+ );
14570
15566
  }
14571
- async cancelRun(conversationId, runId, options) {
14572
- return this.deps.withConversationLock(
15567
+ async cancelRunAfterAbort(conversationId, runId) {
15568
+ await this.deps.withConversationLock(
14573
15569
  conversationId,
14574
- () => this.cancelRunLocked(conversationId, runId, options)
15570
+ () => this.cancelRunLocked(conversationId, runId, {
15571
+ abortUpstream: false,
15572
+ reason: "cancelled by app"
15573
+ })
14575
15574
  );
14576
15575
  }
14577
- async failRun(conversationId, runId, message, source) {
14578
- return this.deps.withConversationLock(
15576
+ async completeCancelledRun(conversationId, runId) {
15577
+ await this.deps.withConversationLock(
14579
15578
  conversationId,
14580
- () => this.failRunLocked(conversationId, runId, message, source)
15579
+ () => this.cancelRunLocked(conversationId, runId, {
15580
+ abortUpstream: false,
15581
+ reason: "cancelled by Hermes"
15582
+ })
14581
15583
  );
14582
15584
  }
14583
- async findConversationIdForRun(runId) {
14584
- const entries = await readdirWithDirs(this.deps.paths.conversationsDir);
14585
- for (const entry of entries) {
14586
- if (!entry.isDirectory()) {
15585
+ async recoverRunTerminalEvent(input) {
15586
+ const deadline = Date.now() + RUN_STATUS_RECOVERY_TIMEOUT_MS;
15587
+ let delayMs = RUN_STATUS_RECOVERY_INITIAL_DELAY_MS;
15588
+ while (!input.signal.aborted) {
15589
+ let status;
15590
+ try {
15591
+ status = await readHermesRunStatus(input.hermesRunId, {
15592
+ logger: this.deps.logger,
15593
+ profileName: input.profileName,
15594
+ signal: input.signal
15595
+ });
15596
+ } catch (error) {
15597
+ if (input.signal.aborted) {
15598
+ return null;
15599
+ }
15600
+ await this.deps.logger.warn("hermes_run_status_recovery_failed", {
15601
+ conversation_id: input.conversationId,
15602
+ run_id: input.runId,
15603
+ hermes_run_id: input.hermesRunId,
15604
+ error: error instanceof Error ? error.message : String(error)
15605
+ });
15606
+ if (Date.now() >= deadline) {
15607
+ return null;
15608
+ }
15609
+ await sleep(Math.min(delayMs, deadline - Date.now()), input.signal);
15610
+ delayMs = Math.min(RUN_STATUS_RECOVERY_MAX_DELAY_MS, delayMs + 250);
14587
15611
  continue;
14588
15612
  }
14589
- const snapshot = await this.deps.readSnapshot(entry.name).catch(() => null);
14590
- if (snapshot?.runs.some((run) => run.id === runId)) {
14591
- return entry.name;
15613
+ if (!status) {
15614
+ return null;
15615
+ }
15616
+ if (status.session_id) {
15617
+ await this.rememberRunHermesSessionId(
15618
+ input.conversationId,
15619
+ input.runId,
15620
+ status.session_id
15621
+ );
15622
+ }
15623
+ const normalizedStatus = status.status.trim().toLowerCase();
15624
+ if (isCompletedRunStatus(normalizedStatus)) {
15625
+ return {
15626
+ eventName: "run.completed",
15627
+ payloadType: "run.completed",
15628
+ payload: {
15629
+ type: "run.completed",
15630
+ run_id: status.run_id,
15631
+ output: status.output,
15632
+ usage: status.usage,
15633
+ status: status.status
15634
+ },
15635
+ rawPayload: status.raw
15636
+ };
15637
+ }
15638
+ if (isFailedRunStatus(normalizedStatus)) {
15639
+ return {
15640
+ eventName: "run.failed",
15641
+ payloadType: "run.failed",
15642
+ payload: {
15643
+ type: "run.failed",
15644
+ run_id: status.run_id,
15645
+ error: {
15646
+ message: readStatusErrorMessage(status.error) ?? "Hermes run failed"
15647
+ },
15648
+ status: status.status,
15649
+ usage: status.usage
15650
+ },
15651
+ rawPayload: status.raw
15652
+ };
15653
+ }
15654
+ if (isCancelledRunStatus(normalizedStatus)) {
15655
+ return {
15656
+ eventName: "run.cancelled",
15657
+ payloadType: "run.cancelled",
15658
+ payload: {
15659
+ type: "run.cancelled",
15660
+ run_id: status.run_id,
15661
+ status: status.status
15662
+ },
15663
+ rawPayload: status.raw
15664
+ };
14592
15665
  }
15666
+ if (Date.now() >= deadline) {
15667
+ return null;
15668
+ }
15669
+ await sleep(Math.min(delayMs, deadline - Date.now()), input.signal);
15670
+ delayMs = Math.min(RUN_STATUS_RECOVERY_MAX_DELAY_MS, delayMs + 250);
15671
+ }
15672
+ return null;
15673
+ }
15674
+ async enrichRunFromHermesTranscript(input) {
15675
+ const snapshot = await this.deps.readSnapshot(input.conversationId).catch(() => null);
15676
+ const run = snapshot?.runs.find((item) => item.id === input.runId);
15677
+ const assistant = snapshot?.messages.find(
15678
+ (message) => message.id === run?.assistant_message_id
15679
+ );
15680
+ if (!snapshot || !run) {
15681
+ return;
15682
+ }
15683
+ const events = await buildRunTranscriptEvents({
15684
+ profileName: input.profileName,
15685
+ hermesSessionId: run.hermes_session_id,
15686
+ runStartedAt: run.started_at,
15687
+ assistant
15688
+ }).catch(async (error) => {
15689
+ await this.deps.logger.warn("hermes_run_transcript_enrichment_failed", {
15690
+ conversation_id: input.conversationId,
15691
+ run_id: input.runId,
15692
+ hermes_session_id: run.hermes_session_id,
15693
+ error: error instanceof Error ? error.message : String(error)
15694
+ });
15695
+ return [];
15696
+ });
15697
+ for (const event of events) {
15698
+ await this.persistHermesEvent(input.conversationId, input.runId, event);
14593
15699
  }
14594
- return void 0;
14595
15700
  }
14596
15701
  async resolveRunInput(input) {
14597
15702
  const userMessage = input.snapshot.messages.find(
@@ -14738,6 +15843,12 @@ ${attachmentLines.join("\n")}`
14738
15843
  "\u8FD9\u66F4\u50CF\u662F Gateway \u6216 provider \u7684\u6D41\u5F0F\u4E8B\u4EF6\u4E2D\u65AD\uFF0C\u4E0D\u662F\u6A21\u578B\u660E\u786E\u5B8C\u6210\u4E86\u7A7A\u56DE\u590D\u3002"
14739
15844
  );
14740
15845
  }
15846
+ if (input?.source === "stream-error") {
15847
+ details.unshift("Hermes \u7684\u8FD0\u884C\u4E8B\u4EF6\u6D41\u8BFB\u53D6\u8FC7\u7A0B\u4E2D\u65AD\u3002");
15848
+ details.push(
15849
+ "Link \u5DF2\u5C1D\u8BD5\u67E5\u8BE2 Hermes run \u7EC8\u6001\uFF0C\u4F46\u4ECD\u6CA1\u6709\u6062\u590D\u5230\u5B8C\u6210\u6216\u5931\u8D25\u4E8B\u4EF6\u3002"
15850
+ );
15851
+ }
14741
15852
  return details.length > 0 ? `Hermes \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\u3002
14742
15853
  ${details.join("\n")}` : emptyHermesResponseMessage();
14743
15854
  }
@@ -14882,8 +15993,8 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
14882
15993
  }
14883
15994
  const textPart = assistant.parts.find((part) => part.type === "text");
14884
15995
  const currentText = textPart?.text ?? "";
14885
- const pendingDeliveryText = readString13(
14886
- toRecord11(assistant.hermes),
15996
+ const pendingDeliveryText = readString15(
15997
+ toRecord13(assistant.hermes),
14887
15998
  "pending_media_delivery_text"
14888
15999
  );
14889
16000
  const normalizedDelta = normalizeStreamingTextDelta(
@@ -14898,7 +16009,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
14898
16009
  pendingDeliveryText ?? ""
14899
16010
  );
14900
16011
  const nextHermes = {
14901
- ...toRecord11(assistant.hermes),
16012
+ ...toRecord13(assistant.hermes),
14902
16013
  ...extracted.pendingText ? { pending_media_delivery_text: extracted.pendingText } : {}
14903
16014
  };
14904
16015
  if (!extracted.pendingText) {
@@ -14977,11 +16088,15 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
14977
16088
  const completedAt = (/* @__PURE__ */ new Date()).toISOString();
14978
16089
  const usage = readUsage(source?.payload);
14979
16090
  const responseId = readResponseId(source?.payload);
16091
+ const hermesRunId = readRunId(source?.payload);
14980
16092
  run.status = "completed";
14981
16093
  run.completed_at = completedAt;
14982
16094
  if (responseId) {
14983
16095
  run.hermes_response_id = responseId;
14984
16096
  }
16097
+ if (hermesRunId) {
16098
+ run.hermes_run_id = hermesRunId;
16099
+ }
14985
16100
  if (usage) {
14986
16101
  run.usage = mergeRunUsage(run.usage, usage);
14987
16102
  }
@@ -15155,7 +16270,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
15155
16270
  if (raw.length <= 200) {
15156
16271
  return raw;
15157
16272
  }
15158
- return `hermespilot:${createHash4("sha256").update(raw).digest("hex")}`;
16273
+ return `hermespilot:${createHash5("sha256").update(raw).digest("hex")}`;
15159
16274
  }
15160
16275
  async assistantMessageIdForRun(conversationId, runId) {
15161
16276
  const snapshot = await this.deps.readSnapshot(conversationId).catch(() => null);
@@ -15176,7 +16291,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
15176
16291
  includeDisabled: true
15177
16292
  });
15178
16293
  return new Set(
15179
- jobs.map((job) => readString13(job, "id") ?? readString13(job, "job_id")).filter((id) => Boolean(id))
16294
+ jobs.map((job) => readString15(job, "id") ?? readString15(job, "job_id")).filter((id) => Boolean(id))
15180
16295
  );
15181
16296
  }
15182
16297
  async bindNewCronJobsCreatedByRun(input) {
@@ -15212,7 +16327,7 @@ function buildRunInstructions(run, deliveryStagingDir) {
15212
16327
  ].join("\n");
15213
16328
  }
15214
16329
  function appendMediaImportFailureNotice(message) {
15215
- const hermes = toRecord11(message.hermes);
16330
+ const hermes = toRecord13(message.hermes);
15216
16331
  if (hermes.media_import_failure_notice_appended === true) {
15217
16332
  return;
15218
16333
  }
@@ -15256,17 +16371,17 @@ function formatFilenameList(filenames) {
15256
16371
  }
15257
16372
  async function readdirWithDirs(directory) {
15258
16373
  return readdir8(directory, { withFileTypes: true }).catch((error) => {
15259
- if (isNodeError13(error, "ENOENT")) {
16374
+ if (isNodeError14(error, "ENOENT")) {
15260
16375
  return [];
15261
16376
  }
15262
16377
  throw error;
15263
16378
  });
15264
16379
  }
15265
- function readString13(payload, key) {
16380
+ function readString15(payload, key) {
15266
16381
  const value = payload[key];
15267
16382
  return typeof value === "string" && value.trim() ? value.trim() : null;
15268
16383
  }
15269
- function toRecord11(value) {
16384
+ function toRecord13(value) {
15270
16385
  return typeof value === "object" && value !== null ? value : {};
15271
16386
  }
15272
16387
  function formatFailureMessage(message, detail) {
@@ -15282,17 +16397,17 @@ function isFileSearchCompletion(payloadType, payload) {
15282
16397
  if (payloadType !== "tool.completed") {
15283
16398
  return false;
15284
16399
  }
15285
- const tool = toRecord11(payload.tool);
15286
- const toolCall = toRecord11(payload.tool_call ?? payload.toolCall);
15287
- const fn = toRecord11(toolCall.function ?? payload.function);
16400
+ const tool = toRecord13(payload.tool);
16401
+ const toolCall = toRecord13(payload.tool_call ?? payload.toolCall);
16402
+ const fn = toRecord13(toolCall.function ?? payload.function);
15288
16403
  const candidates = [
15289
- readString13(payload, "tool_name"),
15290
- readString13(payload, "toolName"),
15291
- readString13(payload, "name"),
15292
- readString13(payload, "tool"),
15293
- readString13(tool, "name"),
15294
- readString13(toolCall, "name"),
15295
- readString13(fn, "name")
16404
+ readString15(payload, "tool_name"),
16405
+ readString15(payload, "toolName"),
16406
+ readString15(payload, "name"),
16407
+ readString15(payload, "tool"),
16408
+ readString15(tool, "name"),
16409
+ readString15(toolCall, "name"),
16410
+ readString15(fn, "name")
15296
16411
  ].filter((value) => Boolean(value)).map(normalizeToolName);
15297
16412
  return candidates.some(
15298
16413
  (name) => [
@@ -15412,22 +16527,15 @@ function appendAgentEventBlock2(message, event, updatedAt) {
15412
16527
  }
15413
16528
  function contextUsagePayload(run) {
15414
16529
  const usage = run.usage;
15415
- if (!usage) {
16530
+ const runtimeContext = resolveRuntimeContextUsage({
16531
+ usage,
16532
+ contextWindow: run.context_window
16533
+ });
16534
+ const contextTokens = runtimeContext.contextTokens;
16535
+ const contextWindow = runtimeContext.contextWindow;
16536
+ if (!usage || contextTokens === void 0) {
15416
16537
  return null;
15417
16538
  }
15418
- const contextTokens = usage?.context_tokens;
15419
- const contextWindow = usage?.context_window ?? run.context_window;
15420
- if (contextTokens === void 0) {
15421
- return {
15422
- input_tokens: 0,
15423
- output_tokens: usage.output_tokens ?? 0,
15424
- total_tokens: usage.total_tokens ?? 0,
15425
- ...contextWindow ? { context_window: contextWindow } : {},
15426
- ...contextWindow ? { window_tokens: contextWindow } : {},
15427
- source: "unknown"
15428
- };
15429
- }
15430
- const contextSource = usage.context_source ?? "explicit";
15431
16539
  return {
15432
16540
  input_tokens: contextTokens,
15433
16541
  output_tokens: usage?.output_tokens ?? 0,
@@ -15435,13 +16543,8 @@ function contextUsagePayload(run) {
15435
16543
  ...contextWindow ? { context_window: contextWindow } : {},
15436
16544
  used_tokens: contextTokens,
15437
16545
  ...contextWindow ? { window_tokens: contextWindow } : {},
15438
- source: contextSource,
15439
- ...usage?.usage_percent !== void 0 ? { usage_percent: usage.usage_percent } : contextWindow ? {
15440
- usage_percent: Math.min(
15441
- 100,
15442
- Math.round(contextTokens / contextWindow * 100)
15443
- )
15444
- } : {}
16546
+ source: runtimeContext.source,
16547
+ ...runtimeContext.usagePercent !== void 0 ? { usage_percent: runtimeContext.usagePercent } : {}
15445
16548
  };
15446
16549
  }
15447
16550
  function mergeRunUsage(previous, next) {
@@ -15506,10 +16609,57 @@ function readResponseId(payload) {
15506
16609
  if (!payload) {
15507
16610
  return null;
15508
16611
  }
15509
- const response = toRecord11(payload.response);
15510
- return readString13(payload, "response_id") ?? readString13(response, "id");
16612
+ const response = toRecord13(payload.response);
16613
+ return readString15(payload, "response_id") ?? readString15(response, "id");
15511
16614
  }
15512
- function isNodeError13(error, code) {
16615
+ function readRunId(payload) {
16616
+ if (!payload) {
16617
+ return null;
16618
+ }
16619
+ return readString15(payload, "run_id") ?? readString15(payload, "runId");
16620
+ }
16621
+ function isCompletedRunStatus(status) {
16622
+ return status === "completed" || status === "complete" || status === "succeeded" || status === "success" || status === "done";
16623
+ }
16624
+ function isFailedRunStatus(status) {
16625
+ return status === "failed" || status === "failure" || status === "error";
16626
+ }
16627
+ function isCancelledRunStatus(status) {
16628
+ return status === "cancelled" || status === "canceled" || status === "stopped" || status === "aborted";
16629
+ }
16630
+ function readStatusErrorMessage(value) {
16631
+ if (typeof value === "string" && value.trim()) {
16632
+ return value.trim();
16633
+ }
16634
+ const record = toRecord13(value);
16635
+ return readString15(record, "message") ?? readString15(record, "error");
16636
+ }
16637
+ function formatUnknownErrorMessage(error) {
16638
+ return error instanceof Error ? error.message : String(error);
16639
+ }
16640
+ async function closeSseIterator(iterator) {
16641
+ if (!iterator.return) {
16642
+ return;
16643
+ }
16644
+ await iterator.return().catch(() => void 0);
16645
+ }
16646
+ async function sleep(ms, signal) {
16647
+ if (ms <= 0 || signal.aborted) {
16648
+ return;
16649
+ }
16650
+ await new Promise((resolve) => {
16651
+ const timeout = setTimeout(resolve, ms);
16652
+ signal.addEventListener(
16653
+ "abort",
16654
+ () => {
16655
+ clearTimeout(timeout);
16656
+ resolve();
16657
+ },
16658
+ { once: true }
16659
+ );
16660
+ });
16661
+ }
16662
+ function isNodeError14(error, code) {
15513
16663
  if (typeof error !== "object" || error === null || !("code" in error)) {
15514
16664
  return false;
15515
16665
  }
@@ -16433,7 +17583,7 @@ function findApproval(snapshot, approvalId) {
16433
17583
  }
16434
17584
 
16435
17585
  // src/security/devices.ts
16436
- import { randomBytes as randomBytes2, randomUUID as randomUUID11, timingSafeEqual, createHash as createHash5 } from "crypto";
17586
+ import { randomBytes as randomBytes2, randomUUID as randomUUID11, timingSafeEqual, createHash as createHash6 } from "crypto";
16437
17587
  var ACCESS_TOKEN_TTL_MS = 15 * 60 * 1e3;
16438
17588
  var REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
16439
17589
  var DEVICE_SEEN_WRITE_INTERVAL_MS = 60 * 60 * 1e3;
@@ -16729,7 +17879,7 @@ function randomToken(prefix) {
16729
17879
  return `${prefix}${randomBytes2(24).toString("base64url")}`;
16730
17880
  }
16731
17881
  function sha256(value) {
16732
- return createHash5("sha256").update(value).digest("hex");
17882
+ return createHash6("sha256").update(value).digest("hex");
16733
17883
  }
16734
17884
  function safeEqual(left, right) {
16735
17885
  const leftBytes = Buffer.from(left);
@@ -16900,12 +18050,12 @@ async function readRawBody(request, maxBytes) {
16900
18050
  }
16901
18051
  return Buffer.concat(chunks);
16902
18052
  }
16903
- function readString14(body, key) {
18053
+ function readString16(body, key) {
16904
18054
  const value = body[key];
16905
18055
  return typeof value === "string" && value.trim() ? value.trim() : null;
16906
18056
  }
16907
18057
  function readOptionalProfileName(body) {
16908
- return readString14(body, "profile") ?? readString14(body, "profile_name") ?? readString14(body, "profileName") ?? void 0;
18058
+ return readString16(body, "profile") ?? readString16(body, "profile_name") ?? readString16(body, "profileName") ?? void 0;
16909
18059
  }
16910
18060
  function readStringArray(body, ...keys) {
16911
18061
  for (const key of keys) {
@@ -17273,7 +18423,7 @@ function registerConversationRoutes(router, options) {
17273
18423
  ctx.body = {
17274
18424
  ok: true,
17275
18425
  conversation: await conversations.createConversation({
17276
- title: readString14(body, "title") ?? void 0,
18426
+ title: readString16(body, "title") ?? void 0,
17277
18427
  profileName: readOptionalProfileName(body)
17278
18428
  })
17279
18429
  };
@@ -17345,7 +18495,7 @@ function registerConversationRoutes(router, options) {
17345
18495
  router.post("/api/v1/conversations/:conversationId/messages", async (ctx) => {
17346
18496
  await authenticateRequest(ctx, paths);
17347
18497
  const body = await readJsonBody(ctx.req);
17348
- const content = readString14(body, "content") ?? readString14(body, "text") ?? readString14(body, "input") ?? "";
18498
+ const content = readString16(body, "content") ?? readString16(body, "text") ?? readString16(body, "input") ?? "";
17349
18499
  const attachments = readMessageAttachments(body.attachments ?? body.blobs);
17350
18500
  if (!content && attachments.length === 0) {
17351
18501
  throw new LinkHttpError(
@@ -17361,7 +18511,7 @@ function registerConversationRoutes(router, options) {
17361
18511
  conversationId: ctx.params.conversationId,
17362
18512
  content,
17363
18513
  attachments,
17364
- clientMessageId: readString14(body, "client_message_id") ?? readString14(body, "clientMessageId") ?? void 0,
18514
+ clientMessageId: readString16(body, "client_message_id") ?? readString16(body, "clientMessageId") ?? void 0,
17365
18515
  idempotencyKey: readHeader(ctx, "idempotency-key") ?? void 0,
17366
18516
  profileName: readOptionalProfileName(body)
17367
18517
  })
@@ -17370,7 +18520,7 @@ function registerConversationRoutes(router, options) {
17370
18520
  router.patch("/api/v1/conversations/:conversationId/model", async (ctx) => {
17371
18521
  await authenticateRequest(ctx, paths);
17372
18522
  const body = await readJsonBody(ctx.req);
17373
- const modelId = readString14(body, "model_id") ?? readString14(body, "modelId") ?? readString14(body, "model");
18523
+ const modelId = readString16(body, "model_id") ?? readString16(body, "modelId") ?? readString16(body, "model");
17374
18524
  if (!modelId) {
17375
18525
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
17376
18526
  }
@@ -17400,7 +18550,7 @@ function registerConversationRoutes(router, options) {
17400
18550
  router.patch("/api/v1/conversations/:conversationId/title", async (ctx) => {
17401
18551
  await authenticateRequest(ctx, paths);
17402
18552
  const body = await readJsonBody(ctx.req);
17403
- const title = readString14(body, "title") ?? readString14(body, "name") ?? readString14(body, "display_name");
18553
+ const title = readString16(body, "title") ?? readString16(body, "name") ?? readString16(body, "display_name");
17404
18554
  if (!title) {
17405
18555
  throw new LinkHttpError(400, "title_required", "title is required");
17406
18556
  }
@@ -17539,7 +18689,7 @@ function registerConversationRoutes(router, options) {
17539
18689
  async (ctx) => {
17540
18690
  await authenticateRequest(ctx, paths);
17541
18691
  const body = await readJsonBody(ctx.req);
17542
- const scope = readString14(body, "scope") ?? "always";
18692
+ const scope = readString16(body, "scope") ?? "always";
17543
18693
  ctx.body = {
17544
18694
  ok: true,
17545
18695
  ...await conversations.resolveApproval({
@@ -17640,7 +18790,7 @@ function resolveConversationEventCursor(input) {
17640
18790
  return Math.max(queryAfter, headerAfter);
17641
18791
  }
17642
18792
  function readConversationClearPlanTargetStatus(body) {
17643
- const raw = readString14(body, "target_status") ?? readString14(body, "targetStatus") ?? "active";
18793
+ const raw = readString16(body, "target_status") ?? readString16(body, "targetStatus") ?? "active";
17644
18794
  if (raw === "active" || raw === "archived") {
17645
18795
  return raw;
17646
18796
  }
@@ -17731,8 +18881,8 @@ function createHttpErrorMiddleware(logger) {
17731
18881
 
17732
18882
  // src/hermes/profiles.ts
17733
18883
  import { execFile as execFile4 } from "child_process";
17734
- import { readdir as readdir9, readFile as readFile12, rename as rename3, stat as stat12 } from "fs/promises";
17735
- import path19 from "path";
18884
+ import { readdir as readdir9, readFile as readFile13, rename as rename3, stat as stat13 } from "fs/promises";
18885
+ import path20 from "path";
17736
18886
  import { setTimeout as delay2 } from "timers/promises";
17737
18887
  import { promisify as promisify4 } from "util";
17738
18888
  import YAML2 from "yaml";
@@ -17749,7 +18899,7 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
17749
18899
  const profilesDir = resolveHermesProfilesDir();
17750
18900
  const entries = await readdir9(profilesDir, { withFileTypes: true }).catch(
17751
18901
  (error) => {
17752
- if (isNodeError14(error, "ENOENT")) {
18902
+ if (isNodeError15(error, "ENOENT")) {
17753
18903
  return [];
17754
18904
  }
17755
18905
  throw error;
@@ -17773,8 +18923,8 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
17773
18923
  async function getHermesProfileStatus(name, paths = resolveRuntimePaths()) {
17774
18924
  assertProfileName(name);
17775
18925
  const profile = await profileInfo(name, paths);
17776
- const exists = await stat12(profile.path).then((value) => value.isDirectory()).catch((error) => {
17777
- if (isNodeError14(error, "ENOENT")) {
18926
+ const exists = await stat13(profile.path).then((value) => value.isDirectory()).catch((error) => {
18927
+ if (isNodeError15(error, "ENOENT")) {
17778
18928
  return false;
17779
18929
  }
17780
18930
  throw error;
@@ -17843,7 +18993,7 @@ async function readHermesProfileCapabilities(name) {
17843
18993
  return {
17844
18994
  defaultModel: listedModels?.defaultModel ?? null,
17845
18995
  modelCount: listedModels?.models.length ?? 0,
17846
- skillCount: await countSkills(path19.join(profileDir, "skills")).catch(
18996
+ skillCount: await countSkills(path20.join(profileDir, "skills")).catch(
17847
18997
  () => 0
17848
18998
  ),
17849
18999
  toolCount: await countConfiguredTools(name).catch(() => 0)
@@ -17886,8 +19036,8 @@ function assertProfileName(name) {
17886
19036
  }
17887
19037
  }
17888
19038
  async function pathExists(targetPath) {
17889
- return await stat12(targetPath).then(() => true).catch((error) => {
17890
- if (isNodeError14(error, "ENOENT")) {
19039
+ return await stat13(targetPath).then(() => true).catch((error) => {
19040
+ if (isNodeError15(error, "ENOENT")) {
17891
19041
  return false;
17892
19042
  }
17893
19043
  throw error;
@@ -18004,7 +19154,7 @@ function isProcessRunning(pid) {
18004
19154
  process.kill(pid, 0);
18005
19155
  return true;
18006
19156
  } catch (error) {
18007
- return isNodeError14(error, "EPERM");
19157
+ return isNodeError15(error, "EPERM");
18008
19158
  }
18009
19159
  }
18010
19160
  async function waitForProfilePathToRemainAbsent(profilePath) {
@@ -18041,7 +19191,7 @@ function readExecErrorOutput2(error) {
18041
19191
  }
18042
19192
  return parts.join("\n");
18043
19193
  }
18044
- function isNodeError14(error, code) {
19194
+ function isNodeError15(error, code) {
18045
19195
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
18046
19196
  }
18047
19197
  function escapeRegExp2(value) {
@@ -18050,7 +19200,7 @@ function escapeRegExp2(value) {
18050
19200
  async function countSkills(root) {
18051
19201
  const entries = await readdir9(root, { withFileTypes: true }).catch(
18052
19202
  (error) => {
18053
- if (isNodeError14(error, "ENOENT")) {
19203
+ if (isNodeError15(error, "ENOENT")) {
18054
19204
  return [];
18055
19205
  }
18056
19206
  throw error;
@@ -18058,7 +19208,7 @@ async function countSkills(root) {
18058
19208
  );
18059
19209
  let count = 0;
18060
19210
  for (const entry of entries) {
18061
- const entryPath = path19.join(root, entry.name);
19211
+ const entryPath = path20.join(root, entry.name);
18062
19212
  if (entry.name === ".git" || entry.name === ".hub") {
18063
19213
  continue;
18064
19214
  }
@@ -18073,11 +19223,11 @@ async function countSkills(root) {
18073
19223
  return count;
18074
19224
  }
18075
19225
  async function countConfiguredTools(profileName) {
18076
- const raw = await readFile12(
19226
+ const raw = await readFile13(
18077
19227
  resolveHermesConfigPath(profileName),
18078
19228
  "utf8"
18079
19229
  ).catch((error) => {
18080
- if (isNodeError14(error, "ENOENT")) {
19230
+ if (isNodeError15(error, "ENOENT")) {
18081
19231
  return "";
18082
19232
  }
18083
19233
  throw error;
@@ -18085,14 +19235,14 @@ async function countConfiguredTools(profileName) {
18085
19235
  if (!raw.trim()) {
18086
19236
  return 0;
18087
19237
  }
18088
- const config = toRecord12(YAML2.parse(raw));
19238
+ const config = toRecord14(YAML2.parse(raw));
18089
19239
  const toolsets = /* @__PURE__ */ new Set();
18090
19240
  collectToolsetValues(config.toolsets, toolsets);
18091
- const platformToolsets = toRecord12(config.platform_toolsets);
19241
+ const platformToolsets = toRecord14(config.platform_toolsets);
18092
19242
  for (const value of Object.values(platformToolsets)) {
18093
19243
  collectToolsetValues(value, toolsets);
18094
19244
  }
18095
- const mcpServers = Object.keys(toRecord12(config.mcp_servers)).length;
19245
+ const mcpServers = Object.keys(toRecord14(config.mcp_servers)).length;
18096
19246
  return toolsets.size + mcpServers;
18097
19247
  }
18098
19248
  function collectToolsetValues(value, target) {
@@ -18106,7 +19256,7 @@ function collectToolsetValues(value, target) {
18106
19256
  target.add(value.trim());
18107
19257
  }
18108
19258
  }
18109
- function toRecord12(value) {
19259
+ function toRecord14(value) {
18110
19260
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
18111
19261
  }
18112
19262
 
@@ -18303,7 +19453,7 @@ function toHermesCronJobInput(input) {
18303
19453
  };
18304
19454
  }
18305
19455
  async function bindAndDecorateCronJobForHermesLink(input) {
18306
- const jobId = readString14(input.job, "id") ?? readString14(input.job, "job_id");
19456
+ const jobId = readString16(input.job, "id") ?? readString16(input.job, "job_id");
18307
19457
  if (!jobId) {
18308
19458
  return input.job;
18309
19459
  }
@@ -18320,9 +19470,9 @@ async function bindAndDecorateCronJobForHermesLink(input) {
18320
19470
  }
18321
19471
  function readCronJobCreateInput(body) {
18322
19472
  const input = {};
18323
- const name = readString14(body, "name") ?? readString14(body, "title");
18324
- const prompt = readString14(body, "prompt") ?? readString14(body, "description") ?? readString14(body, "task");
18325
- const schedule = readString14(body, "schedule");
19473
+ const name = readString16(body, "name") ?? readString16(body, "title");
19474
+ const prompt = readString16(body, "prompt") ?? readString16(body, "description") ?? readString16(body, "task");
19475
+ const schedule = readString16(body, "schedule");
18326
19476
  if (!name) {
18327
19477
  throw new LinkHttpError(400, "cron_job_name_required", "name is required");
18328
19478
  }
@@ -18343,7 +19493,7 @@ function readCronJobCreateInput(body) {
18343
19493
  input.name = name;
18344
19494
  input.prompt = prompt;
18345
19495
  input.schedule = schedule;
18346
- input.deliver = readString14(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
19496
+ input.deliver = readString16(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
18347
19497
  const skills = readOptionalCronSkills(body);
18348
19498
  if (skills) {
18349
19499
  input.skills = skills;
@@ -18587,7 +19737,7 @@ function registerModelConfigRoutes(router, options) {
18587
19737
  router.delete("/api/v1/model-configs", async (ctx) => {
18588
19738
  await authenticateRequest(ctx, paths);
18589
19739
  const body = await readJsonBody(ctx.req);
18590
- const modelId = readString14(body, "model_id") ?? readString14(body, "modelId");
19740
+ const modelId = readString16(body, "model_id") ?? readString16(body, "modelId");
18591
19741
  if (!modelId) {
18592
19742
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
18593
19743
  }
@@ -18659,7 +19809,7 @@ function registerModelConfigRoutes(router, options) {
18659
19809
  await authenticateRequest(ctx, paths);
18660
19810
  await getHermesProfileStatus(ctx.params.name, paths);
18661
19811
  const body = await readJsonBody(ctx.req);
18662
- const modelId = readString14(body, "model_id") ?? readString14(body, "modelId");
19812
+ const modelId = readString16(body, "model_id") ?? readString16(body, "modelId");
18663
19813
  if (!modelId) {
18664
19814
  throw new LinkHttpError(400, "model_id_required", "model_id is required");
18665
19815
  }
@@ -18676,9 +19826,9 @@ function registerModelConfigRoutes(router, options) {
18676
19826
  });
18677
19827
  }
18678
19828
  function readModelConfigInput(body) {
18679
- const id = readString14(body, "id") ?? readString14(body, "model_id") ?? readString14(body, "modelId");
18680
- const provider = readString14(body, "provider") ?? readString14(body, "provider_key") ?? readString14(body, "providerKey");
18681
- const baseUrl = readString14(body, "base_url") ?? readString14(body, "baseUrl");
19829
+ const id = readString16(body, "id") ?? readString16(body, "model_id") ?? readString16(body, "modelId");
19830
+ const provider = readString16(body, "provider") ?? readString16(body, "provider_key") ?? readString16(body, "providerKey");
19831
+ const baseUrl = readString16(body, "base_url") ?? readString16(body, "baseUrl");
18682
19832
  if (!id || !provider || !baseUrl) {
18683
19833
  throw new LinkHttpError(
18684
19834
  400,
@@ -18688,29 +19838,29 @@ function readModelConfigInput(body) {
18688
19838
  }
18689
19839
  return {
18690
19840
  id,
18691
- originalModelId: readString14(body, "original_model_id") ?? readString14(body, "originalModelId") ?? readString14(body, "original_id") ?? void 0,
19841
+ originalModelId: readString16(body, "original_model_id") ?? readString16(body, "originalModelId") ?? readString16(body, "original_id") ?? void 0,
18692
19842
  provider,
18693
- providerName: readString14(body, "provider_name") ?? readString14(body, "providerName") ?? void 0,
19843
+ providerName: readString16(body, "provider_name") ?? readString16(body, "providerName") ?? void 0,
18694
19844
  baseUrl,
18695
- apiKey: readString14(body, "api_key") ?? readString14(body, "apiKey") ?? void 0,
18696
- apiMode: readString14(body, "api_mode") ?? readString14(body, "apiMode") ?? void 0,
19845
+ apiKey: readString16(body, "api_key") ?? readString16(body, "apiKey") ?? void 0,
19846
+ apiMode: readString16(body, "api_mode") ?? readString16(body, "apiMode") ?? void 0,
18697
19847
  contextLength: readPositiveInteger2(
18698
19848
  body.context_length ?? body.contextLength
18699
19849
  ),
18700
- keyEnv: readString14(body, "key_env") ?? readString14(body, "keyEnv") ?? void 0,
19850
+ keyEnv: readString16(body, "key_env") ?? readString16(body, "keyEnv") ?? void 0,
18701
19851
  setDefault: readBoolean3(body.set_default ?? body.setDefault),
18702
- reasoningEffort: readString14(body, "reasoning_effort") ?? readString14(body, "reasoningEffort") ?? void 0
19852
+ reasoningEffort: readString16(body, "reasoning_effort") ?? readString16(body, "reasoningEffort") ?? void 0
18703
19853
  };
18704
19854
  }
18705
19855
  function readModelDefaultsInput(body) {
18706
19856
  return {
18707
- taskModelId: readString14(body, "task_model_id") ?? readString14(body, "taskModelId") ?? readString14(body, "default_model_id") ?? readString14(body, "defaultModelId") ?? void 0,
18708
- compressionModelId: readString14(body, "compression_model_id") ?? readString14(body, "compressionModelId") ?? void 0
19857
+ taskModelId: readString16(body, "task_model_id") ?? readString16(body, "taskModelId") ?? readString16(body, "default_model_id") ?? readString16(body, "defaultModelId") ?? void 0,
19858
+ compressionModelId: readString16(body, "compression_model_id") ?? readString16(body, "compressionModelId") ?? void 0
18709
19859
  };
18710
19860
  }
18711
19861
  function readModelConfigImportInput(body) {
18712
- const sourceProfileName = readString14(body, "source_profile") ?? readString14(body, "sourceProfile") ?? readString14(body, "source_profile_name") ?? readString14(body, "sourceProfileName");
18713
- const modelId = readString14(body, "model_id") ?? readString14(body, "modelId") ?? readString14(body, "id");
19862
+ const sourceProfileName = readString16(body, "source_profile") ?? readString16(body, "sourceProfile") ?? readString16(body, "source_profile_name") ?? readString16(body, "sourceProfileName");
19863
+ const modelId = readString16(body, "model_id") ?? readString16(body, "modelId") ?? readString16(body, "id");
18714
19864
  if (!sourceProfileName || !modelId) {
18715
19865
  throw new LinkHttpError(
18716
19866
  400,
@@ -18721,9 +19871,9 @@ function readModelConfigImportInput(body) {
18721
19871
  return {
18722
19872
  sourceProfileName,
18723
19873
  modelId,
18724
- provider: readString14(body, "provider") ?? readString14(body, "provider_key") ?? readString14(body, "providerKey") ?? void 0,
18725
- baseUrl: readString14(body, "base_url") ?? readString14(body, "baseUrl") ?? void 0,
18726
- apiMode: readString14(body, "api_mode") ?? readString14(body, "apiMode") ?? void 0,
19874
+ provider: readString16(body, "provider") ?? readString16(body, "provider_key") ?? readString16(body, "providerKey") ?? void 0,
19875
+ baseUrl: readString16(body, "base_url") ?? readString16(body, "baseUrl") ?? void 0,
19876
+ apiMode: readString16(body, "api_mode") ?? readString16(body, "apiMode") ?? void 0,
18727
19877
  setDefault: readBoolean3(body.set_default ?? body.setDefault)
18728
19878
  };
18729
19879
  }
@@ -18808,11 +19958,11 @@ import { EventEmitter as EventEmitter2 } from "events";
18808
19958
  import {
18809
19959
  cp,
18810
19960
  mkdir as mkdir11,
18811
- readFile as readFile13,
19961
+ readFile as readFile14,
18812
19962
  rm as rm6,
18813
- stat as stat13
19963
+ stat as stat14
18814
19964
  } from "fs/promises";
18815
- import path20 from "path";
19965
+ import path21 from "path";
18816
19966
  import YAML3 from "yaml";
18817
19967
  var PROFILE_CREATE_LOG_FILE = "profile-create.log";
18818
19968
  var PROFILE_CREATE_LOG_MAX_FILES = 3;
@@ -19202,7 +20352,7 @@ function copyModelConfig(source, target) {
19202
20352
  copied[key] = cloneJson(source[key]);
19203
20353
  }
19204
20354
  }
19205
- const sourceAuxiliary = toRecord13(source.auxiliary);
20355
+ const sourceAuxiliary = toRecord15(source.auxiliary);
19206
20356
  if (Object.prototype.hasOwnProperty.call(sourceAuxiliary, "compression")) {
19207
20357
  const targetAuxiliary = ensureRecord2(target, "auxiliary");
19208
20358
  targetAuxiliary.compression = cloneJson(sourceAuxiliary.compression);
@@ -19211,12 +20361,12 @@ function copyModelConfig(source, target) {
19211
20361
  return copied;
19212
20362
  }
19213
20363
  function copyToolPermissionsConfig(source, target) {
19214
- const sourcePlatformToolsets = toRecord13(source.platform_toolsets);
20364
+ const sourcePlatformToolsets = toRecord15(source.platform_toolsets);
19215
20365
  if (Object.prototype.hasOwnProperty.call(sourcePlatformToolsets, "api_server")) {
19216
20366
  const targetPlatformToolsets = ensureRecord2(target, "platform_toolsets");
19217
20367
  targetPlatformToolsets.api_server = cloneJson(sourcePlatformToolsets.api_server);
19218
20368
  }
19219
- const sourceStt = toRecord13(source.stt);
20369
+ const sourceStt = toRecord15(source.stt);
19220
20370
  if (Object.prototype.hasOwnProperty.call(sourceStt, "enabled")) {
19221
20371
  const targetStt = ensureRecord2(target, "stt");
19222
20372
  targetStt.enabled = cloneJson(sourceStt.enabled);
@@ -19263,9 +20413,9 @@ function collectEnvKeys(value, keys = /* @__PURE__ */ new Set()) {
19263
20413
  return keys;
19264
20414
  }
19265
20415
  async function writeEnvValues(profileName, values) {
19266
- const envPath = path20.join(resolveHermesProfileDir(profileName), ".env");
19267
- const existingRaw = await readFile13(envPath, "utf8").catch((error) => {
19268
- if (isNodeError15(error, "ENOENT")) {
20416
+ const envPath = path21.join(resolveHermesProfileDir(profileName), ".env");
20417
+ const existingRaw = await readFile14(envPath, "utf8").catch((error) => {
20418
+ if (isNodeError16(error, "ENOENT")) {
19269
20419
  return "";
19270
20420
  }
19271
20421
  throw error;
@@ -19300,8 +20450,8 @@ async function writeEnvValues(profileName, values) {
19300
20450
  await atomicWriteFilePreservingMetadata(envPath, nextRaw);
19301
20451
  }
19302
20452
  async function copySkills(sourceProfile, targetProfile) {
19303
- const sourceSkills = path20.join(resolveHermesProfileDir(sourceProfile), "skills");
19304
- const targetSkills = path20.join(resolveHermesProfileDir(targetProfile), "skills");
20453
+ const sourceSkills = path21.join(resolveHermesProfileDir(sourceProfile), "skills");
20454
+ const targetSkills = path21.join(resolveHermesProfileDir(targetProfile), "skills");
19305
20455
  if (!await pathExists2(sourceSkills)) {
19306
20456
  return;
19307
20457
  }
@@ -19324,16 +20474,16 @@ function copyProperty(source, target, key) {
19324
20474
  }
19325
20475
  }
19326
20476
  async function readYamlConfig(configPath) {
19327
- const existingRaw = await readFile13(configPath, "utf8").catch(
20477
+ const existingRaw = await readFile14(configPath, "utf8").catch(
19328
20478
  (error) => {
19329
- if (isNodeError15(error, "ENOENT")) {
20479
+ if (isNodeError16(error, "ENOENT")) {
19330
20480
  return null;
19331
20481
  }
19332
20482
  throw error;
19333
20483
  }
19334
20484
  );
19335
20485
  return {
19336
- config: toRecord13(existingRaw ? YAML3.parse(existingRaw) : {}),
20486
+ config: toRecord15(existingRaw ? YAML3.parse(existingRaw) : {}),
19337
20487
  existingRaw
19338
20488
  };
19339
20489
  }
@@ -19387,7 +20537,7 @@ async function writeProfileCreationState(paths, state) {
19387
20537
  await writeJsonFile(profileCreationStatePath(paths), state);
19388
20538
  }
19389
20539
  async function readProfileCreationLogLines(paths) {
19390
- const raw = await readFile13(profileCreationLogPath(paths), "utf8").catch(() => "");
20540
+ const raw = await readFile14(profileCreationLogPath(paths), "utf8").catch(() => "");
19391
20541
  if (!raw.trim()) {
19392
20542
  return [];
19393
20543
  }
@@ -19396,10 +20546,10 @@ async function readProfileCreationLogLines(paths) {
19396
20546
  );
19397
20547
  }
19398
20548
  function profileCreationStatePath(paths) {
19399
- return path20.join(paths.runDir, "profile-create-state.json");
20549
+ return path21.join(paths.runDir, "profile-create-state.json");
19400
20550
  }
19401
20551
  function profileCreationLogPath(paths) {
19402
- return path20.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
20552
+ return path21.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
19403
20553
  }
19404
20554
  async function clearProfileCreationLogFiles(paths) {
19405
20555
  const primary = profileCreationLogPath(paths);
@@ -19412,8 +20562,8 @@ async function clearProfileCreationLogFiles(paths) {
19412
20562
  ]);
19413
20563
  }
19414
20564
  async function pathExists2(targetPath) {
19415
- return await stat13(targetPath).then(() => true).catch((error) => {
19416
- if (isNodeError15(error, "ENOENT")) {
20565
+ return await stat14(targetPath).then(() => true).catch((error) => {
20566
+ if (isNodeError16(error, "ENOENT")) {
19417
20567
  return false;
19418
20568
  }
19419
20569
  throw error;
@@ -19445,7 +20595,7 @@ function ensureRecord2(target, key) {
19445
20595
  target[key] = next;
19446
20596
  return next;
19447
20597
  }
19448
- function toRecord13(value) {
20598
+ function toRecord15(value) {
19449
20599
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
19450
20600
  }
19451
20601
  function cloneJson(value) {
@@ -19460,7 +20610,7 @@ function formatEnvValue2(value) {
19460
20610
  function escapeRegExp3(value) {
19461
20611
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
19462
20612
  }
19463
- function isNodeError15(error, code) {
20613
+ function isNodeError16(error, code) {
19464
20614
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
19465
20615
  }
19466
20616
 
@@ -19545,16 +20695,16 @@ function readProfilePermissionsInput(body) {
19545
20695
  const approvals = readOptionalObject(body, "approvals");
19546
20696
  if (approvals) {
19547
20697
  input.approvals = {
19548
- mode: readString14(approvals, "mode") ?? readString14(approvals, "approval_mode") ?? readString14(approvals, "approvalMode") ?? void 0,
20698
+ mode: readString16(approvals, "mode") ?? readString16(approvals, "approval_mode") ?? readString16(approvals, "approvalMode") ?? void 0,
19549
20699
  timeout: readPositiveInteger2(approvals.timeout),
19550
- cronMode: readString14(approvals, "cron_mode") ?? readString14(approvals, "cronMode") ?? void 0
20700
+ cronMode: readString16(approvals, "cron_mode") ?? readString16(approvals, "cronMode") ?? void 0
19551
20701
  };
19552
20702
  }
19553
20703
  const terminal = readOptionalObject(body, "terminal");
19554
20704
  if (terminal) {
19555
20705
  input.terminal = {
19556
- backend: readString14(terminal, "backend") ?? void 0,
19557
- cwd: readString14(terminal, "cwd") ?? void 0,
20706
+ backend: readString16(terminal, "backend") ?? void 0,
20707
+ cwd: readString16(terminal, "cwd") ?? void 0,
19558
20708
  containerCpu: readPositiveInteger2(
19559
20709
  terminal.container_cpu ?? terminal.containerCpu
19560
20710
  ),
@@ -19670,10 +20820,10 @@ function toProfileToolConfigHttpError(error) {
19670
20820
  import {
19671
20821
  access as access3,
19672
20822
  readdir as readdir10,
19673
- readFile as readFile14,
19674
- stat as stat14
20823
+ readFile as readFile15,
20824
+ stat as stat15
19675
20825
  } from "fs/promises";
19676
- import path21 from "path";
20826
+ import path22 from "path";
19677
20827
  import YAML4 from "yaml";
19678
20828
  var ENTRY_DELIMITER = "\n\xA7\n";
19679
20829
  var DEFAULT_MEMORY_LIMIT = 2200;
@@ -19861,9 +21011,9 @@ async function testHindsightProviderSettings(profileName, patch) {
19861
21011
  const mode = normalizeHindsightMode(
19862
21012
  patch.mode ?? config.mode ?? env.HINDSIGHT_MODE
19863
21013
  );
19864
- const apiUrl = readString15(patch.apiUrl) ?? readString15(config.api_url) ?? env.HINDSIGHT_API_URL ?? (mode === "cloud" ? HINDSIGHT_DEFAULT_API_URL : HINDSIGHT_DEFAULT_LOCAL_URL);
19865
- const bankId = readString15(patch.bankId) ?? readString15(config.bank_id) ?? "hermes";
19866
- const apiKey = readString15(patch.apiKey) ?? env.HINDSIGHT_API_KEY ?? readString15(config.apiKey) ?? readString15(config.api_key);
21014
+ const apiUrl = readString17(patch.apiUrl) ?? readString17(config.api_url) ?? env.HINDSIGHT_API_URL ?? (mode === "cloud" ? HINDSIGHT_DEFAULT_API_URL : HINDSIGHT_DEFAULT_LOCAL_URL);
21015
+ const bankId = readString17(patch.bankId) ?? readString17(config.bank_id) ?? "hermes";
21016
+ const apiKey = readString17(patch.apiKey) ?? env.HINDSIGHT_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key);
19867
21017
  const baseUrl = normalizeHttpUrl(apiUrl);
19868
21018
  if (!baseUrl) {
19869
21019
  return {
@@ -19995,7 +21145,7 @@ async function saveProviderSettings(profileName, provider, patch) {
19995
21145
  });
19996
21146
  await patchJsonProviderConfig(
19997
21147
  profileName,
19998
- path21.join("hindsight", "config.json"),
21148
+ path22.join("hindsight", "config.json"),
19999
21149
  {
20000
21150
  mode: patch.mode,
20001
21151
  api_url: patch.apiUrl,
@@ -20052,7 +21202,7 @@ async function patchCustomProviderConfig(profileName, provider, patch) {
20052
21202
  "\u81EA\u5B9A\u4E49 memory provider \u914D\u7F6E\u5FC5\u987B\u662F\u6709\u6548\u7684 JSON object\u3002"
20053
21203
  );
20054
21204
  }
20055
- const config = toRecord14(parsed);
21205
+ const config = toRecord16(parsed);
20056
21206
  if (Object.keys(config).length === 0 && parsed !== null) {
20057
21207
  throw new HermesMemoryError(
20058
21208
  "memory_provider_config_invalid",
@@ -20143,17 +21293,17 @@ function normalizeCustomProviderId(provider) {
20143
21293
  }
20144
21294
  async function patchHermesMemoryProvider(profileName, provider) {
20145
21295
  const configPath = resolveHermesConfigPath(profileName);
20146
- const existingRaw = await readFile14(configPath, "utf8").catch(
21296
+ const existingRaw = await readFile15(configPath, "utf8").catch(
20147
21297
  (error) => {
20148
- if (isNodeError16(error, "ENOENT")) {
21298
+ if (isNodeError17(error, "ENOENT")) {
20149
21299
  return null;
20150
21300
  }
20151
21301
  throw error;
20152
21302
  }
20153
21303
  );
20154
21304
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
20155
- const config = toRecord14(document.toJSON());
20156
- const memory = toRecord14(config.memory);
21305
+ const config = toRecord16(document.toJSON());
21306
+ const memory = toRecord16(config.memory);
20157
21307
  memory.provider = provider === "built-in" ? "" : provider;
20158
21308
  config.memory = memory;
20159
21309
  const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null;
@@ -20166,13 +21316,13 @@ async function patchHermesMemoryProvider(profileName, provider) {
20166
21316
  await atomicWriteFilePreservingMetadata(configPath, document.toString());
20167
21317
  }
20168
21318
  function resolveMemoryDir(profileName) {
20169
- return path21.join(resolveHermesProfileDir(profileName), "memories");
21319
+ return path22.join(resolveHermesProfileDir(profileName), "memories");
20170
21320
  }
20171
21321
  async function readMemoryStore(profileName, target, limits) {
20172
21322
  const filePath = memoryFilePath(profileName, target);
20173
21323
  const entries = await readMemoryEntries(filePath);
20174
- const fileStat = await stat14(filePath).catch((error) => {
20175
- if (isNodeError16(error, "ENOENT")) {
21324
+ const fileStat = await stat15(filePath).catch((error) => {
21325
+ if (isNodeError17(error, "ENOENT")) {
20176
21326
  return null;
20177
21327
  }
20178
21328
  throw error;
@@ -20200,8 +21350,8 @@ async function readMemoryStore(profileName, target, limits) {
20200
21350
  };
20201
21351
  }
20202
21352
  async function readMemoryEntries(filePath) {
20203
- const raw = await readFile14(filePath, "utf8").catch((error) => {
20204
- if (isNodeError16(error, "ENOENT")) {
21353
+ const raw = await readFile15(filePath, "utf8").catch((error) => {
21354
+ if (isNodeError17(error, "ENOENT")) {
20205
21355
  return "";
20206
21356
  }
20207
21357
  throw error;
@@ -20227,7 +21377,7 @@ async function writeMemoryEntries(profileName, target, entries) {
20227
21377
  );
20228
21378
  }
20229
21379
  function memoryFilePath(profileName, target) {
20230
- return path21.join(
21380
+ return path22.join(
20231
21381
  resolveMemoryDir(profileName),
20232
21382
  target === "user" ? "USER.md" : "MEMORY.md"
20233
21383
  );
@@ -20287,7 +21437,7 @@ async function readCustomProviderSetupSummary(profileName) {
20287
21437
  configurable: true,
20288
21438
  configured: true,
20289
21439
  configurationIssue: null,
20290
- providerConfigPath: path21.join(
21440
+ providerConfigPath: path22.join(
20291
21441
  resolveHermesProfileDir(profileName),
20292
21442
  "<provider>.json"
20293
21443
  ),
@@ -20365,7 +21515,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
20365
21515
  const config2 = await readJsonObject(
20366
21516
  memoryProviderConfigPath(profileName, "honcho") ?? ""
20367
21517
  );
20368
- return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString15(config2.apiKey)) || isConfiguredEnvValue(readString15(config2.api_key)) || isConfiguredEnvValue(readString15(config2.baseUrl)) ? { configured: true, issue: null } : {
21518
+ return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString17(config2.apiKey)) || isConfiguredEnvValue(readString17(config2.api_key)) || isConfiguredEnvValue(readString17(config2.baseUrl)) ? { configured: true, issue: null } : {
20369
21519
  configured: false,
20370
21520
  issue: "Honcho \u9700\u8981\u5148\u586B\u5199 API Key\uFF0C\u6216\u5728 honcho.json \u914D\u7F6E self-hosted baseUrl\u3002"
20371
21521
  };
@@ -20374,7 +21524,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
20374
21524
  const config2 = await readJsonObject(
20375
21525
  memoryProviderConfigPath(profileName, "mem0") ?? ""
20376
21526
  );
20377
- return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString15(config2.api_key)) ? { configured: true, issue: null } : {
21527
+ return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString17(config2.api_key)) ? { configured: true, issue: null } : {
20378
21528
  configured: false,
20379
21529
  issue: "Mem0 \u9700\u8981\u5148\u5728\u672C\u9875\u586B\u5199 API Key\uFF0CLink \u4F1A\u5199\u5165\u5F53\u524D Profile \u7684 .env\u3002"
20380
21530
  };
@@ -20416,7 +21566,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
20416
21566
  memoryProviderConfigPath(profileName, provider) ?? ""
20417
21567
  );
20418
21568
  const mode = normalizeHindsightMode(config.mode ?? env.HINDSIGHT_MODE);
20419
- const apiKey = readString15(config.apiKey) ?? readString15(config.api_key) ?? env.HINDSIGHT_API_KEY;
21569
+ const apiKey = readString17(config.apiKey) ?? readString17(config.api_key) ?? env.HINDSIGHT_API_KEY;
20420
21570
  if (mode === "cloud") {
20421
21571
  return isConfiguredEnvValue(apiKey) ? { configured: true, issue: null } : {
20422
21572
  configured: false,
@@ -20424,15 +21574,15 @@ async function readProviderConfigurationStatus(profileName, provider) {
20424
21574
  };
20425
21575
  }
20426
21576
  if (mode === "local_external") {
20427
- const apiUrl = readString15(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
21577
+ const apiUrl = readString17(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
20428
21578
  return isConfiguredEnvValue(apiUrl) ? { configured: true, issue: null } : {
20429
21579
  configured: false,
20430
21580
  issue: "Hindsight local_external \u9700\u8981\u914D\u7F6E\u53EF\u8BBF\u95EE\u7684 API URL\u3002"
20431
21581
  };
20432
21582
  }
20433
21583
  if (mode === "local_embedded") {
20434
- const llmProvider = readString15(config.llm_provider) ?? "openai";
20435
- const llmModel = readString15(config.llm_model);
21584
+ const llmProvider = readString17(config.llm_provider) ?? "openai";
21585
+ const llmModel = readString17(config.llm_model);
20436
21586
  if (!llmModel) {
20437
21587
  return {
20438
21588
  configured: false,
@@ -20440,7 +21590,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
20440
21590
  };
20441
21591
  }
20442
21592
  if (llmProvider === "openai_compatible" && !isConfiguredEnvValue(
20443
- readString15(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
21593
+ readString17(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
20444
21594
  )) {
20445
21595
  return {
20446
21596
  configured: false,
@@ -20448,7 +21598,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
20448
21598
  };
20449
21599
  }
20450
21600
  if (!["ollama", "lmstudio", "openai_compatible"].includes(llmProvider) && !isConfiguredEnvValue(
20451
- readString15(config.llmApiKey) ?? readString15(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
21601
+ readString17(config.llmApiKey) ?? readString17(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
20452
21602
  )) {
20453
21603
  return {
20454
21604
  configured: false,
@@ -20504,8 +21654,8 @@ async function readProviderSettings(profileName, provider) {
20504
21654
  secretSetting(
20505
21655
  "apiKey",
20506
21656
  "API Key",
20507
- env.HONCHO_API_KEY ?? readString15(config.apiKey) ?? readString15(config.api_key),
20508
- isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString15(config.apiKey)) || isConfiguredEnvValue(readString15(config.api_key))
21657
+ env.HONCHO_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
21658
+ isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
20509
21659
  ),
20510
21660
  stringSetting("workspace", "Workspace", config.workspace ?? "hermes"),
20511
21661
  stringSetting("peerName", "\u7528\u6237 Peer", config.peerName ?? ""),
@@ -20547,8 +21697,8 @@ async function readProviderSettings(profileName, provider) {
20547
21697
  secretSetting(
20548
21698
  "apiKey",
20549
21699
  "API Key",
20550
- env.MEM0_API_KEY ?? readString15(config.apiKey) ?? readString15(config.api_key),
20551
- isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString15(config.apiKey)) || isConfiguredEnvValue(readString15(config.api_key))
21700
+ env.MEM0_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
21701
+ isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
20552
21702
  ),
20553
21703
  stringSetting("userId", "User ID", config.user_id ?? "hermes-user"),
20554
21704
  stringSetting("agentId", "Agent ID", config.agent_id ?? "hermes"),
@@ -20616,8 +21766,8 @@ async function readProviderSettings(profileName, provider) {
20616
21766
  memoryProviderConfigPath(profileName, provider) ?? ""
20617
21767
  );
20618
21768
  const env = await readHermesMemoryEnv(profileName);
20619
- const banks = toRecord14(config.banks);
20620
- const hermesBank = toRecord14(banks.hermes);
21769
+ const banks = toRecord16(config.banks);
21770
+ const hermesBank = toRecord16(banks.hermes);
20621
21771
  const mode = normalizeHindsightMode(config.mode);
20622
21772
  return [
20623
21773
  selectSetting("mode", "\u8FDE\u63A5\u6A21\u5F0F", mode, [
@@ -20633,8 +21783,8 @@ async function readProviderSettings(profileName, provider) {
20633
21783
  secretSetting(
20634
21784
  "apiKey",
20635
21785
  "Hindsight API Key",
20636
- env.HINDSIGHT_API_KEY ?? readString15(config.apiKey) ?? readString15(config.api_key),
20637
- isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(readString15(config.apiKey)) || isConfiguredEnvValue(readString15(config.api_key))
21786
+ env.HINDSIGHT_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
21787
+ isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
20638
21788
  ),
20639
21789
  stringSetting(
20640
21790
  "bankId",
@@ -20656,8 +21806,8 @@ async function readProviderSettings(profileName, provider) {
20656
21806
  secretSetting(
20657
21807
  "llmApiKey",
20658
21808
  "LLM API Key",
20659
- env.HINDSIGHT_LLM_API_KEY ?? readString15(config.llmApiKey) ?? readString15(config.llm_api_key),
20660
- isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(readString15(config.llmApiKey)) || isConfiguredEnvValue(readString15(config.llm_api_key))
21809
+ env.HINDSIGHT_LLM_API_KEY ?? readString17(config.llmApiKey) ?? readString17(config.llm_api_key),
21810
+ isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(readString17(config.llmApiKey)) || isConfiguredEnvValue(readString17(config.llm_api_key))
20661
21811
  ),
20662
21812
  booleanSetting("autoRecall", "\u81EA\u52A8\u56DE\u5FC6", config.auto_recall ?? true),
20663
21813
  booleanSetting("autoRetain", "\u81EA\u52A8\u6C89\u6DC0", config.auto_retain ?? true),
@@ -20681,7 +21831,7 @@ async function readProviderSettings(profileName, provider) {
20681
21831
  stringSetting(
20682
21832
  "dbPath",
20683
21833
  "SQLite \u6570\u636E\u5E93\u8DEF\u5F84",
20684
- config.db_path ?? path21.join(resolveHermesProfileDir(profileName), "memory_store.db")
21834
+ config.db_path ?? path22.join(resolveHermesProfileDir(profileName), "memory_store.db")
20685
21835
  ),
20686
21836
  booleanSetting("autoExtract", "\u4F1A\u8BDD\u7ED3\u675F\u81EA\u52A8\u62BD\u53D6", config.auto_extract ?? false),
20687
21837
  numberSetting("defaultTrust", "\u9ED8\u8BA4\u4FE1\u4EFB\u5206", config.default_trust ?? 0.5),
@@ -20717,7 +21867,7 @@ async function readProviderSettings(profileName, provider) {
20717
21867
  stringSetting(
20718
21868
  "workingDirectory",
20719
21869
  "\u5DE5\u4F5C\u76EE\u5F55",
20720
- path21.join(resolveHermesProfileDir(profileName), "byterover"),
21870
+ path22.join(resolveHermesProfileDir(profileName), "byterover"),
20721
21871
  false
20722
21872
  )
20723
21873
  ];
@@ -20726,16 +21876,16 @@ async function readProviderSettings(profileName, provider) {
20726
21876
  }
20727
21877
  function memoryProviderConfigPath(profileName, provider) {
20728
21878
  if (provider === "honcho") {
20729
- return path21.join(resolveHermesProfileDir(profileName), "honcho.json");
21879
+ return path22.join(resolveHermesProfileDir(profileName), "honcho.json");
20730
21880
  }
20731
21881
  if (provider === "mem0") {
20732
- return path21.join(resolveHermesProfileDir(profileName), "mem0.json");
21882
+ return path22.join(resolveHermesProfileDir(profileName), "mem0.json");
20733
21883
  }
20734
21884
  if (provider === "supermemory") {
20735
- return path21.join(resolveHermesProfileDir(profileName), "supermemory.json");
21885
+ return path22.join(resolveHermesProfileDir(profileName), "supermemory.json");
20736
21886
  }
20737
21887
  if (provider === "hindsight") {
20738
- return path21.join(
21888
+ return path22.join(
20739
21889
  resolveHermesProfileDir(profileName),
20740
21890
  "hindsight",
20741
21891
  "config.json"
@@ -20744,21 +21894,21 @@ function memoryProviderConfigPath(profileName, provider) {
20744
21894
  return null;
20745
21895
  }
20746
21896
  function customProviderConfigPath(profileName, provider) {
20747
- return path21.join(
21897
+ return path22.join(
20748
21898
  resolveHermesProfileDir(profileName),
20749
21899
  `${normalizeCustomProviderId(provider)}.json`
20750
21900
  );
20751
21901
  }
20752
21902
  function customProviderRegistryPath(profileName) {
20753
- return path21.join(
21903
+ return path22.join(
20754
21904
  resolveHermesProfileDir(profileName),
20755
21905
  CUSTOM_PROVIDER_REGISTRY_FILE
20756
21906
  );
20757
21907
  }
20758
21908
  async function readCustomProviderRegistry(profileName) {
20759
- const raw = await readFile14(customProviderRegistryPath(profileName), "utf8").catch(
21909
+ const raw = await readFile15(customProviderRegistryPath(profileName), "utf8").catch(
20760
21910
  (error) => {
20761
- if (isNodeError16(error, "ENOENT")) {
21911
+ if (isNodeError17(error, "ENOENT")) {
20762
21912
  return "";
20763
21913
  }
20764
21914
  throw error;
@@ -20769,18 +21919,18 @@ async function readCustomProviderRegistry(profileName) {
20769
21919
  }
20770
21920
  try {
20771
21921
  const parsed = JSON.parse(raw);
20772
- const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord14(parsed).providers) ? toRecord14(parsed).providers : [];
21922
+ const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord16(parsed).providers) ? toRecord16(parsed).providers : [];
20773
21923
  return providers.map((item) => {
20774
21924
  if (typeof item === "string") {
20775
21925
  const id2 = normalizeCustomProviderId(item);
20776
21926
  return { id: id2, label: id2, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" };
20777
21927
  }
20778
- const record = toRecord14(item);
20779
- const id = normalizeCustomProviderId(readString15(record.id) ?? "");
21928
+ const record = toRecord16(item);
21929
+ const id = normalizeCustomProviderId(readString17(record.id) ?? "");
20780
21930
  return {
20781
21931
  id,
20782
- label: readString15(record.label) ?? id,
20783
- description: readString15(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
21932
+ label: readString17(record.label) ?? id,
21933
+ description: readString17(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
20784
21934
  };
20785
21935
  }).filter((item) => item.id);
20786
21936
  } catch {
@@ -20802,10 +21952,10 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
20802
21952
  );
20803
21953
  }
20804
21954
  async function discoverUserMemoryProviderDescriptors(profileName) {
20805
- const pluginsDir = path21.join(resolveHermesProfileDir(profileName), "plugins");
21955
+ const pluginsDir = path22.join(resolveHermesProfileDir(profileName), "plugins");
20806
21956
  const entries = await readdir10(pluginsDir, { withFileTypes: true }).catch(
20807
21957
  (error) => {
20808
- if (isNodeError16(error, "ENOENT")) {
21958
+ if (isNodeError17(error, "ENOENT")) {
20809
21959
  return [];
20810
21960
  }
20811
21961
  throw error;
@@ -20822,21 +21972,21 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
20822
21972
  } catch {
20823
21973
  continue;
20824
21974
  }
20825
- const providerDir = path21.join(pluginsDir, entry.name);
21975
+ const providerDir = path22.join(pluginsDir, entry.name);
20826
21976
  if (!await isMemoryProviderPluginDir(providerDir)) {
20827
21977
  continue;
20828
21978
  }
20829
21979
  const meta = await readPluginMetadata(providerDir);
20830
21980
  descriptors.push({
20831
21981
  id: providerId,
20832
- label: readString15(meta.name) ?? providerId,
20833
- description: readString15(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
21982
+ label: readString17(meta.name) ?? providerId,
21983
+ description: readString17(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
20834
21984
  });
20835
21985
  }
20836
21986
  return descriptors;
20837
21987
  }
20838
21988
  async function isUserMemoryProviderInstalled(profileName, provider) {
20839
- const providerDir = path21.join(
21989
+ const providerDir = path22.join(
20840
21990
  resolveHermesProfileDir(profileName),
20841
21991
  "plugins",
20842
21992
  normalizeCustomProviderId(provider)
@@ -20844,9 +21994,9 @@ async function isUserMemoryProviderInstalled(profileName, provider) {
20844
21994
  return isMemoryProviderPluginDir(providerDir);
20845
21995
  }
20846
21996
  async function isMemoryProviderPluginDir(providerDir) {
20847
- const source = await readFile14(path21.join(providerDir, "__init__.py"), "utf8").catch(
21997
+ const source = await readFile15(path22.join(providerDir, "__init__.py"), "utf8").catch(
20848
21998
  (error) => {
20849
- if (isNodeError16(error, "ENOENT")) {
21999
+ if (isNodeError17(error, "ENOENT")) {
20850
22000
  return "";
20851
22001
  }
20852
22002
  throw error;
@@ -20856,22 +22006,22 @@ async function isMemoryProviderPluginDir(providerDir) {
20856
22006
  return sample.includes("register_memory_provider") || sample.includes("MemoryProvider");
20857
22007
  }
20858
22008
  async function readPluginMetadata(providerDir) {
20859
- const raw = await readFile14(path21.join(providerDir, "plugin.yaml"), "utf8").catch(
22009
+ const raw = await readFile15(path22.join(providerDir, "plugin.yaml"), "utf8").catch(
20860
22010
  (error) => {
20861
- if (isNodeError16(error, "ENOENT")) {
22011
+ if (isNodeError17(error, "ENOENT")) {
20862
22012
  return "";
20863
22013
  }
20864
22014
  throw error;
20865
22015
  }
20866
22016
  );
20867
- return raw ? toRecord14(YAML4.parse(raw)) : {};
22017
+ return raw ? toRecord16(YAML4.parse(raw)) : {};
20868
22018
  }
20869
22019
  async function resolveByteRoverCli() {
20870
22020
  const candidates = [
20871
- ...(process.env.PATH ?? "").split(path21.delimiter).filter(Boolean).map((dir) => path21.join(dir, "brv")),
20872
- path21.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
22021
+ ...(process.env.PATH ?? "").split(path22.delimiter).filter(Boolean).map((dir) => path22.join(dir, "brv")),
22022
+ path22.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
20873
22023
  "/usr/local/bin/brv",
20874
- path21.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
22024
+ path22.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
20875
22025
  ].filter(Boolean);
20876
22026
  for (const candidate of candidates) {
20877
22027
  const found = await access3(candidate).then(() => true).catch(() => false);
@@ -20882,32 +22032,32 @@ async function resolveByteRoverCli() {
20882
22032
  return null;
20883
22033
  }
20884
22034
  async function readHolographicProviderConfig(profileName) {
20885
- const raw = await readFile14(resolveHermesConfigPath(profileName), "utf8").catch(
22035
+ const raw = await readFile15(resolveHermesConfigPath(profileName), "utf8").catch(
20886
22036
  (error) => {
20887
- if (isNodeError16(error, "ENOENT")) {
22037
+ if (isNodeError17(error, "ENOENT")) {
20888
22038
  return "";
20889
22039
  }
20890
22040
  throw error;
20891
22041
  }
20892
22042
  );
20893
- const config = raw ? toRecord14(YAML4.parse(raw)) : {};
20894
- const plugins = toRecord14(config.plugins);
20895
- return toRecord14(plugins["hermes-memory-store"]);
22043
+ const config = raw ? toRecord16(YAML4.parse(raw)) : {};
22044
+ const plugins = toRecord16(config.plugins);
22045
+ return toRecord16(plugins["hermes-memory-store"]);
20896
22046
  }
20897
22047
  async function patchHolographicProviderConfig(profileName, patch) {
20898
22048
  const configPath = resolveHermesConfigPath(profileName);
20899
- const existingRaw = await readFile14(configPath, "utf8").catch(
22049
+ const existingRaw = await readFile15(configPath, "utf8").catch(
20900
22050
  (error) => {
20901
- if (isNodeError16(error, "ENOENT")) {
22051
+ if (isNodeError17(error, "ENOENT")) {
20902
22052
  return null;
20903
22053
  }
20904
22054
  throw error;
20905
22055
  }
20906
22056
  );
20907
22057
  const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
20908
- const config = toRecord14(document.toJSON());
20909
- const plugins = toRecord14(config.plugins);
20910
- const memoryStore = toRecord14(plugins["hermes-memory-store"]);
22058
+ const config = toRecord16(document.toJSON());
22059
+ const plugins = toRecord16(config.plugins);
22060
+ const memoryStore = toRecord16(plugins["hermes-memory-store"]);
20911
22061
  for (const [key, value] of Object.entries(patch)) {
20912
22062
  if (value !== void 0) {
20913
22063
  memoryStore[key] = value;
@@ -20932,9 +22082,9 @@ async function patchHermesMemoryEnv(profileName, patch) {
20932
22082
  if (entries.length === 0) {
20933
22083
  return;
20934
22084
  }
20935
- const envPath = path21.join(resolveHermesProfileDir(profileName), ".env");
20936
- const existingRaw = await readFile14(envPath, "utf8").catch((error) => {
20937
- if (isNodeError16(error, "ENOENT")) {
22085
+ const envPath = path22.join(resolveHermesProfileDir(profileName), ".env");
22086
+ const existingRaw = await readFile15(envPath, "utf8").catch((error) => {
22087
+ if (isNodeError17(error, "ENOENT")) {
20938
22088
  return "";
20939
22089
  }
20940
22090
  throw error;
@@ -20992,7 +22142,7 @@ function isMemoryEnvKeyWritable(key) {
20992
22142
  ].includes(key);
20993
22143
  }
20994
22144
  function normalizeHindsightMode(value) {
20995
- const mode = readString15(value) ?? "cloud";
22145
+ const mode = readString17(value) ?? "cloud";
20996
22146
  return mode === "local" ? "local_embedded" : mode;
20997
22147
  }
20998
22148
  function normalizeHttpUrl(value) {
@@ -21055,55 +22205,55 @@ function joinHindsightUrl(baseUrl, pathName) {
21055
22205
  }
21056
22206
  function parseJsonObject2(text) {
21057
22207
  try {
21058
- return toRecord14(JSON.parse(text));
22208
+ return toRecord16(JSON.parse(text));
21059
22209
  } catch {
21060
22210
  return {};
21061
22211
  }
21062
22212
  }
21063
22213
  function readHindsightError(json) {
21064
- const detail = readString15(json.detail) ?? readString15(json.error);
22214
+ const detail = readString17(json.detail) ?? readString17(json.error);
21065
22215
  return detail ? `\uFF1A${detail}` : "";
21066
22216
  }
21067
22217
  function hindsightSemanticIssue(pathName, json) {
21068
22218
  if (pathName === "/health") {
21069
- const status = readString15(json.status);
22219
+ const status = readString17(json.status);
21070
22220
  return status && ["healthy", "ok"].includes(status.toLowerCase()) ? null : `\u5065\u5EB7\u72B6\u6001\u5F02\u5E38\uFF1A${status ?? "unknown"}`;
21071
22221
  }
21072
22222
  return null;
21073
22223
  }
21074
22224
  function summarizeHindsightProbe(pathName, json) {
21075
22225
  if (pathName === "/health") {
21076
- const status = readString15(json.status) ?? "ok";
21077
- const database = readString15(json.database);
22226
+ const status = readString17(json.status) ?? "ok";
22227
+ const database = readString17(json.database);
21078
22228
  return database ? `${status}, database ${database}` : status;
21079
22229
  }
21080
22230
  if (pathName === "/version") {
21081
- const version = readString15(json.api_version);
22231
+ const version = readString17(json.api_version);
21082
22232
  return version ? `API ${version}` : "version endpoint reachable";
21083
22233
  }
21084
- const bankId = readString15(json.bank_id);
22234
+ const bankId = readString17(json.bank_id);
21085
22235
  return bankId ? `bank ${bankId} reachable` : "bank config reachable";
21086
22236
  }
21087
22237
  async function readActiveMemoryProvider(profileName) {
21088
- const raw = await readFile14(
22238
+ const raw = await readFile15(
21089
22239
  resolveHermesConfigPath(profileName),
21090
22240
  "utf8"
21091
22241
  ).catch((error) => {
21092
- if (isNodeError16(error, "ENOENT")) {
22242
+ if (isNodeError17(error, "ENOENT")) {
21093
22243
  return "";
21094
22244
  }
21095
22245
  throw error;
21096
22246
  });
21097
- const config = raw ? toRecord14(YAML4.parse(raw)) : {};
21098
- const memory = toRecord14(config.memory);
21099
- const provider = readString15(memory.provider);
22247
+ const config = raw ? toRecord16(YAML4.parse(raw)) : {};
22248
+ const memory = toRecord16(config.memory);
22249
+ const provider = readString17(memory.provider);
21100
22250
  if (!provider || provider === "built-in" || provider === "builtin" || provider === "built_in") {
21101
22251
  return null;
21102
22252
  }
21103
22253
  return provider;
21104
22254
  }
21105
22255
  async function patchJsonProviderConfig(profileName, relativePath, patch) {
21106
- const configPath = path21.join(
22256
+ const configPath = path22.join(
21107
22257
  resolveHermesProfileDir(profileName),
21108
22258
  relativePath
21109
22259
  );
@@ -21121,18 +22271,18 @@ async function patchJsonProviderConfig(profileName, relativePath, patch) {
21121
22271
  );
21122
22272
  }
21123
22273
  async function readJsonObject(filePath) {
21124
- const raw = await readFile14(filePath, "utf8").catch((error) => {
21125
- if (isNodeError16(error, "ENOENT")) {
22274
+ const raw = await readFile15(filePath, "utf8").catch((error) => {
22275
+ if (isNodeError17(error, "ENOENT")) {
21126
22276
  return "{}";
21127
22277
  }
21128
22278
  throw error;
21129
22279
  });
21130
22280
  try {
21131
- return toRecord14(JSON.parse(raw || "{}"));
22281
+ return toRecord16(JSON.parse(raw || "{}"));
21132
22282
  } catch {
21133
22283
  throw new HermesMemoryError(
21134
22284
  "memory_provider_config_invalid",
21135
- `${path21.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
22285
+ `${path22.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
21136
22286
  );
21137
22287
  }
21138
22288
  }
@@ -21153,7 +22303,7 @@ function stringSetting(key, label, value, editable = true) {
21153
22303
  return {
21154
22304
  key,
21155
22305
  label,
21156
- value: readString15(value) ?? "",
22306
+ value: readString17(value) ?? "",
21157
22307
  editable,
21158
22308
  kind: "string"
21159
22309
  };
@@ -21165,7 +22315,7 @@ function secretSetting(key, label, value, configured) {
21165
22315
  value: "",
21166
22316
  editable: true,
21167
22317
  kind: "secret",
21168
- configured: configured || isConfiguredEnvValue(readString15(value))
22318
+ configured: configured || isConfiguredEnvValue(readString17(value))
21169
22319
  };
21170
22320
  }
21171
22321
  function textSetting(key, label, value, editable = true) {
@@ -21178,21 +22328,21 @@ function textSetting(key, label, value, editable = true) {
21178
22328
  };
21179
22329
  }
21180
22330
  function selectSetting(key, label, value, options, editable = true) {
21181
- const stringValue = readString15(value) ?? options[0] ?? null;
22331
+ const stringValue = readString17(value) ?? options[0] ?? null;
21182
22332
  return { key, label, value: stringValue, editable, kind: "select", options };
21183
22333
  }
21184
22334
  async function readMemoryLimits(profileName) {
21185
- const raw = await readFile14(
22335
+ const raw = await readFile15(
21186
22336
  resolveHermesConfigPath(profileName),
21187
22337
  "utf8"
21188
22338
  ).catch((error) => {
21189
- if (isNodeError16(error, "ENOENT")) {
22339
+ if (isNodeError17(error, "ENOENT")) {
21190
22340
  return "";
21191
22341
  }
21192
22342
  throw error;
21193
22343
  });
21194
- const config = raw ? toRecord14(YAML4.parse(raw)) : {};
21195
- const memory = toRecord14(config.memory);
22344
+ const config = raw ? toRecord16(YAML4.parse(raw)) : {};
22345
+ const memory = toRecord16(config.memory);
21196
22346
  return {
21197
22347
  memory: readPositiveInteger3(memory.memory_char_limit) ?? DEFAULT_MEMORY_LIMIT,
21198
22348
  user: readPositiveInteger3(memory.user_char_limit) ?? DEFAULT_USER_LIMIT
@@ -21248,10 +22398,10 @@ function hashString(value) {
21248
22398
  }
21249
22399
  return hash.toString(16);
21250
22400
  }
21251
- function toRecord14(value) {
22401
+ function toRecord16(value) {
21252
22402
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
21253
22403
  }
21254
- function readString15(value) {
22404
+ function readString17(value) {
21255
22405
  return typeof value === "string" && value.trim() ? value.trim() : null;
21256
22406
  }
21257
22407
  function readPositiveInteger3(value) {
@@ -21279,7 +22429,7 @@ function formatEnvValue3(value) {
21279
22429
  function escapeRegExp4(value) {
21280
22430
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
21281
22431
  }
21282
- function isNodeError16(error, code) {
22432
+ function isNodeError17(error, code) {
21283
22433
  return error instanceof Error && "code" in error && error.code === code;
21284
22434
  }
21285
22435
 
@@ -21410,7 +22560,7 @@ function registerProfileMemoryRoutes(router, options) {
21410
22560
  );
21411
22561
  }
21412
22562
  function readMemoryTarget(body) {
21413
- const raw = readString14(body, "target");
22563
+ const raw = readString16(body, "target");
21414
22564
  if (raw === "memory" || raw === "user") {
21415
22565
  return raw;
21416
22566
  }
@@ -21421,7 +22571,7 @@ function readMemoryTarget(body) {
21421
22571
  );
21422
22572
  }
21423
22573
  function readMemoryResetTarget(body) {
21424
- const raw = readString14(body, "target") ?? "all";
22574
+ const raw = readString16(body, "target") ?? "all";
21425
22575
  if (raw === "all" || raw === "memory" || raw === "user") {
21426
22576
  return raw;
21427
22577
  }
@@ -21432,7 +22582,7 @@ function readMemoryResetTarget(body) {
21432
22582
  );
21433
22583
  }
21434
22584
  function readRequiredMemoryContent(body) {
21435
- const content = readString14(body, "content") ?? readString14(body, "text");
22585
+ const content = readString16(body, "content") ?? readString16(body, "text");
21436
22586
  if (!content) {
21437
22587
  throw new LinkHttpError(
21438
22588
  400,
@@ -21443,7 +22593,7 @@ function readRequiredMemoryContent(body) {
21443
22593
  return content;
21444
22594
  }
21445
22595
  function readRequiredMemoryMatch(body) {
21446
- const oldText = readString14(body, "old_text") ?? readString14(body, "oldText") ?? readString14(body, "match");
22596
+ const oldText = readString16(body, "old_text") ?? readString16(body, "oldText") ?? readString16(body, "match");
21447
22597
  if (!oldText) {
21448
22598
  throw new LinkHttpError(
21449
22599
  400,
@@ -21454,7 +22604,7 @@ function readRequiredMemoryMatch(body) {
21454
22604
  return oldText;
21455
22605
  }
21456
22606
  function readRequiredMemoryProvider(body) {
21457
- const provider = readString14(body, "provider") ?? readString14(body, "provider_id") ?? readString14(body, "providerId");
22607
+ const provider = readString16(body, "provider") ?? readString16(body, "provider_id") ?? readString16(body, "providerId");
21458
22608
  if (!provider) {
21459
22609
  throw new LinkHttpError(
21460
22610
  400,
@@ -21466,7 +22616,7 @@ function readRequiredMemoryProvider(body) {
21466
22616
  }
21467
22617
  function readMemorySettingsPatch(body) {
21468
22618
  const input = {};
21469
- const mode = readString14(body, "mode");
22619
+ const mode = readString16(body, "mode");
21470
22620
  if (mode) {
21471
22621
  input.mode = mode;
21472
22622
  }
@@ -21482,7 +22632,7 @@ function readMemorySettingsPatch(body) {
21482
22632
  if (bankId !== void 0) {
21483
22633
  input.bankId = bankId;
21484
22634
  }
21485
- const llmProvider = readString14(body, "llm_provider") ?? readString14(body, "llmProvider");
22635
+ const llmProvider = readString16(body, "llm_provider") ?? readString16(body, "llmProvider");
21486
22636
  if (llmProvider) {
21487
22637
  input.llmProvider = llmProvider;
21488
22638
  }
@@ -21518,11 +22668,11 @@ function readMemorySettingsPatch(body) {
21518
22668
  if (autoRetain !== void 0) {
21519
22669
  input.autoRetain = autoRetain;
21520
22670
  }
21521
- const memoryMode = readString14(body, "memory_mode") ?? readString14(body, "memoryMode");
22671
+ const memoryMode = readString16(body, "memory_mode") ?? readString16(body, "memoryMode");
21522
22672
  if (memoryMode) {
21523
22673
  input.memoryMode = memoryMode;
21524
22674
  }
21525
- const recallBudget = readString14(body, "recall_budget") ?? readString14(body, "recallBudget");
22675
+ const recallBudget = readString16(body, "recall_budget") ?? readString16(body, "recallBudget");
21526
22676
  if (recallBudget) {
21527
22677
  input.recallBudget = recallBudget;
21528
22678
  }
@@ -21538,11 +22688,11 @@ function readMemorySettingsPatch(body) {
21538
22688
  if (profileFrequency !== void 0) {
21539
22689
  input.profileFrequency = profileFrequency;
21540
22690
  }
21541
- const captureMode = readString14(body, "capture_mode") ?? readString14(body, "captureMode");
22691
+ const captureMode = readString16(body, "capture_mode") ?? readString16(body, "captureMode");
21542
22692
  if (captureMode) {
21543
22693
  input.captureMode = captureMode;
21544
22694
  }
21545
- const searchMode = readString14(body, "search_mode") ?? readString14(body, "searchMode");
22695
+ const searchMode = readString16(body, "search_mode") ?? readString16(body, "searchMode");
21546
22696
  if (searchMode) {
21547
22697
  input.searchMode = searchMode;
21548
22698
  }
@@ -21576,11 +22726,11 @@ function readMemorySettingsPatch(body) {
21576
22726
  if (aiPeer !== void 0) {
21577
22727
  input.aiPeer = aiPeer;
21578
22728
  }
21579
- const recallMode = readString14(body, "recall_mode") ?? readString14(body, "recallMode");
22729
+ const recallMode = readString16(body, "recall_mode") ?? readString16(body, "recallMode");
21580
22730
  if (recallMode) {
21581
22731
  input.recallMode = recallMode;
21582
22732
  }
21583
- const writeFrequency = readString14(body, "write_frequency") ?? readString14(body, "writeFrequency");
22733
+ const writeFrequency = readString16(body, "write_frequency") ?? readString16(body, "writeFrequency");
21584
22734
  if (writeFrequency) {
21585
22735
  input.writeFrequency = writeFrequency;
21586
22736
  }
@@ -21588,7 +22738,7 @@ function readMemorySettingsPatch(body) {
21588
22738
  if (saveMessages !== void 0) {
21589
22739
  input.saveMessages = saveMessages;
21590
22740
  }
21591
- const sessionStrategy = readString14(body, "session_strategy") ?? readString14(body, "sessionStrategy");
22741
+ const sessionStrategy = readString16(body, "session_strategy") ?? readString16(body, "sessionStrategy");
21592
22742
  if (sessionStrategy) {
21593
22743
  input.sessionStrategy = sessionStrategy;
21594
22744
  }
@@ -21720,8 +22870,8 @@ function toMemoryHttpError(error) {
21720
22870
  }
21721
22871
 
21722
22872
  // src/hermes/skills.ts
21723
- import { readFile as readFile15, readdir as readdir11 } from "fs/promises";
21724
- import path22 from "path";
22873
+ import { readFile as readFile16, readdir as readdir11 } from "fs/promises";
22874
+ import path23 from "path";
21725
22875
  import YAML5 from "yaml";
21726
22876
  var HermesSkillNotFoundError = class extends Error {
21727
22877
  constructor(skillName) {
@@ -21735,7 +22885,7 @@ var EXCLUDED_SKILL_DIRS = /* @__PURE__ */ new Set([".git", ".github", ".hub"]);
21735
22885
  async function listHermesProfileSkills(profileName, paths = resolveRuntimePaths()) {
21736
22886
  const profile = await readExistingProfile(profileName, paths);
21737
22887
  const profileDir = resolveHermesProfileDir(profile.name);
21738
- const skillsRoot = path22.join(profileDir, "skills");
22888
+ const skillsRoot = path23.join(profileDir, "skills");
21739
22889
  const [skillFiles, disabled, provenance] = await Promise.all([
21740
22890
  findSkillFiles(skillsRoot),
21741
22891
  readDisabledSkillNames(resolveHermesConfigPath(profile.name)),
@@ -21814,7 +22964,7 @@ async function findSkillFiles(root) {
21814
22964
  async function collectSkillFiles(directory, results) {
21815
22965
  const entries = await readdir11(directory, { withFileTypes: true }).catch(
21816
22966
  (error) => {
21817
- if (isNodeError17(error, "ENOENT")) {
22967
+ if (isNodeError18(error, "ENOENT")) {
21818
22968
  return [];
21819
22969
  }
21820
22970
  throw error;
@@ -21826,7 +22976,7 @@ async function collectSkillFiles(directory, results) {
21826
22976
  if (EXCLUDED_SKILL_DIRS.has(entry.name)) {
21827
22977
  continue;
21828
22978
  }
21829
- const entryPath = path22.join(directory, entry.name);
22979
+ const entryPath = path23.join(directory, entry.name);
21830
22980
  if (entry.isDirectory()) {
21831
22981
  await collectSkillFiles(entryPath, results);
21832
22982
  continue;
@@ -21837,9 +22987,9 @@ async function collectSkillFiles(directory, results) {
21837
22987
  }
21838
22988
  }
21839
22989
  async function readSkillMetadata(input) {
21840
- const raw = await readFile15(input.skillFile, "utf8").catch(
22990
+ const raw = await readFile16(input.skillFile, "utf8").catch(
21841
22991
  (error) => {
21842
- if (isNodeError17(error, "ENOENT") || isNodeError17(error, "EACCES")) {
22992
+ if (isNodeError18(error, "ENOENT") || isNodeError18(error, "EACCES")) {
21843
22993
  return null;
21844
22994
  }
21845
22995
  throw error;
@@ -21848,16 +22998,16 @@ async function readSkillMetadata(input) {
21848
22998
  if (raw === null) {
21849
22999
  return null;
21850
23000
  }
21851
- const skillDir = path22.dirname(input.skillFile);
23001
+ const skillDir = path23.dirname(input.skillFile);
21852
23002
  const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
21853
23003
  const name = normalizeSkillName(
21854
- readString16(frontmatter.name) ?? path22.basename(skillDir)
23004
+ readString18(frontmatter.name) ?? path23.basename(skillDir)
21855
23005
  );
21856
23006
  if (!name) {
21857
23007
  return null;
21858
23008
  }
21859
23009
  const description = normalizeDescription(
21860
- readString16(frontmatter.description) ?? firstBodyDescription(body)
23010
+ readString18(frontmatter.description) ?? firstBodyDescription(body)
21861
23011
  );
21862
23012
  const provenance = input.provenance.get(name) ?? {
21863
23013
  source: "local",
@@ -21870,7 +23020,7 @@ async function readSkillMetadata(input) {
21870
23020
  enabled: !input.disabled.has(name),
21871
23021
  source: provenance.source,
21872
23022
  trust: provenance.trust,
21873
- relativePath: path22.relative(input.skillsRoot, skillDir)
23023
+ relativePath: path23.relative(input.skillsRoot, skillDir)
21874
23024
  };
21875
23025
  }
21876
23026
  function parseSkillDocument(raw) {
@@ -21883,7 +23033,7 @@ function parseSkillDocument(raw) {
21883
23033
  }
21884
23034
  try {
21885
23035
  return {
21886
- frontmatter: toRecord15(YAML5.parse(match[1] ?? "")),
23036
+ frontmatter: toRecord17(YAML5.parse(match[1] ?? "")),
21887
23037
  body: content.slice(match[0].length)
21888
23038
  };
21889
23039
  } catch {
@@ -21891,8 +23041,8 @@ function parseSkillDocument(raw) {
21891
23041
  }
21892
23042
  }
21893
23043
  function categoryFromPath(skillsRoot, skillFile) {
21894
- const relative = path22.relative(skillsRoot, skillFile);
21895
- const parts = relative.split(path22.sep).filter(Boolean);
23044
+ const relative = path23.relative(skillsRoot, skillFile);
23045
+ const parts = relative.split(path23.sep).filter(Boolean);
21896
23046
  return parts.length >= 3 ? parts[0] : null;
21897
23047
  }
21898
23048
  function firstBodyDescription(body) {
@@ -21915,8 +23065,8 @@ function normalizeDescription(value) {
21915
23065
  return `${description.slice(0, MAX_DESCRIPTION_LENGTH - 3)}...`;
21916
23066
  }
21917
23067
  async function readDisabledSkillNames(configPath) {
21918
- const raw = await readFile15(configPath, "utf8").catch((error) => {
21919
- if (isNodeError17(error, "ENOENT")) {
23068
+ const raw = await readFile16(configPath, "utf8").catch((error) => {
23069
+ if (isNodeError18(error, "ENOENT")) {
21920
23070
  return "";
21921
23071
  }
21922
23072
  throw error;
@@ -21924,8 +23074,8 @@ async function readDisabledSkillNames(configPath) {
21924
23074
  if (!raw.trim()) {
21925
23075
  return /* @__PURE__ */ new Set();
21926
23076
  }
21927
- const config = toRecord15(YAML5.parse(raw));
21928
- const skills = toRecord15(config.skills);
23077
+ const config = toRecord17(YAML5.parse(raw));
23078
+ const skills = toRecord17(config.skills);
21929
23079
  return new Set(readStringList3(skills.disabled));
21930
23080
  }
21931
23081
  async function readSkillProvenance(root) {
@@ -21939,9 +23089,9 @@ async function readSkillProvenance(root) {
21939
23089
  return provenance;
21940
23090
  }
21941
23091
  async function readBundledSkillNames(root) {
21942
- const raw = await readFile15(path22.join(root, ".bundled_manifest"), "utf8").catch(
23092
+ const raw = await readFile16(path23.join(root, ".bundled_manifest"), "utf8").catch(
21943
23093
  (error) => {
21944
- if (isNodeError17(error, "ENOENT")) {
23094
+ if (isNodeError18(error, "ENOENT")) {
21945
23095
  return "";
21946
23096
  }
21947
23097
  throw error;
@@ -21962,9 +23112,9 @@ async function readBundledSkillNames(root) {
21962
23112
  return names;
21963
23113
  }
21964
23114
  async function readHubInstalledSkills(root) {
21965
- const raw = await readFile15(path22.join(root, ".hub", "lock.json"), "utf8").catch(
23115
+ const raw = await readFile16(path23.join(root, ".hub", "lock.json"), "utf8").catch(
21966
23116
  (error) => {
21967
- if (isNodeError17(error, "ENOENT")) {
23117
+ if (isNodeError18(error, "ENOENT")) {
21968
23118
  return "";
21969
23119
  }
21970
23120
  throw error;
@@ -21975,17 +23125,17 @@ async function readHubInstalledSkills(root) {
21975
23125
  }
21976
23126
  let lock;
21977
23127
  try {
21978
- lock = toRecord15(JSON.parse(raw));
23128
+ lock = toRecord17(JSON.parse(raw));
21979
23129
  } catch {
21980
23130
  return /* @__PURE__ */ new Map();
21981
23131
  }
21982
- const installed = toRecord15(lock.installed);
23132
+ const installed = toRecord17(lock.installed);
21983
23133
  const result = /* @__PURE__ */ new Map();
21984
23134
  for (const [name, rawEntry] of Object.entries(installed)) {
21985
- const entry = toRecord15(rawEntry);
23135
+ const entry = toRecord17(rawEntry);
21986
23136
  result.set(normalizeSkillName(name), {
21987
- source: readString16(entry.source) ?? "hub",
21988
- trust: readString16(entry.trust_level) ?? null
23137
+ source: readString18(entry.source) ?? "hub",
23138
+ trust: readString18(entry.trust_level) ?? null
21989
23139
  });
21990
23140
  }
21991
23141
  return result;
@@ -22034,9 +23184,9 @@ function compareCategoryNames(left, right) {
22034
23184
  return left.localeCompare(right);
22035
23185
  }
22036
23186
  async function readHermesConfigDocument2(configPath) {
22037
- const existingRaw = await readFile15(configPath, "utf8").catch(
23187
+ const existingRaw = await readFile16(configPath, "utf8").catch(
22038
23188
  (error) => {
22039
- if (isNodeError17(error, "ENOENT")) {
23189
+ if (isNodeError18(error, "ENOENT")) {
22040
23190
  return null;
22041
23191
  }
22042
23192
  throw error;
@@ -22045,7 +23195,7 @@ async function readHermesConfigDocument2(configPath) {
22045
23195
  const document = existingRaw ? YAML5.parseDocument(existingRaw) : new YAML5.Document({});
22046
23196
  return {
22047
23197
  document,
22048
- config: toRecord15(document.toJSON()),
23198
+ config: toRecord17(document.toJSON()),
22049
23199
  existingRaw
22050
23200
  };
22051
23201
  }
@@ -22069,21 +23219,21 @@ function readStringList3(value) {
22069
23219
  }
22070
23220
  return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
22071
23221
  }
22072
- function readString16(value) {
23222
+ function readString18(value) {
22073
23223
  return typeof value === "string" && value.trim() ? value.trim() : null;
22074
23224
  }
22075
- function toRecord15(value) {
23225
+ function toRecord17(value) {
22076
23226
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
22077
23227
  }
22078
23228
  function ensureRecord3(target, key) {
22079
- const current = toRecord15(target[key]);
23229
+ const current = toRecord17(target[key]);
22080
23230
  if (current === target[key]) {
22081
23231
  return current;
22082
23232
  }
22083
23233
  target[key] = current;
22084
23234
  return current;
22085
23235
  }
22086
- function isNodeError17(error, code) {
23236
+ function isNodeError18(error, code) {
22087
23237
  return typeof error === "object" && error !== null && "code" in error && error.code === code;
22088
23238
  }
22089
23239
 
@@ -22382,7 +23532,7 @@ function registerRunRoutes(router, options) {
22382
23532
  router.post("/api/v1/runs", async (ctx) => {
22383
23533
  await authenticateRequest(ctx, paths);
22384
23534
  const body = await readJsonBody(ctx.req);
22385
- const input = readString14(body, "input");
23535
+ const input = readString16(body, "input");
22386
23536
  if (!input) {
22387
23537
  throw new LinkHttpError(400, "run_input_required", "input is required");
22388
23538
  }
@@ -22390,12 +23540,12 @@ function registerRunRoutes(router, options) {
22390
23540
  ctx.body = await createHermesRun(
22391
23541
  {
22392
23542
  input,
22393
- instructions: readString14(body, "instructions") ?? void 0,
23543
+ instructions: readString16(body, "instructions") ?? void 0,
22394
23544
  conversation_history: readConversationHistory(
22395
23545
  body.conversation_history ?? body.conversationHistory
22396
23546
  ),
22397
- session_id: readString14(body, "session_id") ?? readString14(body, "sessionId") ?? void 0,
22398
- session_key: readString14(body, "session_key") ?? readString14(body, "sessionKey") ?? void 0
23547
+ session_id: readString16(body, "session_id") ?? readString16(body, "sessionId") ?? void 0,
23548
+ session_key: readString16(body, "session_key") ?? readString16(body, "sessionKey") ?? void 0
22399
23549
  },
22400
23550
  { logger, profileName: readOptionalProfileName(body) }
22401
23551
  );
@@ -22566,8 +23716,8 @@ function readModelList(payload) {
22566
23716
  // src/hermes/updates.ts
22567
23717
  import { EventEmitter as EventEmitter3 } from "events";
22568
23718
  import { spawn as spawn3 } from "child_process";
22569
- import { mkdir as mkdir12, readFile as readFile16, rm as rm7 } from "fs/promises";
22570
- import path23 from "path";
23719
+ import { mkdir as mkdir12, readFile as readFile17, rm as rm7 } from "fs/promises";
23720
+ import path24 from "path";
22571
23721
  var SERVER_HERMES_RELEASES_LATEST_PATH = "/api/v1/hermes-agent/releases/latest";
22572
23722
  var RELEASE_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
22573
23723
  var RELEASE_FETCH_TIMEOUT_MS = 5e3;
@@ -22800,24 +23950,24 @@ async function readRemoteRelease(options, now) {
22800
23950
  }
22801
23951
  }
22802
23952
  function normalizeServerReleaseSnapshot(payload) {
22803
- const snapshot = toRecord16(payload);
23953
+ const snapshot = toRecord18(payload);
22804
23954
  const remote = toNullableRecord(snapshot.remote);
22805
23955
  return {
22806
23956
  remote: remote ? normalizeServerRelease(remote) : null,
22807
- cacheState: readString17(snapshot, "cache_state") ?? readString17(snapshot, "cacheState"),
22808
- issue: readString17(snapshot, "issue")
23957
+ cacheState: readString19(snapshot, "cache_state") ?? readString19(snapshot, "cacheState"),
23958
+ issue: readString19(snapshot, "issue")
22809
23959
  };
22810
23960
  }
22811
23961
  function normalizeServerRelease(payload) {
22812
- const tag = readString17(payload, "tag");
22813
- const name = readString17(payload, "name");
23962
+ const tag = readString19(payload, "tag");
23963
+ const name = readString19(payload, "name");
22814
23964
  return {
22815
- version: readString17(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
23965
+ version: readString19(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
22816
23966
  tag,
22817
23967
  name,
22818
- releaseUrl: readString17(payload, "releaseUrl") ?? readString17(payload, "release_url"),
22819
- publishedAt: readString17(payload, "publishedAt") ?? readString17(payload, "published_at"),
22820
- fetchedAt: readString17(payload, "fetchedAt") ?? readString17(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
23968
+ releaseUrl: readString19(payload, "releaseUrl") ?? readString19(payload, "release_url"),
23969
+ publishedAt: readString19(payload, "publishedAt") ?? readString19(payload, "published_at"),
23970
+ fetchedAt: readString19(payload, "fetchedAt") ?? readString19(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
22821
23971
  };
22822
23972
  }
22823
23973
  async function readReleaseCache(paths) {
@@ -22836,7 +23986,7 @@ async function writeUpdateState(paths, state) {
22836
23986
  await writeJsonFile(updateStatePath(paths), state);
22837
23987
  }
22838
23988
  async function readUpdateLogLines(paths) {
22839
- const raw = await readFile16(updateLogPath(paths), "utf8").catch(() => "");
23989
+ const raw = await readFile17(updateLogPath(paths), "utf8").catch(() => "");
22840
23990
  if (!raw.trim()) {
22841
23991
  return [];
22842
23992
  }
@@ -22845,13 +23995,13 @@ async function readUpdateLogLines(paths) {
22845
23995
  );
22846
23996
  }
22847
23997
  function releaseCachePath(paths) {
22848
- return path23.join(paths.indexesDir, "hermes-release-check.json");
23998
+ return path24.join(paths.indexesDir, "hermes-release-check.json");
22849
23999
  }
22850
24000
  function updateStatePath(paths) {
22851
- return path23.join(paths.runDir, "hermes-update-state.json");
24001
+ return path24.join(paths.runDir, "hermes-update-state.json");
22852
24002
  }
22853
24003
  function updateLogPath(paths) {
22854
- return path23.join(paths.logsDir, UPDATE_LOG_FILE);
24004
+ return path24.join(paths.logsDir, UPDATE_LOG_FILE);
22855
24005
  }
22856
24006
  async function clearUpdateLogFiles(paths) {
22857
24007
  const primary = updateLogPath(paths);
@@ -22889,7 +24039,7 @@ function compareSemver2(left, right) {
22889
24039
  }
22890
24040
  return 0;
22891
24041
  }
22892
- function toRecord16(value) {
24042
+ function toRecord18(value) {
22893
24043
  return typeof value === "object" && value !== null ? value : {};
22894
24044
  }
22895
24045
  function toNullableRecord(value) {
@@ -22943,7 +24093,7 @@ function isRecentRunningState2(state) {
22943
24093
  const startedAt = Date.parse(state.started_at);
22944
24094
  return Number.isFinite(startedAt) && Date.now() - startedAt < 3e4;
22945
24095
  }
22946
- function readString17(payload, key) {
24096
+ function readString19(payload, key) {
22947
24097
  const value = payload[key];
22948
24098
  return typeof value === "string" && value.trim() ? value.trim() : null;
22949
24099
  }
@@ -22951,13 +24101,13 @@ function readString17(payload, key) {
22951
24101
  // src/link/updates.ts
22952
24102
  import { spawn as spawn5 } from "child_process";
22953
24103
  import { EventEmitter as EventEmitter4 } from "events";
22954
- import { mkdir as mkdir15, readFile as readFile18, rm as rm10 } from "fs/promises";
22955
- import path25 from "path";
24104
+ import { mkdir as mkdir15, readFile as readFile19, rm as rm10 } from "fs/promises";
24105
+ import path26 from "path";
22956
24106
 
22957
24107
  // src/daemon/process.ts
22958
24108
  import { spawn as spawn4 } from "child_process";
22959
- import { mkdir as mkdir14, readFile as readFile17, rm as rm9 } from "fs/promises";
22960
- import path24 from "path";
24109
+ import { mkdir as mkdir14, readFile as readFile18, rm as rm9 } from "fs/promises";
24110
+ import path25 from "path";
22961
24111
 
22962
24112
  // src/daemon/service.ts
22963
24113
  import { createServer } from "http";
@@ -22968,8 +24118,8 @@ import WebSocket from "ws";
22968
24118
 
22969
24119
  // src/relay/stream-policy.ts
22970
24120
  var DEFAULT_RELAY_STREAM_BATCH_POLICY = {
22971
- flushIntervalMs: 50,
22972
- flushBytes: 2 * 1024
24121
+ flushIntervalMs: 1e3,
24122
+ flushBytes: 4 * 1024
22973
24123
  };
22974
24124
  var RELAY_STREAM_POLICY_CONSTRAINTS = {
22975
24125
  flushIntervalMs: {
@@ -24291,7 +25441,7 @@ async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
24291
25441
  await mkdir14(paths.logsDir, { recursive: true, mode: 448 });
24292
25442
  const log = createRotatingTextLogWriter({
24293
25443
  paths,
24294
- fileName: path24.basename(daemonLogFile(paths))
25444
+ fileName: path25.basename(daemonLogFile(paths))
24295
25445
  });
24296
25446
  const scriptPath = currentCliScriptPath();
24297
25447
  const child = spawn4(process.execPath, [scriptPath, "daemon", "--foreground"], {
@@ -24420,7 +25570,7 @@ function currentCliScriptPath() {
24420
25570
  return process.argv[1];
24421
25571
  }
24422
25572
  async function readPid(filePath) {
24423
- const raw = await readFile17(filePath, "utf8").catch(() => null);
25573
+ const raw = await readFile18(filePath, "utf8").catch(() => null);
24424
25574
  if (!raw) {
24425
25575
  return null;
24426
25576
  }
@@ -24849,21 +25999,21 @@ async function readRemoteLinkPolicy(options) {
24849
25999
  }
24850
26000
  }
24851
26001
  function normalizeServerSnapshot(payload) {
24852
- const snapshot = toRecord17(payload);
26002
+ const snapshot = toRecord19(payload);
24853
26003
  const policy = toNullableRecord2(snapshot.policy);
24854
26004
  if (!policy) {
24855
26005
  return {
24856
26006
  remote: null,
24857
- issue: readString18(snapshot, "issue")
26007
+ issue: readString20(snapshot, "issue")
24858
26008
  };
24859
26009
  }
24860
26010
  const release = toNullableRecord2(snapshot.release);
24861
- const currentVersion = readString18(policy, "current_version") ?? readString18(policy, "currentVersion");
24862
- const minSafeVersion = readString18(policy, "min_safe_version") ?? readString18(policy, "minSafeVersion");
26011
+ const currentVersion = readString20(policy, "current_version") ?? readString20(policy, "currentVersion");
26012
+ const minSafeVersion = readString20(policy, "min_safe_version") ?? readString20(policy, "minSafeVersion");
24863
26013
  if (!currentVersion) {
24864
26014
  return {
24865
26015
  remote: null,
24866
- issue: readString18(snapshot, "issue")
26016
+ issue: readString20(snapshot, "issue")
24867
26017
  };
24868
26018
  }
24869
26019
  return {
@@ -24871,10 +26021,10 @@ function normalizeServerSnapshot(payload) {
24871
26021
  current_version: currentVersion,
24872
26022
  min_safe_version: minSafeVersion,
24873
26023
  target_version: currentVersion,
24874
- release_url: release ? readString18(release, "release_url") ?? readString18(release, "releaseUrl") : null,
24875
- published_at: release ? readString18(release, "published_at") ?? readString18(release, "publishedAt") : null
26024
+ release_url: release ? readString20(release, "release_url") ?? readString20(release, "releaseUrl") : null,
26025
+ published_at: release ? readString20(release, "published_at") ?? readString20(release, "publishedAt") : null
24876
26026
  },
24877
- issue: readString18(snapshot, "issue")
26027
+ issue: readString20(snapshot, "issue")
24878
26028
  };
24879
26029
  }
24880
26030
  async function fetchCurrentLinkReleaseFromServer(options, fetcher, channel) {
@@ -25192,7 +26342,7 @@ async function writeUpdateState2(paths, state) {
25192
26342
  await writeJsonFile(updateStatePath2(paths), state);
25193
26343
  }
25194
26344
  async function readUpdateLogLines2(paths) {
25195
- const raw = await readFile18(updateLogPath2(paths), "utf8").catch(() => "");
26345
+ const raw = await readFile19(updateLogPath2(paths), "utf8").catch(() => "");
25196
26346
  if (!raw.trim()) {
25197
26347
  return [];
25198
26348
  }
@@ -25201,10 +26351,10 @@ async function readUpdateLogLines2(paths) {
25201
26351
  );
25202
26352
  }
25203
26353
  function updateStatePath2(paths) {
25204
- return path25.join(paths.runDir, "link-update-state.json");
26354
+ return path26.join(paths.runDir, "link-update-state.json");
25205
26355
  }
25206
26356
  function updateLogPath2(paths) {
25207
- return path25.join(paths.logsDir, UPDATE_LOG_FILE2);
26357
+ return path26.join(paths.logsDir, UPDATE_LOG_FILE2);
25208
26358
  }
25209
26359
  async function clearUpdateLogFiles2(paths) {
25210
26360
  const primary = updateLogPath2(paths);
@@ -25276,19 +26426,19 @@ function isProcessAlive4(pid) {
25276
26426
  return false;
25277
26427
  }
25278
26428
  }
25279
- function toRecord17(value) {
26429
+ function toRecord19(value) {
25280
26430
  return typeof value === "object" && value !== null ? value : {};
25281
26431
  }
25282
26432
  function toNullableRecord2(value) {
25283
26433
  return typeof value === "object" && value !== null ? value : null;
25284
26434
  }
25285
- function readString18(payload, key) {
26435
+ function readString20(payload, key) {
25286
26436
  const value = payload[key];
25287
26437
  return typeof value === "string" && value.trim() ? value.trim() : null;
25288
26438
  }
25289
26439
 
25290
26440
  // src/pairing/pairing.ts
25291
- import path26 from "path";
26441
+ import path27 from "path";
25292
26442
  import { rm as rm11 } from "fs/promises";
25293
26443
 
25294
26444
  // src/relay/bootstrap.ts
@@ -25628,10 +26778,10 @@ async function loadRequiredIdentity2(paths) {
25628
26778
  }
25629
26779
  return identity;
25630
26780
  }
25631
- async function postServerJson(serverBaseUrl, path27, body, options) {
26781
+ async function postServerJson(serverBaseUrl, path28, body, options) {
25632
26782
  let response;
25633
26783
  try {
25634
- response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path27}`, {
26784
+ response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path28}`, {
25635
26785
  method: "POST",
25636
26786
  headers: {
25637
26787
  accept: "application/json",
@@ -25679,10 +26829,10 @@ function pairingErrorSnapshot(stage, error) {
25679
26829
  occurred_at: (/* @__PURE__ */ new Date()).toISOString()
25680
26830
  };
25681
26831
  }
25682
- async function patchServerJson(serverBaseUrl, path27, token, body, options) {
26832
+ async function patchServerJson(serverBaseUrl, path28, token, body, options) {
25683
26833
  let response;
25684
26834
  try {
25685
- response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path27}`, {
26835
+ response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path28}`, {
25686
26836
  method: "PATCH",
25687
26837
  headers: {
25688
26838
  accept: "application/json",
@@ -25730,10 +26880,10 @@ function createPairingNetworkError(input) {
25730
26880
  );
25731
26881
  }
25732
26882
  function pairingClaimPath(sessionId, paths) {
25733
- return path26.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
26883
+ return path27.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
25734
26884
  }
25735
26885
  function pairingSessionPath(sessionId, paths) {
25736
- return path26.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
26886
+ return path27.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
25737
26887
  }
25738
26888
  function qrPreferredUrls(routes) {
25739
26889
  return routes.preferredUrls.filter((url) => !url.includes("/api/v1/relay/links/")).slice(0, 1);
@@ -25809,8 +26959,8 @@ function registerSystemRoutes(router, options) {
25809
26959
  });
25810
26960
  router.post("/api/v1/pairing/claim", async (ctx) => {
25811
26961
  const body = await readJsonBody(ctx.req);
25812
- const sessionId = readString14(body, "session_id") ?? readString14(body, "sessionId");
25813
- const claimToken = readString14(body, "claim_token") ?? readString14(body, "claimToken");
26962
+ const sessionId = readString16(body, "session_id") ?? readString16(body, "sessionId");
26963
+ const claimToken = readString16(body, "claim_token") ?? readString16(body, "claimToken");
25814
26964
  if (!sessionId || !claimToken) {
25815
26965
  throw new LinkHttpError(
25816
26966
  400,
@@ -25821,10 +26971,10 @@ function registerSystemRoutes(router, options) {
25821
26971
  const claimed = await claimPairing({
25822
26972
  sessionId,
25823
26973
  claimToken,
25824
- deviceLabel: readString14(body, "device_label") ?? readString14(body, "deviceLabel") ?? "HermesPilot App",
25825
- devicePlatform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform") ?? "unknown",
25826
- deviceModel: readString14(body, "device_model") ?? readString14(body, "deviceModel"),
25827
- appInstanceId: readString14(body, "app_instance_id") ?? readString14(body, "appInstanceId"),
26974
+ deviceLabel: readString16(body, "device_label") ?? readString16(body, "deviceLabel") ?? "HermesPilot App",
26975
+ devicePlatform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform") ?? "unknown",
26976
+ deviceModel: readString16(body, "device_model") ?? readString16(body, "deviceModel"),
26977
+ appInstanceId: readString16(body, "app_instance_id") ?? readString16(body, "appInstanceId"),
25828
26978
  paths
25829
26979
  });
25830
26980
  ctx.body = claimed;
@@ -25899,9 +27049,9 @@ function registerSystemRoutes(router, options) {
25899
27049
  const body = await readJsonBody(ctx.req);
25900
27050
  const session = await createDeviceSession(
25901
27051
  {
25902
- label: readString14(body, "device_label") ?? readString14(body, "deviceLabel") ?? "HermesPilot App",
25903
- platform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform") ?? "unknown",
25904
- model: readString14(body, "device_model") ?? readString14(body, "deviceModel"),
27052
+ label: readString16(body, "device_label") ?? readString16(body, "deviceLabel") ?? "HermesPilot App",
27053
+ platform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform") ?? "unknown",
27054
+ model: readString16(body, "device_model") ?? readString16(body, "deviceModel"),
25905
27055
  appInstanceId: auth.appInstanceId
25906
27056
  },
25907
27057
  paths
@@ -25930,7 +27080,7 @@ function registerSystemRoutes(router, options) {
25930
27080
  });
25931
27081
  router.post("/api/v1/auth/refresh", async (ctx) => {
25932
27082
  const body = await readJsonBody(ctx.req);
25933
- const refreshToken = readString14(body, "refresh_token") ?? readString14(body, "refreshToken");
27083
+ const refreshToken = readString16(body, "refresh_token") ?? readString16(body, "refreshToken");
25934
27084
  if (!refreshToken) {
25935
27085
  throw new LinkHttpError(
25936
27086
  400,
@@ -25941,10 +27091,10 @@ function registerSystemRoutes(router, options) {
25941
27091
  const session = await refreshDeviceSession(
25942
27092
  refreshToken,
25943
27093
  {
25944
- appInstanceId: readString14(body, "app_instance_id") ?? readString14(body, "appInstanceId"),
25945
- label: readString14(body, "device_label") ?? readString14(body, "deviceLabel"),
25946
- platform: readString14(body, "device_platform") ?? readString14(body, "devicePlatform"),
25947
- model: readString14(body, "device_model") ?? readString14(body, "deviceModel")
27094
+ appInstanceId: readString16(body, "app_instance_id") ?? readString16(body, "appInstanceId"),
27095
+ label: readString16(body, "device_label") ?? readString16(body, "deviceLabel"),
27096
+ platform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform"),
27097
+ model: readString16(body, "device_model") ?? readString16(body, "deviceModel")
25948
27098
  },
25949
27099
  paths
25950
27100
  );
@@ -25963,7 +27113,7 @@ function registerSystemRoutes(router, options) {
25963
27113
  });
25964
27114
  router.post("/api/v1/auth/logout", async (ctx) => {
25965
27115
  const body = await readJsonBody(ctx.req);
25966
- const refreshToken = readString14(body, "refresh_token") ?? readString14(body, "refreshToken");
27116
+ const refreshToken = readString16(body, "refresh_token") ?? readString16(body, "refreshToken");
25967
27117
  if (refreshToken) {
25968
27118
  await revokeDeviceRefreshToken(refreshToken, paths);
25969
27119
  }
@@ -26189,7 +27339,7 @@ function registerSystemRoutes(router, options) {
26189
27339
  router.patch("/api/v1/devices/:deviceId", async (ctx) => {
26190
27340
  const auth = await authenticateRequest(ctx, paths);
26191
27341
  const body = await readJsonBody(ctx.req);
26192
- const label = readString14(body, "label") ?? readString14(body, "device_label");
27342
+ const label = readString16(body, "label") ?? readString16(body, "device_label");
26193
27343
  if (!label) {
26194
27344
  throw new LinkHttpError(
26195
27345
  400,
@@ -26233,7 +27383,7 @@ function isActiveCronJob(job) {
26233
27383
  if (!enabled) {
26234
27384
  return false;
26235
27385
  }
26236
- const state = readString14(job, "state")?.toLowerCase();
27386
+ const state = readString16(job, "state")?.toLowerCase();
26237
27387
  return !["paused", "disabled", "completed", "deleted"].includes(state ?? "");
26238
27388
  }
26239
27389
  function filterLogsWithinHours(logs, hours, now = Date.now()) {
@@ -26327,8 +27477,8 @@ function registerLinkUpdateRoutes(router, options) {
26327
27477
  ctx.body = await startLinkUpdate({
26328
27478
  paths,
26329
27479
  logger,
26330
- channel: readString14(body, "channel"),
26331
- targetVersion: readString14(body, "target_version") ?? readString14(body, "targetVersion")
27480
+ channel: readString16(body, "channel"),
27481
+ targetVersion: readString16(body, "target_version") ?? readString16(body, "targetVersion")
26332
27482
  });
26333
27483
  });
26334
27484
  router.get("/api/v1/link/update/events", async (ctx) => {
@@ -26358,7 +27508,7 @@ import QRCode from "qrcode";
26358
27508
  function registerPairingRoutes(router, options) {
26359
27509
  const { paths } = options;
26360
27510
  router.get("/pair", async (ctx) => {
26361
- const sessionId = readString14(ctx.query, "session_id");
27511
+ const sessionId = readString16(ctx.query, "session_id");
26362
27512
  if (!sessionId) {
26363
27513
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
26364
27514
  }
@@ -26383,7 +27533,7 @@ function registerPairingRoutes(router, options) {
26383
27533
  ctx.body = page;
26384
27534
  });
26385
27535
  router.get("/api/v1/pairing/session", async (ctx) => {
26386
- const sessionId = readString14(ctx.query, "session_id");
27536
+ const sessionId = readString16(ctx.query, "session_id");
26387
27537
  if (!sessionId) {
26388
27538
  throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
26389
27539
  }
@@ -26834,7 +27984,7 @@ function registerInternalRoutes(router, options) {
26834
27984
  router.post("/internal/deliver", async (ctx) => {
26835
27985
  assertLoopbackRequest(ctx.req);
26836
27986
  const body = await readJsonBody(ctx.req);
26837
- const stagingDir = readString14(body, "staging_dir") ?? readString14(body, "stagingDir");
27987
+ const stagingDir = readString16(body, "staging_dir") ?? readString16(body, "stagingDir");
26838
27988
  if (!stagingDir) {
26839
27989
  throw new LinkHttpError(
26840
27990
  400,