@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.
- package/dist/{chunk-M64JBORD.js → chunk-UHYO4EJD.js} +1791 -641
- package/dist/cli/index.js +1 -1
- package/dist/http/app.js +1 -1
- package/package.json +1 -1
|
@@ -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:
|
|
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.
|
|
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
|
|
7120
|
-
|
|
7121
|
-
|
|
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:
|
|
7145
|
-
...
|
|
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
|
|
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(
|
|
12759
|
-
|
|
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(
|
|
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(
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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}${
|
|
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:
|
|
13218
|
+
path: path28,
|
|
13129
13219
|
profile: options.profileName ?? "default",
|
|
13130
13220
|
port: config.port ?? null,
|
|
13131
|
-
url: `http://127.0.0.1:${config.port}${
|
|
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,
|
|
13231
|
+
function logHermesApiResponse(logger, method, path28, profileName, startedAt, response) {
|
|
13142
13232
|
const fields = {
|
|
13143
13233
|
method,
|
|
13144
|
-
path:
|
|
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,
|
|
13255
|
+
function logHermesApiError(logger, method, path28, profileName, startedAt, error) {
|
|
13166
13256
|
void logger?.warn("hermes_api_request_failed", {
|
|
13167
13257
|
method,
|
|
13168
|
-
path:
|
|
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
|
-
|
|
13410
|
+
readHermesTranscriptFilesHistory(
|
|
13411
|
+
sessionsDirConfig.sessionsDir,
|
|
13412
|
+
normalizedSessionId
|
|
13413
|
+
)
|
|
13310
13414
|
]);
|
|
13311
13415
|
const diagnosticCounts = {
|
|
13312
13416
|
state_db_message_count: dbHistory.length,
|
|
13313
|
-
|
|
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
|
-
"
|
|
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
|
|
13362
|
-
|
|
13363
|
-
|
|
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/
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
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 (
|
|
13966
|
-
|
|
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
|
-
|
|
13981
|
-
|
|
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
|
|
13984
|
-
|
|
13985
|
-
|
|
13986
|
-
|
|
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
|
|
13992
|
-
const
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
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
|
|
14228
|
+
return events;
|
|
14005
14229
|
}
|
|
14006
|
-
function
|
|
14007
|
-
|
|
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
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
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
|
|
14042
|
-
|
|
14043
|
-
|
|
14044
|
-
return null;
|
|
14261
|
+
async function readStateDbMessages2(dbPath, sessionId) {
|
|
14262
|
+
if (!await isFile2(dbPath)) {
|
|
14263
|
+
return [];
|
|
14045
14264
|
}
|
|
14046
|
-
|
|
14047
|
-
|
|
14048
|
-
|
|
14049
|
-
|
|
14050
|
-
|
|
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:
|
|
14833
|
+
tool_call_id: readString14(item, "call_id") ?? readString14(item, "id"),
|
|
14057
14834
|
arguments: argumentsValue,
|
|
14058
14835
|
preview: toolName,
|
|
14059
|
-
response_item_id:
|
|
14836
|
+
response_item_id: readString14(item, "id") ?? void 0
|
|
14060
14837
|
}
|
|
14061
14838
|
};
|
|
14062
14839
|
}
|
|
14063
14840
|
function normalizeResponseOutputItemDone(event) {
|
|
14064
|
-
const item =
|
|
14065
|
-
if (
|
|
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 (
|
|
14850
|
+
if (readString14(item, "type") !== "function_call_output") {
|
|
14074
14851
|
return null;
|
|
14075
14852
|
}
|
|
14076
14853
|
const output = readResponseItemOutput(item.output);
|
|
14077
|
-
const parsedOutput =
|
|
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:
|
|
14084
|
-
status:
|
|
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:
|
|
14865
|
+
response_item_id: readString14(item, "id") ?? void 0
|
|
14089
14866
|
}
|
|
14090
14867
|
};
|
|
14091
14868
|
}
|
|
14092
14869
|
function normalizeResponseCompleted(event) {
|
|
14093
|
-
const 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:
|
|
14100
|
-
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 =
|
|
14107
|
-
const 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:
|
|
14890
|
+
response_id: readString14(response, "id") ?? readString14(event.payload, "id"),
|
|
14114
14891
|
error: {
|
|
14115
|
-
message:
|
|
14892
|
+
message: readString14(error, "message") ?? readString14(event.payload, "message") ?? "Hermes run failed"
|
|
14116
14893
|
},
|
|
14117
|
-
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 =
|
|
14142
|
-
return
|
|
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 =
|
|
14152
|
-
const response =
|
|
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 =
|
|
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
|
|
14987
|
+
return readString14(choice, "finish_reason") ?? readString14(choice, "finishReason");
|
|
14207
14988
|
}
|
|
14208
14989
|
function readChatCompletionUsage(payload) {
|
|
14209
|
-
const 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
|
|
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(
|
|
14246
|
-
const 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
|
|
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 =
|
|
14275
|
-
const type =
|
|
14276
|
-
const 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 =
|
|
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 =
|
|
14302
|
-
const 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(
|
|
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
|
|
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
|
|
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
|
|
14439
|
-
|
|
14440
|
-
|
|
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
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
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
|
-
|
|
14466
|
-
|
|
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
|
-
|
|
14470
|
-
|
|
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
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
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
|
-
|
|
14492
|
-
|
|
14493
|
-
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
|
|
14498
|
-
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
|
|
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.
|
|
14516
|
-
|
|
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
|
-
|
|
14525
|
-
|
|
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.
|
|
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
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
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: "
|
|
14549
|
-
})
|
|
15488
|
+
source: "final-empty-response"
|
|
15489
|
+
}),
|
|
15490
|
+
input.event
|
|
14550
15491
|
);
|
|
15492
|
+
return true;
|
|
14551
15493
|
}
|
|
14552
|
-
this.
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
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
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
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
|
|
14572
|
-
|
|
15567
|
+
async cancelRunAfterAbort(conversationId, runId) {
|
|
15568
|
+
await this.deps.withConversationLock(
|
|
14573
15569
|
conversationId,
|
|
14574
|
-
() => this.cancelRunLocked(conversationId, runId,
|
|
15570
|
+
() => this.cancelRunLocked(conversationId, runId, {
|
|
15571
|
+
abortUpstream: false,
|
|
15572
|
+
reason: "cancelled by app"
|
|
15573
|
+
})
|
|
14575
15574
|
);
|
|
14576
15575
|
}
|
|
14577
|
-
async
|
|
14578
|
-
|
|
15576
|
+
async completeCancelledRun(conversationId, runId) {
|
|
15577
|
+
await this.deps.withConversationLock(
|
|
14579
15578
|
conversationId,
|
|
14580
|
-
() => this.
|
|
15579
|
+
() => this.cancelRunLocked(conversationId, runId, {
|
|
15580
|
+
abortUpstream: false,
|
|
15581
|
+
reason: "cancelled by Hermes"
|
|
15582
|
+
})
|
|
14581
15583
|
);
|
|
14582
15584
|
}
|
|
14583
|
-
async
|
|
14584
|
-
const
|
|
14585
|
-
|
|
14586
|
-
|
|
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
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
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 =
|
|
14886
|
-
|
|
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
|
-
...
|
|
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:${
|
|
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) =>
|
|
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 =
|
|
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 (
|
|
16374
|
+
if (isNodeError14(error, "ENOENT")) {
|
|
15260
16375
|
return [];
|
|
15261
16376
|
}
|
|
15262
16377
|
throw error;
|
|
15263
16378
|
});
|
|
15264
16379
|
}
|
|
15265
|
-
function
|
|
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
|
|
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 =
|
|
15286
|
-
const toolCall =
|
|
15287
|
-
const fn =
|
|
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
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
|
|
15295
|
-
|
|
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
|
-
|
|
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:
|
|
15439
|
-
...
|
|
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 =
|
|
15510
|
-
return
|
|
16612
|
+
const response = toRecord13(payload.response);
|
|
16613
|
+
return readString15(payload, "response_id") ?? readString15(response, "id");
|
|
15511
16614
|
}
|
|
15512
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
17735
|
-
import
|
|
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 (
|
|
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
|
|
17777
|
-
if (
|
|
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(
|
|
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
|
|
17890
|
-
if (
|
|
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
|
|
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
|
|
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 (
|
|
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 =
|
|
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
|
|
19226
|
+
const raw = await readFile13(
|
|
18077
19227
|
resolveHermesConfigPath(profileName),
|
|
18078
19228
|
"utf8"
|
|
18079
19229
|
).catch((error) => {
|
|
18080
|
-
if (
|
|
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 =
|
|
19238
|
+
const config = toRecord14(YAML2.parse(raw));
|
|
18089
19239
|
const toolsets = /* @__PURE__ */ new Set();
|
|
18090
19240
|
collectToolsetValues(config.toolsets, toolsets);
|
|
18091
|
-
const platformToolsets =
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
18324
|
-
const prompt =
|
|
18325
|
-
const 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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
18680
|
-
const provider =
|
|
18681
|
-
const 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:
|
|
19841
|
+
originalModelId: readString16(body, "original_model_id") ?? readString16(body, "originalModelId") ?? readString16(body, "original_id") ?? void 0,
|
|
18692
19842
|
provider,
|
|
18693
|
-
providerName:
|
|
19843
|
+
providerName: readString16(body, "provider_name") ?? readString16(body, "providerName") ?? void 0,
|
|
18694
19844
|
baseUrl,
|
|
18695
|
-
apiKey:
|
|
18696
|
-
apiMode:
|
|
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:
|
|
19850
|
+
keyEnv: readString16(body, "key_env") ?? readString16(body, "keyEnv") ?? void 0,
|
|
18701
19851
|
setDefault: readBoolean3(body.set_default ?? body.setDefault),
|
|
18702
|
-
reasoningEffort:
|
|
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:
|
|
18708
|
-
compressionModelId:
|
|
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 =
|
|
18713
|
-
const modelId =
|
|
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:
|
|
18725
|
-
baseUrl:
|
|
18726
|
-
apiMode:
|
|
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
|
|
19961
|
+
readFile as readFile14,
|
|
18812
19962
|
rm as rm6,
|
|
18813
|
-
stat as
|
|
19963
|
+
stat as stat14
|
|
18814
19964
|
} from "fs/promises";
|
|
18815
|
-
import
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
19267
|
-
const existingRaw = await
|
|
19268
|
-
if (
|
|
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 =
|
|
19304
|
-
const targetSkills =
|
|
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
|
|
20477
|
+
const existingRaw = await readFile14(configPath, "utf8").catch(
|
|
19328
20478
|
(error) => {
|
|
19329
|
-
if (
|
|
20479
|
+
if (isNodeError16(error, "ENOENT")) {
|
|
19330
20480
|
return null;
|
|
19331
20481
|
}
|
|
19332
20482
|
throw error;
|
|
19333
20483
|
}
|
|
19334
20484
|
);
|
|
19335
20485
|
return {
|
|
19336
|
-
config:
|
|
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
|
|
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
|
|
20549
|
+
return path21.join(paths.runDir, "profile-create-state.json");
|
|
19400
20550
|
}
|
|
19401
20551
|
function profileCreationLogPath(paths) {
|
|
19402
|
-
return
|
|
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
|
|
19416
|
-
if (
|
|
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
|
|
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
|
|
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:
|
|
20698
|
+
mode: readString16(approvals, "mode") ?? readString16(approvals, "approval_mode") ?? readString16(approvals, "approvalMode") ?? void 0,
|
|
19549
20699
|
timeout: readPositiveInteger2(approvals.timeout),
|
|
19550
|
-
cronMode:
|
|
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:
|
|
19557
|
-
cwd:
|
|
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
|
|
19674
|
-
stat as
|
|
20823
|
+
readFile as readFile15,
|
|
20824
|
+
stat as stat15
|
|
19675
20825
|
} from "fs/promises";
|
|
19676
|
-
import
|
|
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 =
|
|
19865
|
-
const bankId =
|
|
19866
|
-
const apiKey =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
21296
|
+
const existingRaw = await readFile15(configPath, "utf8").catch(
|
|
20147
21297
|
(error) => {
|
|
20148
|
-
if (
|
|
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 =
|
|
20156
|
-
const 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
|
|
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
|
|
20175
|
-
if (
|
|
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
|
|
20204
|
-
if (
|
|
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
|
|
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:
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
20435
|
-
const llmModel =
|
|
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
|
-
|
|
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
|
-
|
|
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 ??
|
|
20508
|
-
isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(
|
|
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 ??
|
|
20551
|
-
isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(
|
|
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 =
|
|
20620
|
-
const hermesBank =
|
|
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 ??
|
|
20637
|
-
isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(
|
|
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 ??
|
|
20660
|
-
isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(
|
|
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 ??
|
|
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
|
-
|
|
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
|
|
21879
|
+
return path22.join(resolveHermesProfileDir(profileName), "honcho.json");
|
|
20730
21880
|
}
|
|
20731
21881
|
if (provider === "mem0") {
|
|
20732
|
-
return
|
|
21882
|
+
return path22.join(resolveHermesProfileDir(profileName), "mem0.json");
|
|
20733
21883
|
}
|
|
20734
21884
|
if (provider === "supermemory") {
|
|
20735
|
-
return
|
|
21885
|
+
return path22.join(resolveHermesProfileDir(profileName), "supermemory.json");
|
|
20736
21886
|
}
|
|
20737
21887
|
if (provider === "hindsight") {
|
|
20738
|
-
return
|
|
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
|
|
21897
|
+
return path22.join(
|
|
20748
21898
|
resolveHermesProfileDir(profileName),
|
|
20749
21899
|
`${normalizeCustomProviderId(provider)}.json`
|
|
20750
21900
|
);
|
|
20751
21901
|
}
|
|
20752
21902
|
function customProviderRegistryPath(profileName) {
|
|
20753
|
-
return
|
|
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
|
|
21909
|
+
const raw = await readFile15(customProviderRegistryPath(profileName), "utf8").catch(
|
|
20760
21910
|
(error) => {
|
|
20761
|
-
if (
|
|
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(
|
|
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 =
|
|
20779
|
-
const id = normalizeCustomProviderId(
|
|
21928
|
+
const record = toRecord16(item);
|
|
21929
|
+
const id = normalizeCustomProviderId(readString17(record.id) ?? "");
|
|
20780
21930
|
return {
|
|
20781
21931
|
id,
|
|
20782
|
-
label:
|
|
20783
|
-
description:
|
|
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 =
|
|
21955
|
+
const pluginsDir = path22.join(resolveHermesProfileDir(profileName), "plugins");
|
|
20806
21956
|
const entries = await readdir10(pluginsDir, { withFileTypes: true }).catch(
|
|
20807
21957
|
(error) => {
|
|
20808
|
-
if (
|
|
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 =
|
|
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:
|
|
20833
|
-
description:
|
|
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 =
|
|
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
|
|
21997
|
+
const source = await readFile15(path22.join(providerDir, "__init__.py"), "utf8").catch(
|
|
20848
21998
|
(error) => {
|
|
20849
|
-
if (
|
|
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
|
|
22009
|
+
const raw = await readFile15(path22.join(providerDir, "plugin.yaml"), "utf8").catch(
|
|
20860
22010
|
(error) => {
|
|
20861
|
-
if (
|
|
22011
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20862
22012
|
return "";
|
|
20863
22013
|
}
|
|
20864
22014
|
throw error;
|
|
20865
22015
|
}
|
|
20866
22016
|
);
|
|
20867
|
-
return raw ?
|
|
22017
|
+
return raw ? toRecord16(YAML4.parse(raw)) : {};
|
|
20868
22018
|
}
|
|
20869
22019
|
async function resolveByteRoverCli() {
|
|
20870
22020
|
const candidates = [
|
|
20871
|
-
...(process.env.PATH ?? "").split(
|
|
20872
|
-
|
|
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
|
-
|
|
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
|
|
22035
|
+
const raw = await readFile15(resolveHermesConfigPath(profileName), "utf8").catch(
|
|
20886
22036
|
(error) => {
|
|
20887
|
-
if (
|
|
22037
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20888
22038
|
return "";
|
|
20889
22039
|
}
|
|
20890
22040
|
throw error;
|
|
20891
22041
|
}
|
|
20892
22042
|
);
|
|
20893
|
-
const config = raw ?
|
|
20894
|
-
const plugins =
|
|
20895
|
-
return
|
|
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
|
|
22049
|
+
const existingRaw = await readFile15(configPath, "utf8").catch(
|
|
20900
22050
|
(error) => {
|
|
20901
|
-
if (
|
|
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 =
|
|
20909
|
-
const plugins =
|
|
20910
|
-
const memoryStore =
|
|
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 =
|
|
20936
|
-
const existingRaw = await
|
|
20937
|
-
if (
|
|
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 =
|
|
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
|
|
22208
|
+
return toRecord16(JSON.parse(text));
|
|
21059
22209
|
} catch {
|
|
21060
22210
|
return {};
|
|
21061
22211
|
}
|
|
21062
22212
|
}
|
|
21063
22213
|
function readHindsightError(json) {
|
|
21064
|
-
const detail =
|
|
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 =
|
|
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 =
|
|
21077
|
-
const 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 =
|
|
22231
|
+
const version = readString17(json.api_version);
|
|
21082
22232
|
return version ? `API ${version}` : "version endpoint reachable";
|
|
21083
22233
|
}
|
|
21084
|
-
const bankId =
|
|
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
|
|
22238
|
+
const raw = await readFile15(
|
|
21089
22239
|
resolveHermesConfigPath(profileName),
|
|
21090
22240
|
"utf8"
|
|
21091
22241
|
).catch((error) => {
|
|
21092
|
-
if (
|
|
22242
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
21093
22243
|
return "";
|
|
21094
22244
|
}
|
|
21095
22245
|
throw error;
|
|
21096
22246
|
});
|
|
21097
|
-
const config = raw ?
|
|
21098
|
-
const memory =
|
|
21099
|
-
const 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 =
|
|
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
|
|
21125
|
-
if (
|
|
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
|
|
22281
|
+
return toRecord16(JSON.parse(raw || "{}"));
|
|
21132
22282
|
} catch {
|
|
21133
22283
|
throw new HermesMemoryError(
|
|
21134
22284
|
"memory_provider_config_invalid",
|
|
21135
|
-
`${
|
|
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:
|
|
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(
|
|
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 =
|
|
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
|
|
22335
|
+
const raw = await readFile15(
|
|
21186
22336
|
resolveHermesConfigPath(profileName),
|
|
21187
22337
|
"utf8"
|
|
21188
22338
|
).catch((error) => {
|
|
21189
|
-
if (
|
|
22339
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
21190
22340
|
return "";
|
|
21191
22341
|
}
|
|
21192
22342
|
throw error;
|
|
21193
22343
|
});
|
|
21194
|
-
const config = raw ?
|
|
21195
|
-
const 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
|
|
22401
|
+
function toRecord16(value) {
|
|
21252
22402
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
21253
22403
|
}
|
|
21254
|
-
function
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
22671
|
+
const memoryMode = readString16(body, "memory_mode") ?? readString16(body, "memoryMode");
|
|
21522
22672
|
if (memoryMode) {
|
|
21523
22673
|
input.memoryMode = memoryMode;
|
|
21524
22674
|
}
|
|
21525
|
-
const 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 =
|
|
22691
|
+
const captureMode = readString16(body, "capture_mode") ?? readString16(body, "captureMode");
|
|
21542
22692
|
if (captureMode) {
|
|
21543
22693
|
input.captureMode = captureMode;
|
|
21544
22694
|
}
|
|
21545
|
-
const 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 =
|
|
22729
|
+
const recallMode = readString16(body, "recall_mode") ?? readString16(body, "recallMode");
|
|
21580
22730
|
if (recallMode) {
|
|
21581
22731
|
input.recallMode = recallMode;
|
|
21582
22732
|
}
|
|
21583
|
-
const 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 =
|
|
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
|
|
21724
|
-
import
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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
|
|
22990
|
+
const raw = await readFile16(input.skillFile, "utf8").catch(
|
|
21841
22991
|
(error) => {
|
|
21842
|
-
if (
|
|
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 =
|
|
23001
|
+
const skillDir = path23.dirname(input.skillFile);
|
|
21852
23002
|
const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
|
|
21853
23003
|
const name = normalizeSkillName(
|
|
21854
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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 =
|
|
21895
|
-
const parts = relative.split(
|
|
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
|
|
21919
|
-
if (
|
|
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 =
|
|
21928
|
-
const 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
|
|
23092
|
+
const raw = await readFile16(path23.join(root, ".bundled_manifest"), "utf8").catch(
|
|
21943
23093
|
(error) => {
|
|
21944
|
-
if (
|
|
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
|
|
23115
|
+
const raw = await readFile16(path23.join(root, ".hub", "lock.json"), "utf8").catch(
|
|
21966
23116
|
(error) => {
|
|
21967
|
-
if (
|
|
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 =
|
|
23128
|
+
lock = toRecord17(JSON.parse(raw));
|
|
21979
23129
|
} catch {
|
|
21980
23130
|
return /* @__PURE__ */ new Map();
|
|
21981
23131
|
}
|
|
21982
|
-
const 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 =
|
|
23135
|
+
const entry = toRecord17(rawEntry);
|
|
21986
23136
|
result.set(normalizeSkillName(name), {
|
|
21987
|
-
source:
|
|
21988
|
-
trust:
|
|
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
|
|
23187
|
+
const existingRaw = await readFile16(configPath, "utf8").catch(
|
|
22038
23188
|
(error) => {
|
|
22039
|
-
if (
|
|
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:
|
|
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
|
|
23222
|
+
function readString18(value) {
|
|
22073
23223
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
22074
23224
|
}
|
|
22075
|
-
function
|
|
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 =
|
|
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
|
|
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 =
|
|
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:
|
|
23543
|
+
instructions: readString16(body, "instructions") ?? void 0,
|
|
22394
23544
|
conversation_history: readConversationHistory(
|
|
22395
23545
|
body.conversation_history ?? body.conversationHistory
|
|
22396
23546
|
),
|
|
22397
|
-
session_id:
|
|
22398
|
-
session_key:
|
|
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
|
|
22570
|
-
import
|
|
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 =
|
|
23953
|
+
const snapshot = toRecord18(payload);
|
|
22804
23954
|
const remote = toNullableRecord(snapshot.remote);
|
|
22805
23955
|
return {
|
|
22806
23956
|
remote: remote ? normalizeServerRelease(remote) : null,
|
|
22807
|
-
cacheState:
|
|
22808
|
-
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 =
|
|
22813
|
-
const name =
|
|
23962
|
+
const tag = readString19(payload, "tag");
|
|
23963
|
+
const name = readString19(payload, "name");
|
|
22814
23964
|
return {
|
|
22815
|
-
version:
|
|
23965
|
+
version: readString19(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
|
|
22816
23966
|
tag,
|
|
22817
23967
|
name,
|
|
22818
|
-
releaseUrl:
|
|
22819
|
-
publishedAt:
|
|
22820
|
-
fetchedAt:
|
|
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
|
|
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
|
|
23998
|
+
return path24.join(paths.indexesDir, "hermes-release-check.json");
|
|
22849
23999
|
}
|
|
22850
24000
|
function updateStatePath(paths) {
|
|
22851
|
-
return
|
|
24001
|
+
return path24.join(paths.runDir, "hermes-update-state.json");
|
|
22852
24002
|
}
|
|
22853
24003
|
function updateLogPath(paths) {
|
|
22854
|
-
return
|
|
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
|
|
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
|
|
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
|
|
22955
|
-
import
|
|
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
|
|
22960
|
-
import
|
|
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:
|
|
22972
|
-
flushBytes:
|
|
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:
|
|
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
|
|
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 =
|
|
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:
|
|
26007
|
+
issue: readString20(snapshot, "issue")
|
|
24858
26008
|
};
|
|
24859
26009
|
}
|
|
24860
26010
|
const release = toNullableRecord2(snapshot.release);
|
|
24861
|
-
const currentVersion =
|
|
24862
|
-
const 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:
|
|
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 ?
|
|
24875
|
-
published_at: release ?
|
|
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:
|
|
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
|
|
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
|
|
26354
|
+
return path26.join(paths.runDir, "link-update-state.json");
|
|
25205
26355
|
}
|
|
25206
26356
|
function updateLogPath2(paths) {
|
|
25207
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
26781
|
+
async function postServerJson(serverBaseUrl, path28, body, options) {
|
|
25632
26782
|
let response;
|
|
25633
26783
|
try {
|
|
25634
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
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,
|
|
26832
|
+
async function patchServerJson(serverBaseUrl, path28, token, body, options) {
|
|
25683
26833
|
let response;
|
|
25684
26834
|
try {
|
|
25685
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
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
|
|
26883
|
+
return path27.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
|
|
25734
26884
|
}
|
|
25735
26885
|
function pairingSessionPath(sessionId, paths) {
|
|
25736
|
-
return
|
|
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 =
|
|
25813
|
-
const 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:
|
|
25825
|
-
devicePlatform:
|
|
25826
|
-
deviceModel:
|
|
25827
|
-
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:
|
|
25903
|
-
platform:
|
|
25904
|
-
model:
|
|
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 =
|
|
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:
|
|
25945
|
-
label:
|
|
25946
|
-
platform:
|
|
25947
|
-
model:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
26331
|
-
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 =
|
|
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 =
|
|
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 =
|
|
27987
|
+
const stagingDir = readString16(body, "staging_dir") ?? readString16(body, "stagingDir");
|
|
26838
27988
|
if (!stagingDir) {
|
|
26839
27989
|
throw new LinkHttpError(
|
|
26840
27990
|
400,
|