@hermespilot/link 0.5.8 → 0.5.9
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-52SUJB7K.js} +1587 -543
- 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.5.
|
|
4505
|
+
var LINK_VERSION = "0.5.9";
|
|
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 } : {},
|
|
@@ -13943,6 +14033,587 @@ function toRecord9(value) {
|
|
|
13943
14033
|
return typeof value === "object" && value !== null ? value : {};
|
|
13944
14034
|
}
|
|
13945
14035
|
|
|
14036
|
+
// src/conversations/run-backend.ts
|
|
14037
|
+
var RUNS_BACKEND_VALUES = /* @__PURE__ */ new Set(["run", "runs", "v1/runs", "/v1/runs"]);
|
|
14038
|
+
var RESPONSES_BACKEND_VALUES = /* @__PURE__ */ new Set([
|
|
14039
|
+
"response",
|
|
14040
|
+
"responses",
|
|
14041
|
+
"v1/responses",
|
|
14042
|
+
"/v1/responses"
|
|
14043
|
+
]);
|
|
14044
|
+
function resolveConversationRunBackend(env = process.env) {
|
|
14045
|
+
const raw = (env.HERMESLINK_CONVERSATION_BACKEND ?? env.HERMESLINK_CHAT_BACKEND ?? "").trim().toLowerCase();
|
|
14046
|
+
if (RESPONSES_BACKEND_VALUES.has(raw)) {
|
|
14047
|
+
return "responses";
|
|
14048
|
+
}
|
|
14049
|
+
if (RUNS_BACKEND_VALUES.has(raw)) {
|
|
14050
|
+
return "runs";
|
|
14051
|
+
}
|
|
14052
|
+
return "runs";
|
|
14053
|
+
}
|
|
14054
|
+
function isRunToolResultCompensationEnabled(env = process.env) {
|
|
14055
|
+
const raw = env.HERMESLINK_RUN_TOOL_RESULT_COMPENSATION?.trim().toLowerCase();
|
|
14056
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
14057
|
+
}
|
|
14058
|
+
|
|
14059
|
+
// src/conversations/run-transcript-enrichment.ts
|
|
14060
|
+
import { readFile as readFile12, stat as stat12 } from "fs/promises";
|
|
14061
|
+
import path19 from "path";
|
|
14062
|
+
var MESSAGE_COLUMNS2 = [
|
|
14063
|
+
"id",
|
|
14064
|
+
"session_id",
|
|
14065
|
+
"role",
|
|
14066
|
+
"content",
|
|
14067
|
+
"tool_call_id",
|
|
14068
|
+
"tool_calls",
|
|
14069
|
+
"tool_name",
|
|
14070
|
+
"timestamp"
|
|
14071
|
+
];
|
|
14072
|
+
async function buildRunTranscriptEvents(input) {
|
|
14073
|
+
const sessionId = input.hermesSessionId.trim();
|
|
14074
|
+
if (!sessionId) {
|
|
14075
|
+
return [];
|
|
14076
|
+
}
|
|
14077
|
+
const profileName = isValidProfileName3(input.profileName) ? input.profileName : "default";
|
|
14078
|
+
const rows = await readHermesTranscriptRows(profileName, sessionId);
|
|
14079
|
+
if (rows.length === 0) {
|
|
14080
|
+
return [];
|
|
14081
|
+
}
|
|
14082
|
+
const lowerBoundSeconds = runStartedLowerBoundSeconds(input.runStartedAt);
|
|
14083
|
+
const reusableEventIds = groupReusableToolEventIds(
|
|
14084
|
+
input.assistant?.agent_events ?? []
|
|
14085
|
+
);
|
|
14086
|
+
const events = [];
|
|
14087
|
+
const pendingToolCalls = [];
|
|
14088
|
+
const toolCallsById = /* @__PURE__ */ new Map();
|
|
14089
|
+
for (const row of rows) {
|
|
14090
|
+
if (!isRunRow(row, lowerBoundSeconds)) {
|
|
14091
|
+
continue;
|
|
14092
|
+
}
|
|
14093
|
+
const role = normalizeRole(row.role);
|
|
14094
|
+
if (role === "assistant") {
|
|
14095
|
+
for (const toolCall of readHermesToolCalls2(row)) {
|
|
14096
|
+
const pending = { toolCall };
|
|
14097
|
+
pendingToolCalls.push(pending);
|
|
14098
|
+
if (toolCall.id) {
|
|
14099
|
+
toolCallsById.set(toolCall.id, pending);
|
|
14100
|
+
}
|
|
14101
|
+
}
|
|
14102
|
+
continue;
|
|
14103
|
+
}
|
|
14104
|
+
if (role === "tool") {
|
|
14105
|
+
const pending = consumePendingToolCall2({
|
|
14106
|
+
toolMessage: row,
|
|
14107
|
+
pendingToolCalls,
|
|
14108
|
+
toolCallsById
|
|
14109
|
+
});
|
|
14110
|
+
if (!pending) {
|
|
14111
|
+
continue;
|
|
14112
|
+
}
|
|
14113
|
+
events.push(
|
|
14114
|
+
toolCompletedEvent(
|
|
14115
|
+
row,
|
|
14116
|
+
pending,
|
|
14117
|
+
consumeReusableToolEventId(reusableEventIds, pending, row)
|
|
14118
|
+
)
|
|
14119
|
+
);
|
|
14120
|
+
}
|
|
14121
|
+
}
|
|
14122
|
+
return events;
|
|
14123
|
+
}
|
|
14124
|
+
async function readHermesTranscriptRows(profileName, sessionId) {
|
|
14125
|
+
const profileDir = resolveHermesProfileDir(profileName);
|
|
14126
|
+
const dbPath = path19.join(profileDir, "state.db");
|
|
14127
|
+
const sessionsDir = await readHermesSessionsDir(profileName).then((value) => value.sessionsDir).catch(() => path19.join(profileDir, "sessions"));
|
|
14128
|
+
const [dbRows, jsonlRows] = await Promise.all([
|
|
14129
|
+
readStateDbMessages2(dbPath, sessionId),
|
|
14130
|
+
readJsonlMessages2(sessionsDir, sessionId)
|
|
14131
|
+
]);
|
|
14132
|
+
return selectTranscriptRows(dbRows, jsonlRows);
|
|
14133
|
+
}
|
|
14134
|
+
function selectTranscriptRows(dbRows, jsonlRows) {
|
|
14135
|
+
if (jsonlRows.length === 0) {
|
|
14136
|
+
return dbRows;
|
|
14137
|
+
}
|
|
14138
|
+
if (dbRows.length === 0) {
|
|
14139
|
+
return jsonlRows;
|
|
14140
|
+
}
|
|
14141
|
+
if (jsonlRows.length <= dbRows.length) {
|
|
14142
|
+
return dbRows;
|
|
14143
|
+
}
|
|
14144
|
+
const jsonlTimestampedRows = jsonlRows.filter(
|
|
14145
|
+
(row) => hasUsableTimestamp(row.timestamp)
|
|
14146
|
+
).length;
|
|
14147
|
+
const dbTimestampedRows = dbRows.filter(
|
|
14148
|
+
(row) => hasUsableTimestamp(row.timestamp)
|
|
14149
|
+
).length;
|
|
14150
|
+
if (jsonlTimestampedRows === 0 && dbTimestampedRows > 0) {
|
|
14151
|
+
return dbRows;
|
|
14152
|
+
}
|
|
14153
|
+
return jsonlRows;
|
|
14154
|
+
}
|
|
14155
|
+
async function readStateDbMessages2(dbPath, sessionId) {
|
|
14156
|
+
if (!await isFile2(dbPath)) {
|
|
14157
|
+
return [];
|
|
14158
|
+
}
|
|
14159
|
+
let db = null;
|
|
14160
|
+
try {
|
|
14161
|
+
db = openSqliteDatabase(dbPath, {
|
|
14162
|
+
readonly: true,
|
|
14163
|
+
timeout: 1e3
|
|
14164
|
+
});
|
|
14165
|
+
const columns = readTableColumns3(db, "messages");
|
|
14166
|
+
if (!columns.has("session_id") || !columns.has("role")) {
|
|
14167
|
+
return [];
|
|
14168
|
+
}
|
|
14169
|
+
const selectColumns = MESSAGE_COLUMNS2.map(
|
|
14170
|
+
(column) => columns.has(column) ? quoteIdentifier2(column) : `NULL AS ${column}`
|
|
14171
|
+
).join(", ");
|
|
14172
|
+
return db.prepare(
|
|
14173
|
+
`
|
|
14174
|
+
SELECT ${selectColumns}
|
|
14175
|
+
FROM messages
|
|
14176
|
+
WHERE session_id = ?
|
|
14177
|
+
ORDER BY timestamp, id
|
|
14178
|
+
`
|
|
14179
|
+
).all(sessionId);
|
|
14180
|
+
} catch {
|
|
14181
|
+
return [];
|
|
14182
|
+
} finally {
|
|
14183
|
+
db?.close();
|
|
14184
|
+
}
|
|
14185
|
+
}
|
|
14186
|
+
async function readJsonlMessages2(sessionsDir, sessionId) {
|
|
14187
|
+
if (!/^[A-Za-z0-9._:-]{1,160}$/u.test(sessionId)) {
|
|
14188
|
+
return [];
|
|
14189
|
+
}
|
|
14190
|
+
const transcriptPath = path19.join(sessionsDir, `${sessionId}.jsonl`);
|
|
14191
|
+
const raw = await readFile12(transcriptPath, "utf8").catch((error) => {
|
|
14192
|
+
if (isNodeError13(error, "ENOENT")) {
|
|
14193
|
+
return "";
|
|
14194
|
+
}
|
|
14195
|
+
throw error;
|
|
14196
|
+
});
|
|
14197
|
+
if (!raw.trim()) {
|
|
14198
|
+
return [];
|
|
14199
|
+
}
|
|
14200
|
+
const rows = [];
|
|
14201
|
+
for (const line of raw.split(/\r?\n/u)) {
|
|
14202
|
+
if (!line.trim()) {
|
|
14203
|
+
continue;
|
|
14204
|
+
}
|
|
14205
|
+
try {
|
|
14206
|
+
const parsed = JSON.parse(line);
|
|
14207
|
+
const role = readString12(parsed, "role");
|
|
14208
|
+
if (!role) {
|
|
14209
|
+
continue;
|
|
14210
|
+
}
|
|
14211
|
+
rows.push({
|
|
14212
|
+
...parsed,
|
|
14213
|
+
role,
|
|
14214
|
+
content: normalizeContent3(parsed.content),
|
|
14215
|
+
timestamp: readNumber3(parsed.timestamp) ?? readNumber3(parsed.created_at) ?? readNumber3(parsed.createdAt) ?? void 0
|
|
14216
|
+
});
|
|
14217
|
+
} catch {
|
|
14218
|
+
continue;
|
|
14219
|
+
}
|
|
14220
|
+
}
|
|
14221
|
+
return rows;
|
|
14222
|
+
}
|
|
14223
|
+
function readHermesToolCalls2(row) {
|
|
14224
|
+
const decoded = parseJsonValue2(row.tool_calls) ?? row.tool_calls;
|
|
14225
|
+
const values = Array.isArray(decoded) ? decoded : decoded ? [decoded] : [];
|
|
14226
|
+
return values.map((value) => normalizeHermesToolCall2(value)).filter(
|
|
14227
|
+
(toolCall) => Boolean(toolCall)
|
|
14228
|
+
);
|
|
14229
|
+
}
|
|
14230
|
+
function normalizeHermesToolCall2(value) {
|
|
14231
|
+
const record = toRecord10(value);
|
|
14232
|
+
if (Object.keys(record).length === 0) {
|
|
14233
|
+
return null;
|
|
14234
|
+
}
|
|
14235
|
+
const fn = toRecord10(record.function);
|
|
14236
|
+
const id = readString12(record, "id") ?? readString12(record, "call_id") ?? readString12(record, "tool_call_id") ?? readString12(fn, "id") ?? void 0;
|
|
14237
|
+
const name = readString12(fn, "name") ?? readString12(record, "name") ?? readString12(record, "tool_name") ?? readString12(record, "tool") ?? "tool";
|
|
14238
|
+
const rawArguments = fn.arguments ?? record.arguments ?? record.args ?? record.input;
|
|
14239
|
+
return {
|
|
14240
|
+
...id ? { id } : {},
|
|
14241
|
+
name,
|
|
14242
|
+
...rawArguments === void 0 ? {} : { arguments: parseJsonValue2(rawArguments) ?? rawArguments },
|
|
14243
|
+
raw: value
|
|
14244
|
+
};
|
|
14245
|
+
}
|
|
14246
|
+
function consumePendingToolCall2(input) {
|
|
14247
|
+
const toolCallId = readString12(input.toolMessage, "tool_call_id");
|
|
14248
|
+
const toolName = readString12(input.toolMessage, "tool_name");
|
|
14249
|
+
let pending = toolCallId ? input.toolCallsById.get(toolCallId) : void 0;
|
|
14250
|
+
if (!pending && toolName) {
|
|
14251
|
+
pending = input.pendingToolCalls.find(
|
|
14252
|
+
(item) => item.toolCall.name === toolName
|
|
14253
|
+
);
|
|
14254
|
+
}
|
|
14255
|
+
pending ??= input.pendingToolCalls[0];
|
|
14256
|
+
if (!pending) {
|
|
14257
|
+
return void 0;
|
|
14258
|
+
}
|
|
14259
|
+
const index = input.pendingToolCalls.indexOf(pending);
|
|
14260
|
+
if (index >= 0) {
|
|
14261
|
+
input.pendingToolCalls.splice(index, 1);
|
|
14262
|
+
}
|
|
14263
|
+
if (pending.toolCall.id) {
|
|
14264
|
+
input.toolCallsById.delete(pending.toolCall.id);
|
|
14265
|
+
}
|
|
14266
|
+
return pending;
|
|
14267
|
+
}
|
|
14268
|
+
function toolCompletedEvent(row, pending, existingEventId) {
|
|
14269
|
+
const output = normalizeContent3(row.content);
|
|
14270
|
+
const parsedOutput = parseJsonValue2(output);
|
|
14271
|
+
const toolCallId = readString12(row, "tool_call_id") ?? pending?.toolCall.id;
|
|
14272
|
+
const toolName = readString12(row, "tool_name") ?? pending?.toolCall.name ?? "tool";
|
|
14273
|
+
const payload = {
|
|
14274
|
+
type: "tool.completed",
|
|
14275
|
+
event: "tool.completed",
|
|
14276
|
+
tool: toolName,
|
|
14277
|
+
tool_name: toolName,
|
|
14278
|
+
name: toolName,
|
|
14279
|
+
...existingEventId ? {
|
|
14280
|
+
id: existingEventId,
|
|
14281
|
+
...toolCallId ? { hermes_tool_call_id: toolCallId } : {}
|
|
14282
|
+
} : toolCallId ? { tool_call_id: toolCallId, id: toolCallId } : {},
|
|
14283
|
+
...pending?.toolCall.arguments === void 0 ? {} : { arguments: pending.toolCall.arguments },
|
|
14284
|
+
output,
|
|
14285
|
+
content: output,
|
|
14286
|
+
result: parsedOutput ?? output,
|
|
14287
|
+
...pending ? { tool_call: pending.toolCall.raw } : {},
|
|
14288
|
+
timestamp: row.timestamp
|
|
14289
|
+
};
|
|
14290
|
+
return {
|
|
14291
|
+
eventName: "tool.completed",
|
|
14292
|
+
payloadType: "tool.completed",
|
|
14293
|
+
payload,
|
|
14294
|
+
rawPayload: {
|
|
14295
|
+
format: "hermes-message",
|
|
14296
|
+
message: row,
|
|
14297
|
+
...pending ? { tool_call: pending.toolCall.raw } : {}
|
|
14298
|
+
}
|
|
14299
|
+
};
|
|
14300
|
+
}
|
|
14301
|
+
function groupReusableToolEventIds(events) {
|
|
14302
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
14303
|
+
for (const event of events) {
|
|
14304
|
+
if (event.kind && event.kind !== "tool") {
|
|
14305
|
+
continue;
|
|
14306
|
+
}
|
|
14307
|
+
const key = normalizeToolTitle(event.title);
|
|
14308
|
+
if (!key) {
|
|
14309
|
+
continue;
|
|
14310
|
+
}
|
|
14311
|
+
grouped.set(key, [...grouped.get(key) ?? [], event.id]);
|
|
14312
|
+
}
|
|
14313
|
+
return grouped;
|
|
14314
|
+
}
|
|
14315
|
+
function consumeReusableToolEventId(grouped, pending, row) {
|
|
14316
|
+
const toolName = pending?.toolCall.name ?? readString12(row, "tool_name") ?? "tool";
|
|
14317
|
+
const key = normalizeToolTitle(humanizeToolName2(toolName));
|
|
14318
|
+
const ids = grouped.get(key);
|
|
14319
|
+
const id = ids?.shift();
|
|
14320
|
+
if (ids && ids.length === 0) {
|
|
14321
|
+
grouped.delete(key);
|
|
14322
|
+
}
|
|
14323
|
+
return id;
|
|
14324
|
+
}
|
|
14325
|
+
function humanizeToolName2(value) {
|
|
14326
|
+
const normalized = value.trim().replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").replace(/\s+/gu, " ");
|
|
14327
|
+
if (!normalized) {
|
|
14328
|
+
return "\u5DE5\u5177\u8C03\u7528";
|
|
14329
|
+
}
|
|
14330
|
+
return normalized.split(" ").map(
|
|
14331
|
+
(part) => part ? `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}` : part
|
|
14332
|
+
).join(" ");
|
|
14333
|
+
}
|
|
14334
|
+
function normalizeToolTitle(value) {
|
|
14335
|
+
return value.trim().toLowerCase().replace(/[\s_-]+/gu, "");
|
|
14336
|
+
}
|
|
14337
|
+
function isRunRow(row, lowerBoundSeconds) {
|
|
14338
|
+
if (lowerBoundSeconds === null) {
|
|
14339
|
+
return true;
|
|
14340
|
+
}
|
|
14341
|
+
const timestamp = readNumber3(row.timestamp);
|
|
14342
|
+
if (!timestamp) {
|
|
14343
|
+
return false;
|
|
14344
|
+
}
|
|
14345
|
+
const seconds = timestamp > 1e10 ? timestamp / 1e3 : timestamp;
|
|
14346
|
+
return seconds >= lowerBoundSeconds;
|
|
14347
|
+
}
|
|
14348
|
+
function hasUsableTimestamp(value) {
|
|
14349
|
+
return readNumber3(value) !== null;
|
|
14350
|
+
}
|
|
14351
|
+
function runStartedLowerBoundSeconds(value) {
|
|
14352
|
+
const millis = Date.parse(value);
|
|
14353
|
+
if (Number.isNaN(millis)) {
|
|
14354
|
+
return null;
|
|
14355
|
+
}
|
|
14356
|
+
return millis / 1e3 - 1;
|
|
14357
|
+
}
|
|
14358
|
+
function normalizeRole(value) {
|
|
14359
|
+
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
14360
|
+
}
|
|
14361
|
+
function normalizeContent3(value) {
|
|
14362
|
+
if (typeof value === "string") {
|
|
14363
|
+
return value;
|
|
14364
|
+
}
|
|
14365
|
+
if (Array.isArray(value)) {
|
|
14366
|
+
return value.map((item) => {
|
|
14367
|
+
if (typeof item === "string") {
|
|
14368
|
+
return item;
|
|
14369
|
+
}
|
|
14370
|
+
if (typeof item === "object" && item !== null) {
|
|
14371
|
+
return readString12(item, "text") ?? "";
|
|
14372
|
+
}
|
|
14373
|
+
return "";
|
|
14374
|
+
}).filter(Boolean).join("");
|
|
14375
|
+
}
|
|
14376
|
+
return "";
|
|
14377
|
+
}
|
|
14378
|
+
function parseJsonValue2(value) {
|
|
14379
|
+
if (typeof value !== "string") {
|
|
14380
|
+
return void 0;
|
|
14381
|
+
}
|
|
14382
|
+
const trimmed = value.trim();
|
|
14383
|
+
if (!trimmed) {
|
|
14384
|
+
return void 0;
|
|
14385
|
+
}
|
|
14386
|
+
try {
|
|
14387
|
+
return JSON.parse(trimmed);
|
|
14388
|
+
} catch {
|
|
14389
|
+
return void 0;
|
|
14390
|
+
}
|
|
14391
|
+
}
|
|
14392
|
+
function readTableColumns3(db, tableName) {
|
|
14393
|
+
try {
|
|
14394
|
+
const rows = db.prepare(`PRAGMA table_info(${quoteIdentifier2(tableName)})`).all();
|
|
14395
|
+
return new Set(
|
|
14396
|
+
rows.map((row) => typeof row.name === "string" ? row.name : "").filter(Boolean)
|
|
14397
|
+
);
|
|
14398
|
+
} catch {
|
|
14399
|
+
return /* @__PURE__ */ new Set();
|
|
14400
|
+
}
|
|
14401
|
+
}
|
|
14402
|
+
function quoteIdentifier2(value) {
|
|
14403
|
+
return `"${value.replaceAll('"', '""')}"`;
|
|
14404
|
+
}
|
|
14405
|
+
async function isFile2(filePath) {
|
|
14406
|
+
return stat12(filePath).then((value) => value.isFile()).catch((error) => {
|
|
14407
|
+
if (isNodeError13(error, "ENOENT")) {
|
|
14408
|
+
return false;
|
|
14409
|
+
}
|
|
14410
|
+
throw error;
|
|
14411
|
+
});
|
|
14412
|
+
}
|
|
14413
|
+
function isValidProfileName3(value) {
|
|
14414
|
+
return typeof value === "string" && /^[a-zA-Z0-9._-]{1,64}$/u.test(value);
|
|
14415
|
+
}
|
|
14416
|
+
function readString12(payload, key) {
|
|
14417
|
+
const value = payload[key];
|
|
14418
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
14419
|
+
}
|
|
14420
|
+
function readNumber3(value) {
|
|
14421
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
14422
|
+
return value;
|
|
14423
|
+
}
|
|
14424
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
14425
|
+
return null;
|
|
14426
|
+
}
|
|
14427
|
+
const numeric = Number(value);
|
|
14428
|
+
if (Number.isFinite(numeric)) {
|
|
14429
|
+
return numeric;
|
|
14430
|
+
}
|
|
14431
|
+
const millis = Date.parse(value);
|
|
14432
|
+
return Number.isNaN(millis) ? null : millis;
|
|
14433
|
+
}
|
|
14434
|
+
function toRecord10(value) {
|
|
14435
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
14436
|
+
}
|
|
14437
|
+
function isNodeError13(error, code) {
|
|
14438
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
14439
|
+
}
|
|
14440
|
+
|
|
14441
|
+
// src/conversations/run-tool-event-ids.ts
|
|
14442
|
+
import { createHash as createHash4 } from "crypto";
|
|
14443
|
+
var RunToolEventIdCoalescer = class {
|
|
14444
|
+
scope;
|
|
14445
|
+
ordinal = 0;
|
|
14446
|
+
pendingByToolKey = /* @__PURE__ */ new Map();
|
|
14447
|
+
startedByFingerprint = /* @__PURE__ */ new Map();
|
|
14448
|
+
completedByFingerprint = /* @__PURE__ */ new Map();
|
|
14449
|
+
constructor(options) {
|
|
14450
|
+
this.scope = `${options.runId}:${options.hermesRunId ?? ""}`;
|
|
14451
|
+
}
|
|
14452
|
+
normalize(event) {
|
|
14453
|
+
const type = readToolEventType(event);
|
|
14454
|
+
if (!type || hasStableToolEventId(event.payload)) {
|
|
14455
|
+
return event;
|
|
14456
|
+
}
|
|
14457
|
+
const toolKey = normalizeToolKey(readToolName(event.payload));
|
|
14458
|
+
if (type === "tool.started") {
|
|
14459
|
+
return withGeneratedToolEventId(
|
|
14460
|
+
event,
|
|
14461
|
+
this.idForStartedToolEvent(toolKey, event.payload)
|
|
14462
|
+
);
|
|
14463
|
+
}
|
|
14464
|
+
if (isTerminalToolEvent(type)) {
|
|
14465
|
+
return withGeneratedToolEventId(
|
|
14466
|
+
event,
|
|
14467
|
+
this.idForTerminalToolEvent(type, toolKey, event.payload)
|
|
14468
|
+
);
|
|
14469
|
+
}
|
|
14470
|
+
return event;
|
|
14471
|
+
}
|
|
14472
|
+
idForStartedToolEvent(toolKey, payload) {
|
|
14473
|
+
const fingerprint = startedToolEventFingerprint(toolKey, payload);
|
|
14474
|
+
if (fingerprint) {
|
|
14475
|
+
const existing = this.startedByFingerprint.get(fingerprint);
|
|
14476
|
+
if (existing) {
|
|
14477
|
+
return existing.id;
|
|
14478
|
+
}
|
|
14479
|
+
}
|
|
14480
|
+
const pending = {
|
|
14481
|
+
id: this.nextId(toolKey),
|
|
14482
|
+
toolKey
|
|
14483
|
+
};
|
|
14484
|
+
const pendingForTool = this.pendingByToolKey.get(toolKey) ?? [];
|
|
14485
|
+
pendingForTool.push(pending);
|
|
14486
|
+
this.pendingByToolKey.set(toolKey, pendingForTool);
|
|
14487
|
+
if (fingerprint) {
|
|
14488
|
+
this.startedByFingerprint.set(fingerprint, pending);
|
|
14489
|
+
}
|
|
14490
|
+
return pending.id;
|
|
14491
|
+
}
|
|
14492
|
+
idForTerminalToolEvent(type, toolKey, payload) {
|
|
14493
|
+
const pending = this.shiftPendingToolEvent(toolKey);
|
|
14494
|
+
const fingerprint = terminalToolEventFingerprint(type, toolKey, payload);
|
|
14495
|
+
if (pending) {
|
|
14496
|
+
this.completedByFingerprint.set(fingerprint, pending.id);
|
|
14497
|
+
return pending.id;
|
|
14498
|
+
}
|
|
14499
|
+
const existing = this.completedByFingerprint.get(fingerprint);
|
|
14500
|
+
if (existing) {
|
|
14501
|
+
return existing;
|
|
14502
|
+
}
|
|
14503
|
+
const id = this.nextId(toolKey);
|
|
14504
|
+
this.completedByFingerprint.set(fingerprint, id);
|
|
14505
|
+
return id;
|
|
14506
|
+
}
|
|
14507
|
+
shiftPendingToolEvent(toolKey) {
|
|
14508
|
+
const exact = this.shiftPendingByToolKey(toolKey);
|
|
14509
|
+
if (exact) {
|
|
14510
|
+
return exact;
|
|
14511
|
+
}
|
|
14512
|
+
for (const [candidateToolKey] of this.pendingByToolKey) {
|
|
14513
|
+
const pending = this.shiftPendingByToolKey(candidateToolKey);
|
|
14514
|
+
if (pending) {
|
|
14515
|
+
return pending;
|
|
14516
|
+
}
|
|
14517
|
+
}
|
|
14518
|
+
return void 0;
|
|
14519
|
+
}
|
|
14520
|
+
shiftPendingByToolKey(toolKey) {
|
|
14521
|
+
const pendingForTool = this.pendingByToolKey.get(toolKey);
|
|
14522
|
+
const pending = pendingForTool?.shift();
|
|
14523
|
+
if (pendingForTool && pendingForTool.length === 0) {
|
|
14524
|
+
this.pendingByToolKey.delete(toolKey);
|
|
14525
|
+
}
|
|
14526
|
+
return pending;
|
|
14527
|
+
}
|
|
14528
|
+
nextId(toolKey) {
|
|
14529
|
+
this.ordinal += 1;
|
|
14530
|
+
return `tool_${hashStableValue(`${this.scope}:${this.ordinal}:${toolKey}`)}`;
|
|
14531
|
+
}
|
|
14532
|
+
};
|
|
14533
|
+
function readToolEventType(event) {
|
|
14534
|
+
const type = readString13(event.payload, "type") ?? readString13(event.payload, "event") ?? event.payloadType;
|
|
14535
|
+
return type.startsWith("tool.") ? type : null;
|
|
14536
|
+
}
|
|
14537
|
+
function isTerminalToolEvent(type) {
|
|
14538
|
+
return type === "tool.completed" || type === "tool.failed" || type === "tool.error";
|
|
14539
|
+
}
|
|
14540
|
+
function hasStableToolEventId(payload) {
|
|
14541
|
+
const tool = toRecord11(payload.tool);
|
|
14542
|
+
const call = toRecord11(payload.tool_call ?? payload.toolCall);
|
|
14543
|
+
const fn = toRecord11(call.function ?? payload.function);
|
|
14544
|
+
return Boolean(
|
|
14545
|
+
readString13(payload, "tool_call_id") ?? readString13(payload, "toolCallId") ?? readString13(payload, "call_id") ?? readString13(payload, "id") ?? readString13(tool, "id") ?? readString13(call, "id") ?? readString13(fn, "id")
|
|
14546
|
+
);
|
|
14547
|
+
}
|
|
14548
|
+
function readToolName(payload) {
|
|
14549
|
+
const tool = toRecord11(payload.tool);
|
|
14550
|
+
const call = toRecord11(payload.tool_call ?? payload.toolCall);
|
|
14551
|
+
const fn = toRecord11(call.function ?? payload.function);
|
|
14552
|
+
return readString13(payload, "tool_name") ?? readString13(payload, "toolName") ?? readString13(payload, "name") ?? readString13(payload, "tool") ?? readString13(tool, "name") ?? readString13(call, "name") ?? readString13(fn, "name") ?? "tool";
|
|
14553
|
+
}
|
|
14554
|
+
function withGeneratedToolEventId(event, id) {
|
|
14555
|
+
return {
|
|
14556
|
+
...event,
|
|
14557
|
+
payload: {
|
|
14558
|
+
...event.payload,
|
|
14559
|
+
id,
|
|
14560
|
+
link_tool_event_id: id,
|
|
14561
|
+
link_generated_tool_event_id: true
|
|
14562
|
+
}
|
|
14563
|
+
};
|
|
14564
|
+
}
|
|
14565
|
+
function startedToolEventFingerprint(toolKey, payload) {
|
|
14566
|
+
const timestamp = payload.timestamp ?? payload.started_at ?? payload.created_at;
|
|
14567
|
+
if (timestamp === void 0 || timestamp === null) {
|
|
14568
|
+
return null;
|
|
14569
|
+
}
|
|
14570
|
+
return stableStringify2({
|
|
14571
|
+
toolKey,
|
|
14572
|
+
timestamp,
|
|
14573
|
+
preview: payload.preview,
|
|
14574
|
+
arguments: payload.arguments ?? payload.args ?? payload.input
|
|
14575
|
+
});
|
|
14576
|
+
}
|
|
14577
|
+
function terminalToolEventFingerprint(type, toolKey, payload) {
|
|
14578
|
+
return stableStringify2({
|
|
14579
|
+
type,
|
|
14580
|
+
toolKey,
|
|
14581
|
+
timestamp: payload.timestamp ?? payload.completed_at ?? payload.created_at,
|
|
14582
|
+
duration: payload.duration,
|
|
14583
|
+
error: payload.error,
|
|
14584
|
+
output: payload.output ?? payload.content ?? payload.result ?? payload.message ?? null
|
|
14585
|
+
});
|
|
14586
|
+
}
|
|
14587
|
+
function normalizeToolKey(value) {
|
|
14588
|
+
return value.trim().toLowerCase().replace(/[\s-]+/gu, "_") || "tool";
|
|
14589
|
+
}
|
|
14590
|
+
function stableStringify2(value) {
|
|
14591
|
+
try {
|
|
14592
|
+
return JSON.stringify(value, (_key, data) => {
|
|
14593
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
14594
|
+
return data;
|
|
14595
|
+
}
|
|
14596
|
+
return Object.fromEntries(
|
|
14597
|
+
Object.entries(data).sort(
|
|
14598
|
+
([left], [right]) => left.localeCompare(right)
|
|
14599
|
+
)
|
|
14600
|
+
);
|
|
14601
|
+
});
|
|
14602
|
+
} catch {
|
|
14603
|
+
return String(value);
|
|
14604
|
+
}
|
|
14605
|
+
}
|
|
14606
|
+
function hashStableValue(value) {
|
|
14607
|
+
return createHash4("sha256").update(value).digest("hex").slice(0, 16);
|
|
14608
|
+
}
|
|
14609
|
+
function readString13(payload, key) {
|
|
14610
|
+
const value = payload[key];
|
|
14611
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
14612
|
+
}
|
|
14613
|
+
function toRecord11(value) {
|
|
14614
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
14615
|
+
}
|
|
14616
|
+
|
|
13946
14617
|
// src/conversations/stream-events.ts
|
|
13947
14618
|
function normalizeHermesStreamEvent(event) {
|
|
13948
14619
|
const responseEvent = normalizeHermesResponseEvent(event);
|
|
@@ -13963,8 +14634,8 @@ function normalizeHermesStreamEvent(event) {
|
|
|
13963
14634
|
};
|
|
13964
14635
|
}
|
|
13965
14636
|
if (event.eventName === "hermes.tool.progress") {
|
|
13966
|
-
const toolName =
|
|
13967
|
-
const preview =
|
|
14637
|
+
const toolName = readString14(event.payload, "tool") ?? readString14(event.payload, "name") ?? "tool";
|
|
14638
|
+
const preview = readString14(event.payload, "label") ?? readString14(event.payload, "preview") ?? toolName;
|
|
13968
14639
|
return {
|
|
13969
14640
|
...event,
|
|
13970
14641
|
payloadType: "tool.started",
|
|
@@ -14039,12 +14710,12 @@ function normalizeHermesResponseEvent(event) {
|
|
|
14039
14710
|
}
|
|
14040
14711
|
}
|
|
14041
14712
|
function normalizeResponseOutputItemAdded(event) {
|
|
14042
|
-
const item =
|
|
14043
|
-
if (
|
|
14713
|
+
const item = toRecord12(event.payload.item);
|
|
14714
|
+
if (readString14(item, "type") !== "function_call") {
|
|
14044
14715
|
return null;
|
|
14045
14716
|
}
|
|
14046
|
-
const toolName =
|
|
14047
|
-
const argumentsValue =
|
|
14717
|
+
const toolName = readString14(item, "name") ?? "tool";
|
|
14718
|
+
const argumentsValue = parseJsonValue3(item.arguments) ?? item.arguments;
|
|
14048
14719
|
return {
|
|
14049
14720
|
...event,
|
|
14050
14721
|
payloadType: "tool.started",
|
|
@@ -14053,16 +14724,16 @@ function normalizeResponseOutputItemAdded(event) {
|
|
|
14053
14724
|
tool: toolName,
|
|
14054
14725
|
tool_name: toolName,
|
|
14055
14726
|
name: toolName,
|
|
14056
|
-
tool_call_id:
|
|
14727
|
+
tool_call_id: readString14(item, "call_id") ?? readString14(item, "id"),
|
|
14057
14728
|
arguments: argumentsValue,
|
|
14058
14729
|
preview: toolName,
|
|
14059
|
-
response_item_id:
|
|
14730
|
+
response_item_id: readString14(item, "id") ?? void 0
|
|
14060
14731
|
}
|
|
14061
14732
|
};
|
|
14062
14733
|
}
|
|
14063
14734
|
function normalizeResponseOutputItemDone(event) {
|
|
14064
|
-
const item =
|
|
14065
|
-
if (
|
|
14735
|
+
const item = toRecord12(event.payload.item);
|
|
14736
|
+
if (readString14(item, "type") === "message") {
|
|
14066
14737
|
const delta = extractResponseAssistantText({ output: [item] });
|
|
14067
14738
|
return delta ? {
|
|
14068
14739
|
...event,
|
|
@@ -14070,51 +14741,51 @@ function normalizeResponseOutputItemDone(event) {
|
|
|
14070
14741
|
payload: { type: "message.delta", delta }
|
|
14071
14742
|
} : null;
|
|
14072
14743
|
}
|
|
14073
|
-
if (
|
|
14744
|
+
if (readString14(item, "type") !== "function_call_output") {
|
|
14074
14745
|
return null;
|
|
14075
14746
|
}
|
|
14076
14747
|
const output = readResponseItemOutput(item.output);
|
|
14077
|
-
const parsedOutput =
|
|
14748
|
+
const parsedOutput = parseJsonValue3(output);
|
|
14078
14749
|
return {
|
|
14079
14750
|
...event,
|
|
14080
14751
|
payloadType: "tool.completed",
|
|
14081
14752
|
payload: {
|
|
14082
14753
|
type: "tool.completed",
|
|
14083
|
-
tool_call_id:
|
|
14084
|
-
status:
|
|
14754
|
+
tool_call_id: readString14(item, "call_id") ?? readString14(item, "id"),
|
|
14755
|
+
status: readString14(item, "status") ?? "completed",
|
|
14085
14756
|
output,
|
|
14086
14757
|
content: output,
|
|
14087
14758
|
result: parsedOutput ?? output,
|
|
14088
|
-
response_item_id:
|
|
14759
|
+
response_item_id: readString14(item, "id") ?? void 0
|
|
14089
14760
|
}
|
|
14090
14761
|
};
|
|
14091
14762
|
}
|
|
14092
14763
|
function normalizeResponseCompleted(event) {
|
|
14093
|
-
const response =
|
|
14764
|
+
const response = toRecord12(event.payload.response);
|
|
14094
14765
|
return {
|
|
14095
14766
|
...event,
|
|
14096
14767
|
payloadType: "run.completed",
|
|
14097
14768
|
payload: {
|
|
14098
14769
|
type: "run.completed",
|
|
14099
|
-
response_id:
|
|
14100
|
-
usage:
|
|
14770
|
+
response_id: readString14(response, "id") ?? readString14(event.payload, "id"),
|
|
14771
|
+
usage: toRecord12(response.usage),
|
|
14101
14772
|
response
|
|
14102
14773
|
}
|
|
14103
14774
|
};
|
|
14104
14775
|
}
|
|
14105
14776
|
function normalizeResponseFailed(event) {
|
|
14106
|
-
const response =
|
|
14107
|
-
const error =
|
|
14777
|
+
const response = toRecord12(event.payload.response);
|
|
14778
|
+
const error = toRecord12(response.error);
|
|
14108
14779
|
return {
|
|
14109
14780
|
...event,
|
|
14110
14781
|
payloadType: "run.failed",
|
|
14111
14782
|
payload: {
|
|
14112
14783
|
type: "run.failed",
|
|
14113
|
-
response_id:
|
|
14784
|
+
response_id: readString14(response, "id") ?? readString14(event.payload, "id"),
|
|
14114
14785
|
error: {
|
|
14115
|
-
message:
|
|
14786
|
+
message: readString14(error, "message") ?? readString14(event.payload, "message") ?? "Hermes run failed"
|
|
14116
14787
|
},
|
|
14117
|
-
usage:
|
|
14788
|
+
usage: toRecord12(response.usage),
|
|
14118
14789
|
response
|
|
14119
14790
|
}
|
|
14120
14791
|
};
|
|
@@ -14138,8 +14809,8 @@ function readErrorMessage2(payload) {
|
|
|
14138
14809
|
if (typeof payload.error === "string" && payload.error.trim()) {
|
|
14139
14810
|
return payload.error.trim();
|
|
14140
14811
|
}
|
|
14141
|
-
const error =
|
|
14142
|
-
return
|
|
14812
|
+
const error = toRecord12(payload.error);
|
|
14813
|
+
return readString14(error, "message") ?? readString14(payload, "message");
|
|
14143
14814
|
}
|
|
14144
14815
|
function readDelta(payload) {
|
|
14145
14816
|
return readText2(payload, "delta") ?? readText2(payload, "text") ?? readText2(payload, "content");
|
|
@@ -14148,8 +14819,12 @@ function extractResponseAssistantText(value) {
|
|
|
14148
14819
|
if (typeof value === "string") {
|
|
14149
14820
|
return value.trim().length > 0 ? value : null;
|
|
14150
14821
|
}
|
|
14151
|
-
const payload =
|
|
14152
|
-
const response =
|
|
14822
|
+
const payload = toRecord12(value);
|
|
14823
|
+
const response = toRecord12(payload.response ?? value);
|
|
14824
|
+
const directOutput = readText2(response, "output");
|
|
14825
|
+
if (directOutput?.trim()) {
|
|
14826
|
+
return directOutput;
|
|
14827
|
+
}
|
|
14153
14828
|
const directText = readText2(response, "output_text");
|
|
14154
14829
|
if (directText?.trim()) {
|
|
14155
14830
|
return directText;
|
|
@@ -14198,15 +14873,15 @@ function isTopLevelErrorEvent(event) {
|
|
|
14198
14873
|
}
|
|
14199
14874
|
function readChatCompletionDelta(payload) {
|
|
14200
14875
|
const choice = readFirstChoice(payload);
|
|
14201
|
-
const delta =
|
|
14876
|
+
const delta = toRecord12(choice.delta);
|
|
14202
14877
|
return readText2(delta, "content");
|
|
14203
14878
|
}
|
|
14204
14879
|
function readChatCompletionFinishReason(payload) {
|
|
14205
14880
|
const choice = readFirstChoice(payload);
|
|
14206
|
-
return
|
|
14881
|
+
return readString14(choice, "finish_reason") ?? readString14(choice, "finishReason");
|
|
14207
14882
|
}
|
|
14208
14883
|
function readChatCompletionUsage(payload) {
|
|
14209
|
-
const usage =
|
|
14884
|
+
const usage = toRecord12(payload.usage);
|
|
14210
14885
|
const input = readInteger2(usage, "prompt_tokens") ?? readInteger2(usage, "input_tokens");
|
|
14211
14886
|
const output = readInteger2(usage, "completion_tokens") ?? readInteger2(usage, "output_tokens");
|
|
14212
14887
|
const total = readInteger2(usage, "total_tokens");
|
|
@@ -14235,15 +14910,15 @@ function readFirstChoice(payload) {
|
|
|
14235
14910
|
if (!Array.isArray(choices)) {
|
|
14236
14911
|
return {};
|
|
14237
14912
|
}
|
|
14238
|
-
return
|
|
14913
|
+
return toRecord12(choices[0]);
|
|
14239
14914
|
}
|
|
14240
14915
|
function readAssistantTextFromChoices(payload) {
|
|
14241
14916
|
const choices = payload.choices;
|
|
14242
14917
|
if (!Array.isArray(choices)) {
|
|
14243
14918
|
return null;
|
|
14244
14919
|
}
|
|
14245
|
-
const messages = choices.map(
|
|
14246
|
-
const role =
|
|
14920
|
+
const messages = choices.map(toRecord12).map((choice) => toRecord12(choice.message ?? choice.delta)).filter((message) => {
|
|
14921
|
+
const role = readString14(message, "role");
|
|
14247
14922
|
return !role || role === "assistant";
|
|
14248
14923
|
}).map(readResponseMessageText).filter((text) => Boolean(text?.trim()));
|
|
14249
14924
|
return messages.length > 0 ? messages.join("\n\n") : null;
|
|
@@ -14259,7 +14934,7 @@ function readInteger2(payload, key) {
|
|
|
14259
14934
|
}
|
|
14260
14935
|
return void 0;
|
|
14261
14936
|
}
|
|
14262
|
-
function
|
|
14937
|
+
function readString14(payload, key) {
|
|
14263
14938
|
const value = payload[key];
|
|
14264
14939
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
14265
14940
|
}
|
|
@@ -14271,9 +14946,9 @@ function readResponseOutputItemText(value) {
|
|
|
14271
14946
|
if (typeof value === "string") {
|
|
14272
14947
|
return value;
|
|
14273
14948
|
}
|
|
14274
|
-
const item =
|
|
14275
|
-
const type =
|
|
14276
|
-
const role =
|
|
14949
|
+
const item = toRecord12(value);
|
|
14950
|
+
const type = readString14(item, "type");
|
|
14951
|
+
const role = readString14(item, "role");
|
|
14277
14952
|
if (type && type !== "message" && type !== "output_text" && type !== "text") {
|
|
14278
14953
|
return null;
|
|
14279
14954
|
}
|
|
@@ -14291,15 +14966,15 @@ function readResponseContentText(value) {
|
|
|
14291
14966
|
return value;
|
|
14292
14967
|
}
|
|
14293
14968
|
if (!Array.isArray(value)) {
|
|
14294
|
-
const record =
|
|
14969
|
+
const record = toRecord12(value);
|
|
14295
14970
|
return readText2(record, "text") ?? readText2(record, "content") ?? readText2(record, "output_text") ?? readText2(record, "refusal");
|
|
14296
14971
|
}
|
|
14297
14972
|
const chunks = value.map((partValue) => {
|
|
14298
14973
|
if (typeof partValue === "string") {
|
|
14299
14974
|
return partValue;
|
|
14300
14975
|
}
|
|
14301
|
-
const part =
|
|
14302
|
-
const type =
|
|
14976
|
+
const part = toRecord12(partValue);
|
|
14977
|
+
const type = readString14(part, "type");
|
|
14303
14978
|
if (type && !isVisibleResponseTextPart(type)) {
|
|
14304
14979
|
return null;
|
|
14305
14980
|
}
|
|
@@ -14318,10 +14993,10 @@ function readResponseItemOutput(value) {
|
|
|
14318
14993
|
if (!Array.isArray(value)) {
|
|
14319
14994
|
return stringifyJsonValue(value);
|
|
14320
14995
|
}
|
|
14321
|
-
const text = value.map(
|
|
14996
|
+
const text = value.map(toRecord12).map((part) => readText2(part, "text") ?? readText2(part, "content") ?? "").join("");
|
|
14322
14997
|
return text || stringifyJsonValue(value);
|
|
14323
14998
|
}
|
|
14324
|
-
function
|
|
14999
|
+
function parseJsonValue3(value) {
|
|
14325
15000
|
if (typeof value !== "string" || !value.trim()) {
|
|
14326
15001
|
return null;
|
|
14327
15002
|
}
|
|
@@ -14344,11 +15019,14 @@ function stringifyJsonValue(value) {
|
|
|
14344
15019
|
return String(value);
|
|
14345
15020
|
}
|
|
14346
15021
|
}
|
|
14347
|
-
function
|
|
15022
|
+
function toRecord12(value) {
|
|
14348
15023
|
return typeof value === "object" && value !== null ? value : {};
|
|
14349
15024
|
}
|
|
14350
15025
|
|
|
14351
15026
|
// src/conversations/run-lifecycle.ts
|
|
15027
|
+
var RUN_STATUS_RECOVERY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
15028
|
+
var RUN_STATUS_RECOVERY_INITIAL_DELAY_MS = 500;
|
|
15029
|
+
var RUN_STATUS_RECOVERY_MAX_DELAY_MS = 2500;
|
|
14352
15030
|
var ConversationRunLifecycle = class {
|
|
14353
15031
|
constructor(deps) {
|
|
14354
15032
|
this.deps = deps;
|
|
@@ -14363,6 +15041,7 @@ var ConversationRunLifecycle = class {
|
|
|
14363
15041
|
const controller = new AbortController();
|
|
14364
15042
|
this.deps.activeRunControllers.set(runId, { conversationId, controller });
|
|
14365
15043
|
try {
|
|
15044
|
+
const backend = resolveConversationRunBackend();
|
|
14366
15045
|
const hermesSessionId = await readHermesCompressionTip(
|
|
14367
15046
|
run.hermes_session_id,
|
|
14368
15047
|
this.deps.paths,
|
|
@@ -14407,7 +15086,7 @@ var ConversationRunLifecycle = class {
|
|
|
14407
15086
|
fallbackInput: input,
|
|
14408
15087
|
snapshot
|
|
14409
15088
|
});
|
|
14410
|
-
const previousResponseId = findPreviousHermesResponseId(snapshot, run);
|
|
15089
|
+
const previousResponseId = backend === "responses" ? findPreviousHermesResponseId(snapshot, run) : void 0;
|
|
14411
15090
|
if (previousResponseId) {
|
|
14412
15091
|
await this.updateRun(conversationId, runId, {
|
|
14413
15092
|
previous_response_id: previousResponseId
|
|
@@ -14435,99 +15114,98 @@ var ConversationRunLifecycle = class {
|
|
|
14435
15114
|
if (estimatedUsage) {
|
|
14436
15115
|
await this.updateRun(conversationId, runId, { usage: estimatedUsage });
|
|
14437
15116
|
}
|
|
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
|
-
}
|
|
15117
|
+
const sessionKey = await this.buildHermesSessionKey(
|
|
15118
|
+
conversationId,
|
|
15119
|
+
run.profile ?? "default"
|
|
14456
15120
|
);
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
15121
|
+
if (backend === "responses") {
|
|
15122
|
+
const response = await streamHermesResponses(
|
|
15123
|
+
{
|
|
15124
|
+
input: resolvedInput,
|
|
15125
|
+
instructions,
|
|
15126
|
+
session_id: hermesSessionId,
|
|
15127
|
+
session_key: sessionKey,
|
|
15128
|
+
model: run.model,
|
|
15129
|
+
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
15130
|
+
...conversationHistory.messages.length > 0 ? { conversation_history: conversationHistory.messages } : {}
|
|
15131
|
+
},
|
|
15132
|
+
{
|
|
15133
|
+
logger: this.deps.logger,
|
|
15134
|
+
profileName: run.profile,
|
|
15135
|
+
signal: controller.signal
|
|
15136
|
+
}
|
|
14463
15137
|
);
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
|
|
14467
|
-
await this.deps.withConversationLock(
|
|
15138
|
+
const responseSessionId = response.headers.get("x-hermes-session-id")?.trim();
|
|
15139
|
+
if (responseSessionId) {
|
|
15140
|
+
await this.rememberRunHermesSessionId(
|
|
14468
15141
|
conversationId,
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
reason: "cancelled by app"
|
|
14472
|
-
})
|
|
15142
|
+
runId,
|
|
15143
|
+
responseSessionId
|
|
14473
15144
|
);
|
|
14474
|
-
return;
|
|
14475
|
-
}
|
|
14476
|
-
if (!await this.deps.isConversationRunnable(conversationId)) {
|
|
14477
|
-
return;
|
|
14478
15145
|
}
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
|
|
14484
|
-
|
|
14485
|
-
|
|
14486
|
-
|
|
14487
|
-
|
|
14488
|
-
|
|
14489
|
-
|
|
15146
|
+
await this.consumeHermesEventStream({
|
|
15147
|
+
backend,
|
|
15148
|
+
conversationId,
|
|
15149
|
+
runId,
|
|
15150
|
+
response,
|
|
15151
|
+
controller,
|
|
15152
|
+
profileName: run.profile,
|
|
15153
|
+
cronJobIdsBeforeRun
|
|
15154
|
+
});
|
|
15155
|
+
} else {
|
|
15156
|
+
const hermesRun = await createHermesRun(
|
|
15157
|
+
{
|
|
15158
|
+
input: resolvedInput,
|
|
15159
|
+
instructions,
|
|
15160
|
+
session_id: hermesSessionId,
|
|
15161
|
+
session_key: sessionKey,
|
|
15162
|
+
model: run.model,
|
|
15163
|
+
...conversationHistory.messages.length > 0 ? { conversation_history: conversationHistory.messages } : {}
|
|
15164
|
+
},
|
|
15165
|
+
{
|
|
15166
|
+
logger: this.deps.logger,
|
|
15167
|
+
profileName: run.profile,
|
|
15168
|
+
signal: controller.signal
|
|
14490
15169
|
}
|
|
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;
|
|
15170
|
+
);
|
|
15171
|
+
await this.updateRun(conversationId, runId, {
|
|
15172
|
+
hermes_run_id: hermesRun.run_id
|
|
15173
|
+
});
|
|
15174
|
+
const response = await streamHermesRunEvents(hermesRun.run_id, {
|
|
15175
|
+
logger: this.deps.logger,
|
|
15176
|
+
profileName: run.profile,
|
|
15177
|
+
signal: controller.signal
|
|
15178
|
+
}).catch(async (error) => {
|
|
15179
|
+
if (controller.signal.aborted) {
|
|
15180
|
+
throw error;
|
|
14514
15181
|
}
|
|
14515
|
-
await this.
|
|
14516
|
-
|
|
14517
|
-
return;
|
|
14518
|
-
}
|
|
14519
|
-
if (event.payloadType === "run.failed") {
|
|
14520
|
-
await this.importMediaReferencesForEvent(conversationId, runId, event);
|
|
14521
|
-
await this.failRun(
|
|
15182
|
+
await this.recoverRunAfterEventStreamOpenFailure({
|
|
15183
|
+
backend,
|
|
14522
15184
|
conversationId,
|
|
14523
15185
|
runId,
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
15186
|
+
hermesRunId: hermesRun.run_id,
|
|
15187
|
+
controller,
|
|
15188
|
+
profileName: run.profile,
|
|
15189
|
+
cronJobIdsBeforeRun,
|
|
15190
|
+
error
|
|
15191
|
+
});
|
|
15192
|
+
return null;
|
|
15193
|
+
});
|
|
15194
|
+
if (!response) {
|
|
14527
15195
|
return;
|
|
14528
15196
|
}
|
|
14529
|
-
await this.
|
|
15197
|
+
await this.consumeHermesEventStream({
|
|
15198
|
+
backend,
|
|
15199
|
+
conversationId,
|
|
15200
|
+
runId,
|
|
15201
|
+
response,
|
|
15202
|
+
controller,
|
|
15203
|
+
profileName: run.profile,
|
|
15204
|
+
hermesRunId: hermesRun.run_id,
|
|
15205
|
+
cronJobIdsBeforeRun
|
|
15206
|
+
});
|
|
14530
15207
|
}
|
|
15208
|
+
} catch (error) {
|
|
14531
15209
|
if (controller.signal.aborted) {
|
|
14532
15210
|
await this.deps.withConversationLock(
|
|
14533
15211
|
conversationId,
|
|
@@ -14538,60 +15216,381 @@ var ConversationRunLifecycle = class {
|
|
|
14538
15216
|
);
|
|
14539
15217
|
return;
|
|
14540
15218
|
}
|
|
14541
|
-
|
|
14542
|
-
|
|
14543
|
-
|
|
15219
|
+
throw error;
|
|
15220
|
+
} finally {
|
|
15221
|
+
if (this.deps.activeRunControllers.get(runId)?.controller === controller) {
|
|
15222
|
+
this.deps.activeRunControllers.delete(runId);
|
|
15223
|
+
}
|
|
15224
|
+
}
|
|
15225
|
+
}
|
|
15226
|
+
async cancelRun(conversationId, runId, options) {
|
|
15227
|
+
return this.deps.withConversationLock(
|
|
15228
|
+
conversationId,
|
|
15229
|
+
() => this.cancelRunLocked(conversationId, runId, options)
|
|
15230
|
+
);
|
|
15231
|
+
}
|
|
15232
|
+
async failRun(conversationId, runId, message, source) {
|
|
15233
|
+
return this.deps.withConversationLock(
|
|
15234
|
+
conversationId,
|
|
15235
|
+
() => this.failRunLocked(conversationId, runId, message, source)
|
|
15236
|
+
);
|
|
15237
|
+
}
|
|
15238
|
+
async findConversationIdForRun(runId) {
|
|
15239
|
+
const entries = await readdirWithDirs(this.deps.paths.conversationsDir);
|
|
15240
|
+
for (const entry of entries) {
|
|
15241
|
+
if (!entry.isDirectory()) {
|
|
15242
|
+
continue;
|
|
15243
|
+
}
|
|
15244
|
+
const snapshot = await this.deps.readSnapshot(entry.name).catch(() => null);
|
|
15245
|
+
if (snapshot?.runs.some((run) => run.id === runId)) {
|
|
15246
|
+
return entry.name;
|
|
15247
|
+
}
|
|
15248
|
+
}
|
|
15249
|
+
return void 0;
|
|
15250
|
+
}
|
|
15251
|
+
async consumeHermesEventStream(input) {
|
|
15252
|
+
let streamError;
|
|
15253
|
+
const iterator = parseSseResponse(input.response)[Symbol.asyncIterator]();
|
|
15254
|
+
const toolEventIds = input.backend === "runs" ? new RunToolEventIdCoalescer({
|
|
15255
|
+
runId: input.runId,
|
|
15256
|
+
hermesRunId: input.hermesRunId
|
|
15257
|
+
}) : null;
|
|
15258
|
+
while (true) {
|
|
15259
|
+
let next;
|
|
15260
|
+
try {
|
|
15261
|
+
next = await iterator.next();
|
|
15262
|
+
} catch (error) {
|
|
15263
|
+
if (input.controller.signal.aborted) {
|
|
15264
|
+
await this.cancelRunAfterAbort(input.conversationId, input.runId);
|
|
15265
|
+
return;
|
|
15266
|
+
}
|
|
15267
|
+
streamError = error;
|
|
15268
|
+
await this.deps.logger.warn("hermes_event_stream_interrupted", {
|
|
15269
|
+
backend: input.backend,
|
|
15270
|
+
conversation_id: input.conversationId,
|
|
15271
|
+
run_id: input.runId,
|
|
15272
|
+
...input.hermesRunId ? { hermes_run_id: input.hermesRunId } : {},
|
|
15273
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15274
|
+
});
|
|
15275
|
+
break;
|
|
15276
|
+
}
|
|
15277
|
+
if (next.done) {
|
|
15278
|
+
break;
|
|
15279
|
+
}
|
|
15280
|
+
if (input.controller.signal.aborted) {
|
|
15281
|
+
await closeSseIterator(iterator);
|
|
15282
|
+
await this.cancelRunAfterAbort(input.conversationId, input.runId);
|
|
15283
|
+
return;
|
|
15284
|
+
}
|
|
15285
|
+
if (!await this.deps.isConversationRunnable(input.conversationId)) {
|
|
15286
|
+
await closeSseIterator(iterator);
|
|
15287
|
+
return;
|
|
15288
|
+
}
|
|
15289
|
+
const event = normalizeHermesStreamEvent(next.value);
|
|
15290
|
+
if (!event) {
|
|
15291
|
+
continue;
|
|
15292
|
+
}
|
|
15293
|
+
const normalizedEvent = toolEventIds?.normalize(event) ?? event;
|
|
15294
|
+
const handled = await this.handleNormalizedHermesEvent({
|
|
15295
|
+
...input,
|
|
15296
|
+
event: normalizedEvent
|
|
15297
|
+
});
|
|
15298
|
+
if (handled) {
|
|
15299
|
+
await closeSseIterator(iterator);
|
|
15300
|
+
return;
|
|
15301
|
+
}
|
|
15302
|
+
}
|
|
15303
|
+
if (input.controller.signal.aborted) {
|
|
15304
|
+
await this.cancelRunAfterAbort(input.conversationId, input.runId);
|
|
15305
|
+
return;
|
|
15306
|
+
}
|
|
15307
|
+
if (!await this.deps.isConversationRunnable(input.conversationId)) {
|
|
15308
|
+
return;
|
|
15309
|
+
}
|
|
15310
|
+
const recoveredEvent = input.backend === "runs" && input.hermesRunId ? await this.recoverRunTerminalEvent({
|
|
15311
|
+
conversationId: input.conversationId,
|
|
15312
|
+
runId: input.runId,
|
|
15313
|
+
hermesRunId: input.hermesRunId,
|
|
15314
|
+
profileName: input.profileName,
|
|
15315
|
+
signal: input.controller.signal
|
|
15316
|
+
}) : null;
|
|
15317
|
+
if (recoveredEvent) {
|
|
15318
|
+
const handled = await this.handleNormalizedHermesEvent({
|
|
15319
|
+
...input,
|
|
15320
|
+
event: recoveredEvent
|
|
15321
|
+
});
|
|
15322
|
+
if (handled) {
|
|
15323
|
+
return;
|
|
15324
|
+
}
|
|
15325
|
+
}
|
|
15326
|
+
if (input.controller.signal.aborted) {
|
|
15327
|
+
await this.cancelRunAfterAbort(input.conversationId, input.runId);
|
|
15328
|
+
return;
|
|
15329
|
+
}
|
|
15330
|
+
if (input.backend === "responses" && !streamError && await this.runHasAssistantOutput(input.conversationId, input.runId)) {
|
|
15331
|
+
await this.completeRun(input.conversationId, input.runId);
|
|
15332
|
+
} else {
|
|
15333
|
+
await this.failRun(
|
|
15334
|
+
input.conversationId,
|
|
15335
|
+
input.runId,
|
|
15336
|
+
await this.buildEmptyHermesResponseMessage({
|
|
15337
|
+
source: streamError ? "stream-error" : "stream-ended-without-terminal-event",
|
|
15338
|
+
...streamError ? { eventError: formatUnknownErrorMessage(streamError) } : {}
|
|
15339
|
+
})
|
|
15340
|
+
);
|
|
15341
|
+
}
|
|
15342
|
+
this.deps.scheduleTitleRefresh(input.conversationId);
|
|
15343
|
+
}
|
|
15344
|
+
async handleNormalizedHermesEvent(input) {
|
|
15345
|
+
if (input.event.payloadType === "run.completed") {
|
|
15346
|
+
if (input.cronJobIdsBeforeRun) {
|
|
15347
|
+
await this.bindNewCronJobsCreatedByRun({
|
|
15348
|
+
profileName: input.profileName,
|
|
15349
|
+
conversationId: input.conversationId,
|
|
15350
|
+
beforeJobIds: input.cronJobIdsBeforeRun
|
|
15351
|
+
});
|
|
15352
|
+
}
|
|
15353
|
+
await this.deps.syncCronDeliveries().catch((error) => {
|
|
15354
|
+
void this.deps.logger.warn("cron_link_delivery_sync_failed", {
|
|
15355
|
+
conversation_id: input.conversationId,
|
|
15356
|
+
run_id: input.runId,
|
|
15357
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15358
|
+
});
|
|
15359
|
+
});
|
|
15360
|
+
if (input.backend === "runs" && isRunToolResultCompensationEnabled()) {
|
|
15361
|
+
await this.enrichRunFromHermesTranscript({
|
|
15362
|
+
conversationId: input.conversationId,
|
|
15363
|
+
runId: input.runId,
|
|
15364
|
+
profileName: input.profileName
|
|
15365
|
+
});
|
|
15366
|
+
}
|
|
15367
|
+
await this.appendAssistantTextFromCompletedResponse(
|
|
15368
|
+
input.conversationId,
|
|
15369
|
+
input.runId,
|
|
15370
|
+
input.event
|
|
15371
|
+
);
|
|
15372
|
+
await this.importMediaReferencesForEvent(
|
|
15373
|
+
input.conversationId,
|
|
15374
|
+
input.runId,
|
|
15375
|
+
input.event
|
|
15376
|
+
);
|
|
15377
|
+
if (!await this.runHasAssistantOutput(input.conversationId, input.runId)) {
|
|
14544
15378
|
await this.failRun(
|
|
14545
|
-
conversationId,
|
|
14546
|
-
runId,
|
|
15379
|
+
input.conversationId,
|
|
15380
|
+
input.runId,
|
|
14547
15381
|
await this.buildEmptyHermesResponseMessage({
|
|
14548
|
-
source: "
|
|
14549
|
-
})
|
|
15382
|
+
source: "final-empty-response"
|
|
15383
|
+
}),
|
|
15384
|
+
input.event
|
|
14550
15385
|
);
|
|
15386
|
+
return true;
|
|
14551
15387
|
}
|
|
14552
|
-
this.
|
|
14553
|
-
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
15388
|
+
await this.completeRun(input.conversationId, input.runId, input.event);
|
|
15389
|
+
this.deps.scheduleTitleRefresh(input.conversationId);
|
|
15390
|
+
return true;
|
|
15391
|
+
}
|
|
15392
|
+
if (input.event.payloadType === "run.failed") {
|
|
15393
|
+
if (input.backend === "runs" && isRunToolResultCompensationEnabled()) {
|
|
15394
|
+
await this.enrichRunFromHermesTranscript({
|
|
15395
|
+
conversationId: input.conversationId,
|
|
15396
|
+
runId: input.runId,
|
|
15397
|
+
profileName: input.profileName
|
|
15398
|
+
});
|
|
14563
15399
|
}
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
15400
|
+
await this.importMediaReferencesForEvent(
|
|
15401
|
+
input.conversationId,
|
|
15402
|
+
input.runId,
|
|
15403
|
+
input.event
|
|
15404
|
+
);
|
|
15405
|
+
await this.failRun(
|
|
15406
|
+
input.conversationId,
|
|
15407
|
+
input.runId,
|
|
15408
|
+
readErrorMessage2(input.event.payload) ?? "Hermes run failed",
|
|
15409
|
+
input.event
|
|
15410
|
+
);
|
|
15411
|
+
return true;
|
|
15412
|
+
}
|
|
15413
|
+
if (input.event.payloadType === "run.cancelled") {
|
|
15414
|
+
await this.completeCancelledRun(input.conversationId, input.runId);
|
|
15415
|
+
return true;
|
|
15416
|
+
}
|
|
15417
|
+
await this.persistHermesEvent(input.conversationId, input.runId, input.event);
|
|
15418
|
+
return false;
|
|
15419
|
+
}
|
|
15420
|
+
async recoverRunAfterEventStreamOpenFailure(input) {
|
|
15421
|
+
await this.deps.logger.warn("hermes_event_stream_open_failed", {
|
|
15422
|
+
backend: input.backend,
|
|
15423
|
+
conversation_id: input.conversationId,
|
|
15424
|
+
run_id: input.runId,
|
|
15425
|
+
hermes_run_id: input.hermesRunId,
|
|
15426
|
+
error: input.error instanceof Error ? input.error.message : String(input.error)
|
|
15427
|
+
});
|
|
15428
|
+
const recoveredEvent = await this.recoverRunTerminalEvent({
|
|
15429
|
+
conversationId: input.conversationId,
|
|
15430
|
+
runId: input.runId,
|
|
15431
|
+
hermesRunId: input.hermesRunId,
|
|
15432
|
+
profileName: input.profileName,
|
|
15433
|
+
signal: input.controller.signal
|
|
15434
|
+
});
|
|
15435
|
+
if (recoveredEvent) {
|
|
15436
|
+
const handled = await this.handleNormalizedHermesEvent({
|
|
15437
|
+
backend: input.backend,
|
|
15438
|
+
conversationId: input.conversationId,
|
|
15439
|
+
runId: input.runId,
|
|
15440
|
+
event: recoveredEvent,
|
|
15441
|
+
profileName: input.profileName,
|
|
15442
|
+
cronJobIdsBeforeRun: input.cronJobIdsBeforeRun
|
|
15443
|
+
});
|
|
15444
|
+
if (handled) {
|
|
15445
|
+
return;
|
|
14568
15446
|
}
|
|
14569
15447
|
}
|
|
15448
|
+
if (input.controller.signal.aborted) {
|
|
15449
|
+
await this.cancelRunAfterAbort(input.conversationId, input.runId);
|
|
15450
|
+
return;
|
|
15451
|
+
}
|
|
15452
|
+
await this.failRun(
|
|
15453
|
+
input.conversationId,
|
|
15454
|
+
input.runId,
|
|
15455
|
+
await this.buildEmptyHermesResponseMessage({
|
|
15456
|
+
source: "stream-error",
|
|
15457
|
+
eventError: formatUnknownErrorMessage(input.error)
|
|
15458
|
+
})
|
|
15459
|
+
);
|
|
14570
15460
|
}
|
|
14571
|
-
async
|
|
14572
|
-
|
|
15461
|
+
async cancelRunAfterAbort(conversationId, runId) {
|
|
15462
|
+
await this.deps.withConversationLock(
|
|
14573
15463
|
conversationId,
|
|
14574
|
-
() => this.cancelRunLocked(conversationId, runId,
|
|
15464
|
+
() => this.cancelRunLocked(conversationId, runId, {
|
|
15465
|
+
abortUpstream: false,
|
|
15466
|
+
reason: "cancelled by app"
|
|
15467
|
+
})
|
|
14575
15468
|
);
|
|
14576
15469
|
}
|
|
14577
|
-
async
|
|
14578
|
-
|
|
15470
|
+
async completeCancelledRun(conversationId, runId) {
|
|
15471
|
+
await this.deps.withConversationLock(
|
|
14579
15472
|
conversationId,
|
|
14580
|
-
() => this.
|
|
15473
|
+
() => this.cancelRunLocked(conversationId, runId, {
|
|
15474
|
+
abortUpstream: false,
|
|
15475
|
+
reason: "cancelled by Hermes"
|
|
15476
|
+
})
|
|
14581
15477
|
);
|
|
14582
15478
|
}
|
|
14583
|
-
async
|
|
14584
|
-
const
|
|
14585
|
-
|
|
14586
|
-
|
|
15479
|
+
async recoverRunTerminalEvent(input) {
|
|
15480
|
+
const deadline = Date.now() + RUN_STATUS_RECOVERY_TIMEOUT_MS;
|
|
15481
|
+
let delayMs = RUN_STATUS_RECOVERY_INITIAL_DELAY_MS;
|
|
15482
|
+
while (!input.signal.aborted) {
|
|
15483
|
+
let status;
|
|
15484
|
+
try {
|
|
15485
|
+
status = await readHermesRunStatus(input.hermesRunId, {
|
|
15486
|
+
logger: this.deps.logger,
|
|
15487
|
+
profileName: input.profileName,
|
|
15488
|
+
signal: input.signal
|
|
15489
|
+
});
|
|
15490
|
+
} catch (error) {
|
|
15491
|
+
if (input.signal.aborted) {
|
|
15492
|
+
return null;
|
|
15493
|
+
}
|
|
15494
|
+
await this.deps.logger.warn("hermes_run_status_recovery_failed", {
|
|
15495
|
+
conversation_id: input.conversationId,
|
|
15496
|
+
run_id: input.runId,
|
|
15497
|
+
hermes_run_id: input.hermesRunId,
|
|
15498
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15499
|
+
});
|
|
15500
|
+
if (Date.now() >= deadline) {
|
|
15501
|
+
return null;
|
|
15502
|
+
}
|
|
15503
|
+
await sleep(Math.min(delayMs, deadline - Date.now()), input.signal);
|
|
15504
|
+
delayMs = Math.min(RUN_STATUS_RECOVERY_MAX_DELAY_MS, delayMs + 250);
|
|
14587
15505
|
continue;
|
|
14588
15506
|
}
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
15507
|
+
if (!status) {
|
|
15508
|
+
return null;
|
|
15509
|
+
}
|
|
15510
|
+
if (status.session_id) {
|
|
15511
|
+
await this.rememberRunHermesSessionId(
|
|
15512
|
+
input.conversationId,
|
|
15513
|
+
input.runId,
|
|
15514
|
+
status.session_id
|
|
15515
|
+
);
|
|
15516
|
+
}
|
|
15517
|
+
const normalizedStatus = status.status.trim().toLowerCase();
|
|
15518
|
+
if (isCompletedRunStatus(normalizedStatus)) {
|
|
15519
|
+
return {
|
|
15520
|
+
eventName: "run.completed",
|
|
15521
|
+
payloadType: "run.completed",
|
|
15522
|
+
payload: {
|
|
15523
|
+
type: "run.completed",
|
|
15524
|
+
run_id: status.run_id,
|
|
15525
|
+
output: status.output,
|
|
15526
|
+
usage: status.usage,
|
|
15527
|
+
status: status.status
|
|
15528
|
+
},
|
|
15529
|
+
rawPayload: status.raw
|
|
15530
|
+
};
|
|
15531
|
+
}
|
|
15532
|
+
if (isFailedRunStatus(normalizedStatus)) {
|
|
15533
|
+
return {
|
|
15534
|
+
eventName: "run.failed",
|
|
15535
|
+
payloadType: "run.failed",
|
|
15536
|
+
payload: {
|
|
15537
|
+
type: "run.failed",
|
|
15538
|
+
run_id: status.run_id,
|
|
15539
|
+
error: {
|
|
15540
|
+
message: readStatusErrorMessage(status.error) ?? "Hermes run failed"
|
|
15541
|
+
},
|
|
15542
|
+
status: status.status,
|
|
15543
|
+
usage: status.usage
|
|
15544
|
+
},
|
|
15545
|
+
rawPayload: status.raw
|
|
15546
|
+
};
|
|
15547
|
+
}
|
|
15548
|
+
if (isCancelledRunStatus(normalizedStatus)) {
|
|
15549
|
+
return {
|
|
15550
|
+
eventName: "run.cancelled",
|
|
15551
|
+
payloadType: "run.cancelled",
|
|
15552
|
+
payload: {
|
|
15553
|
+
type: "run.cancelled",
|
|
15554
|
+
run_id: status.run_id,
|
|
15555
|
+
status: status.status
|
|
15556
|
+
},
|
|
15557
|
+
rawPayload: status.raw
|
|
15558
|
+
};
|
|
14592
15559
|
}
|
|
15560
|
+
if (Date.now() >= deadline) {
|
|
15561
|
+
return null;
|
|
15562
|
+
}
|
|
15563
|
+
await sleep(Math.min(delayMs, deadline - Date.now()), input.signal);
|
|
15564
|
+
delayMs = Math.min(RUN_STATUS_RECOVERY_MAX_DELAY_MS, delayMs + 250);
|
|
15565
|
+
}
|
|
15566
|
+
return null;
|
|
15567
|
+
}
|
|
15568
|
+
async enrichRunFromHermesTranscript(input) {
|
|
15569
|
+
const snapshot = await this.deps.readSnapshot(input.conversationId).catch(() => null);
|
|
15570
|
+
const run = snapshot?.runs.find((item) => item.id === input.runId);
|
|
15571
|
+
const assistant = snapshot?.messages.find(
|
|
15572
|
+
(message) => message.id === run?.assistant_message_id
|
|
15573
|
+
);
|
|
15574
|
+
if (!snapshot || !run) {
|
|
15575
|
+
return;
|
|
15576
|
+
}
|
|
15577
|
+
const events = await buildRunTranscriptEvents({
|
|
15578
|
+
profileName: input.profileName,
|
|
15579
|
+
hermesSessionId: run.hermes_session_id,
|
|
15580
|
+
runStartedAt: run.started_at,
|
|
15581
|
+
assistant
|
|
15582
|
+
}).catch(async (error) => {
|
|
15583
|
+
await this.deps.logger.warn("hermes_run_transcript_enrichment_failed", {
|
|
15584
|
+
conversation_id: input.conversationId,
|
|
15585
|
+
run_id: input.runId,
|
|
15586
|
+
hermes_session_id: run.hermes_session_id,
|
|
15587
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15588
|
+
});
|
|
15589
|
+
return [];
|
|
15590
|
+
});
|
|
15591
|
+
for (const event of events) {
|
|
15592
|
+
await this.persistHermesEvent(input.conversationId, input.runId, event);
|
|
14593
15593
|
}
|
|
14594
|
-
return void 0;
|
|
14595
15594
|
}
|
|
14596
15595
|
async resolveRunInput(input) {
|
|
14597
15596
|
const userMessage = input.snapshot.messages.find(
|
|
@@ -14738,6 +15737,12 @@ ${attachmentLines.join("\n")}`
|
|
|
14738
15737
|
"\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
15738
|
);
|
|
14740
15739
|
}
|
|
15740
|
+
if (input?.source === "stream-error") {
|
|
15741
|
+
details.unshift("Hermes \u7684\u8FD0\u884C\u4E8B\u4EF6\u6D41\u8BFB\u53D6\u8FC7\u7A0B\u4E2D\u65AD\u3002");
|
|
15742
|
+
details.push(
|
|
15743
|
+
"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"
|
|
15744
|
+
);
|
|
15745
|
+
}
|
|
14741
15746
|
return details.length > 0 ? `Hermes \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\u3002
|
|
14742
15747
|
${details.join("\n")}` : emptyHermesResponseMessage();
|
|
14743
15748
|
}
|
|
@@ -14882,8 +15887,8 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
|
|
|
14882
15887
|
}
|
|
14883
15888
|
const textPart = assistant.parts.find((part) => part.type === "text");
|
|
14884
15889
|
const currentText = textPart?.text ?? "";
|
|
14885
|
-
const pendingDeliveryText =
|
|
14886
|
-
|
|
15890
|
+
const pendingDeliveryText = readString15(
|
|
15891
|
+
toRecord13(assistant.hermes),
|
|
14887
15892
|
"pending_media_delivery_text"
|
|
14888
15893
|
);
|
|
14889
15894
|
const normalizedDelta = normalizeStreamingTextDelta(
|
|
@@ -14898,7 +15903,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
|
|
|
14898
15903
|
pendingDeliveryText ?? ""
|
|
14899
15904
|
);
|
|
14900
15905
|
const nextHermes = {
|
|
14901
|
-
...
|
|
15906
|
+
...toRecord13(assistant.hermes),
|
|
14902
15907
|
...extracted.pendingText ? { pending_media_delivery_text: extracted.pendingText } : {}
|
|
14903
15908
|
};
|
|
14904
15909
|
if (!extracted.pendingText) {
|
|
@@ -14977,11 +15982,15 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
|
|
|
14977
15982
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14978
15983
|
const usage = readUsage(source?.payload);
|
|
14979
15984
|
const responseId = readResponseId(source?.payload);
|
|
15985
|
+
const hermesRunId = readRunId(source?.payload);
|
|
14980
15986
|
run.status = "completed";
|
|
14981
15987
|
run.completed_at = completedAt;
|
|
14982
15988
|
if (responseId) {
|
|
14983
15989
|
run.hermes_response_id = responseId;
|
|
14984
15990
|
}
|
|
15991
|
+
if (hermesRunId) {
|
|
15992
|
+
run.hermes_run_id = hermesRunId;
|
|
15993
|
+
}
|
|
14985
15994
|
if (usage) {
|
|
14986
15995
|
run.usage = mergeRunUsage(run.usage, usage);
|
|
14987
15996
|
}
|
|
@@ -15155,7 +16164,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
|
|
|
15155
16164
|
if (raw.length <= 200) {
|
|
15156
16165
|
return raw;
|
|
15157
16166
|
}
|
|
15158
|
-
return `hermespilot:${
|
|
16167
|
+
return `hermespilot:${createHash5("sha256").update(raw).digest("hex")}`;
|
|
15159
16168
|
}
|
|
15160
16169
|
async assistantMessageIdForRun(conversationId, runId) {
|
|
15161
16170
|
const snapshot = await this.deps.readSnapshot(conversationId).catch(() => null);
|
|
@@ -15176,7 +16185,7 @@ ${details.join("\n")}` : emptyHermesResponseMessage();
|
|
|
15176
16185
|
includeDisabled: true
|
|
15177
16186
|
});
|
|
15178
16187
|
return new Set(
|
|
15179
|
-
jobs.map((job) =>
|
|
16188
|
+
jobs.map((job) => readString15(job, "id") ?? readString15(job, "job_id")).filter((id) => Boolean(id))
|
|
15180
16189
|
);
|
|
15181
16190
|
}
|
|
15182
16191
|
async bindNewCronJobsCreatedByRun(input) {
|
|
@@ -15212,7 +16221,7 @@ function buildRunInstructions(run, deliveryStagingDir) {
|
|
|
15212
16221
|
].join("\n");
|
|
15213
16222
|
}
|
|
15214
16223
|
function appendMediaImportFailureNotice(message) {
|
|
15215
|
-
const hermes =
|
|
16224
|
+
const hermes = toRecord13(message.hermes);
|
|
15216
16225
|
if (hermes.media_import_failure_notice_appended === true) {
|
|
15217
16226
|
return;
|
|
15218
16227
|
}
|
|
@@ -15256,17 +16265,17 @@ function formatFilenameList(filenames) {
|
|
|
15256
16265
|
}
|
|
15257
16266
|
async function readdirWithDirs(directory) {
|
|
15258
16267
|
return readdir8(directory, { withFileTypes: true }).catch((error) => {
|
|
15259
|
-
if (
|
|
16268
|
+
if (isNodeError14(error, "ENOENT")) {
|
|
15260
16269
|
return [];
|
|
15261
16270
|
}
|
|
15262
16271
|
throw error;
|
|
15263
16272
|
});
|
|
15264
16273
|
}
|
|
15265
|
-
function
|
|
16274
|
+
function readString15(payload, key) {
|
|
15266
16275
|
const value = payload[key];
|
|
15267
16276
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
15268
16277
|
}
|
|
15269
|
-
function
|
|
16278
|
+
function toRecord13(value) {
|
|
15270
16279
|
return typeof value === "object" && value !== null ? value : {};
|
|
15271
16280
|
}
|
|
15272
16281
|
function formatFailureMessage(message, detail) {
|
|
@@ -15282,17 +16291,17 @@ function isFileSearchCompletion(payloadType, payload) {
|
|
|
15282
16291
|
if (payloadType !== "tool.completed") {
|
|
15283
16292
|
return false;
|
|
15284
16293
|
}
|
|
15285
|
-
const tool =
|
|
15286
|
-
const toolCall =
|
|
15287
|
-
const fn =
|
|
16294
|
+
const tool = toRecord13(payload.tool);
|
|
16295
|
+
const toolCall = toRecord13(payload.tool_call ?? payload.toolCall);
|
|
16296
|
+
const fn = toRecord13(toolCall.function ?? payload.function);
|
|
15288
16297
|
const candidates = [
|
|
15289
|
-
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
|
|
15293
|
-
|
|
15294
|
-
|
|
15295
|
-
|
|
16298
|
+
readString15(payload, "tool_name"),
|
|
16299
|
+
readString15(payload, "toolName"),
|
|
16300
|
+
readString15(payload, "name"),
|
|
16301
|
+
readString15(payload, "tool"),
|
|
16302
|
+
readString15(tool, "name"),
|
|
16303
|
+
readString15(toolCall, "name"),
|
|
16304
|
+
readString15(fn, "name")
|
|
15296
16305
|
].filter((value) => Boolean(value)).map(normalizeToolName);
|
|
15297
16306
|
return candidates.some(
|
|
15298
16307
|
(name) => [
|
|
@@ -15412,22 +16421,15 @@ function appendAgentEventBlock2(message, event, updatedAt) {
|
|
|
15412
16421
|
}
|
|
15413
16422
|
function contextUsagePayload(run) {
|
|
15414
16423
|
const usage = run.usage;
|
|
15415
|
-
|
|
16424
|
+
const runtimeContext = resolveRuntimeContextUsage({
|
|
16425
|
+
usage,
|
|
16426
|
+
contextWindow: run.context_window
|
|
16427
|
+
});
|
|
16428
|
+
const contextTokens = runtimeContext.contextTokens;
|
|
16429
|
+
const contextWindow = runtimeContext.contextWindow;
|
|
16430
|
+
if (!usage || contextTokens === void 0) {
|
|
15416
16431
|
return null;
|
|
15417
16432
|
}
|
|
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
16433
|
return {
|
|
15432
16434
|
input_tokens: contextTokens,
|
|
15433
16435
|
output_tokens: usage?.output_tokens ?? 0,
|
|
@@ -15435,13 +16437,8 @@ function contextUsagePayload(run) {
|
|
|
15435
16437
|
...contextWindow ? { context_window: contextWindow } : {},
|
|
15436
16438
|
used_tokens: contextTokens,
|
|
15437
16439
|
...contextWindow ? { window_tokens: contextWindow } : {},
|
|
15438
|
-
source:
|
|
15439
|
-
...
|
|
15440
|
-
usage_percent: Math.min(
|
|
15441
|
-
100,
|
|
15442
|
-
Math.round(contextTokens / contextWindow * 100)
|
|
15443
|
-
)
|
|
15444
|
-
} : {}
|
|
16440
|
+
source: runtimeContext.source,
|
|
16441
|
+
...runtimeContext.usagePercent !== void 0 ? { usage_percent: runtimeContext.usagePercent } : {}
|
|
15445
16442
|
};
|
|
15446
16443
|
}
|
|
15447
16444
|
function mergeRunUsage(previous, next) {
|
|
@@ -15506,10 +16503,57 @@ function readResponseId(payload) {
|
|
|
15506
16503
|
if (!payload) {
|
|
15507
16504
|
return null;
|
|
15508
16505
|
}
|
|
15509
|
-
const response =
|
|
15510
|
-
return
|
|
16506
|
+
const response = toRecord13(payload.response);
|
|
16507
|
+
return readString15(payload, "response_id") ?? readString15(response, "id");
|
|
15511
16508
|
}
|
|
15512
|
-
function
|
|
16509
|
+
function readRunId(payload) {
|
|
16510
|
+
if (!payload) {
|
|
16511
|
+
return null;
|
|
16512
|
+
}
|
|
16513
|
+
return readString15(payload, "run_id") ?? readString15(payload, "runId");
|
|
16514
|
+
}
|
|
16515
|
+
function isCompletedRunStatus(status) {
|
|
16516
|
+
return status === "completed" || status === "complete" || status === "succeeded" || status === "success" || status === "done";
|
|
16517
|
+
}
|
|
16518
|
+
function isFailedRunStatus(status) {
|
|
16519
|
+
return status === "failed" || status === "failure" || status === "error";
|
|
16520
|
+
}
|
|
16521
|
+
function isCancelledRunStatus(status) {
|
|
16522
|
+
return status === "cancelled" || status === "canceled" || status === "stopped" || status === "aborted";
|
|
16523
|
+
}
|
|
16524
|
+
function readStatusErrorMessage(value) {
|
|
16525
|
+
if (typeof value === "string" && value.trim()) {
|
|
16526
|
+
return value.trim();
|
|
16527
|
+
}
|
|
16528
|
+
const record = toRecord13(value);
|
|
16529
|
+
return readString15(record, "message") ?? readString15(record, "error");
|
|
16530
|
+
}
|
|
16531
|
+
function formatUnknownErrorMessage(error) {
|
|
16532
|
+
return error instanceof Error ? error.message : String(error);
|
|
16533
|
+
}
|
|
16534
|
+
async function closeSseIterator(iterator) {
|
|
16535
|
+
if (!iterator.return) {
|
|
16536
|
+
return;
|
|
16537
|
+
}
|
|
16538
|
+
await iterator.return().catch(() => void 0);
|
|
16539
|
+
}
|
|
16540
|
+
async function sleep(ms, signal) {
|
|
16541
|
+
if (ms <= 0 || signal.aborted) {
|
|
16542
|
+
return;
|
|
16543
|
+
}
|
|
16544
|
+
await new Promise((resolve) => {
|
|
16545
|
+
const timeout = setTimeout(resolve, ms);
|
|
16546
|
+
signal.addEventListener(
|
|
16547
|
+
"abort",
|
|
16548
|
+
() => {
|
|
16549
|
+
clearTimeout(timeout);
|
|
16550
|
+
resolve();
|
|
16551
|
+
},
|
|
16552
|
+
{ once: true }
|
|
16553
|
+
);
|
|
16554
|
+
});
|
|
16555
|
+
}
|
|
16556
|
+
function isNodeError14(error, code) {
|
|
15513
16557
|
if (typeof error !== "object" || error === null || !("code" in error)) {
|
|
15514
16558
|
return false;
|
|
15515
16559
|
}
|
|
@@ -16433,7 +17477,7 @@ function findApproval(snapshot, approvalId) {
|
|
|
16433
17477
|
}
|
|
16434
17478
|
|
|
16435
17479
|
// src/security/devices.ts
|
|
16436
|
-
import { randomBytes as randomBytes2, randomUUID as randomUUID11, timingSafeEqual, createHash as
|
|
17480
|
+
import { randomBytes as randomBytes2, randomUUID as randomUUID11, timingSafeEqual, createHash as createHash6 } from "crypto";
|
|
16437
17481
|
var ACCESS_TOKEN_TTL_MS = 15 * 60 * 1e3;
|
|
16438
17482
|
var REFRESH_TOKEN_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
16439
17483
|
var DEVICE_SEEN_WRITE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
@@ -16729,7 +17773,7 @@ function randomToken(prefix) {
|
|
|
16729
17773
|
return `${prefix}${randomBytes2(24).toString("base64url")}`;
|
|
16730
17774
|
}
|
|
16731
17775
|
function sha256(value) {
|
|
16732
|
-
return
|
|
17776
|
+
return createHash6("sha256").update(value).digest("hex");
|
|
16733
17777
|
}
|
|
16734
17778
|
function safeEqual(left, right) {
|
|
16735
17779
|
const leftBytes = Buffer.from(left);
|
|
@@ -16900,12 +17944,12 @@ async function readRawBody(request, maxBytes) {
|
|
|
16900
17944
|
}
|
|
16901
17945
|
return Buffer.concat(chunks);
|
|
16902
17946
|
}
|
|
16903
|
-
function
|
|
17947
|
+
function readString16(body, key) {
|
|
16904
17948
|
const value = body[key];
|
|
16905
17949
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
16906
17950
|
}
|
|
16907
17951
|
function readOptionalProfileName(body) {
|
|
16908
|
-
return
|
|
17952
|
+
return readString16(body, "profile") ?? readString16(body, "profile_name") ?? readString16(body, "profileName") ?? void 0;
|
|
16909
17953
|
}
|
|
16910
17954
|
function readStringArray(body, ...keys) {
|
|
16911
17955
|
for (const key of keys) {
|
|
@@ -17273,7 +18317,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17273
18317
|
ctx.body = {
|
|
17274
18318
|
ok: true,
|
|
17275
18319
|
conversation: await conversations.createConversation({
|
|
17276
|
-
title:
|
|
18320
|
+
title: readString16(body, "title") ?? void 0,
|
|
17277
18321
|
profileName: readOptionalProfileName(body)
|
|
17278
18322
|
})
|
|
17279
18323
|
};
|
|
@@ -17345,7 +18389,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17345
18389
|
router.post("/api/v1/conversations/:conversationId/messages", async (ctx) => {
|
|
17346
18390
|
await authenticateRequest(ctx, paths);
|
|
17347
18391
|
const body = await readJsonBody(ctx.req);
|
|
17348
|
-
const content =
|
|
18392
|
+
const content = readString16(body, "content") ?? readString16(body, "text") ?? readString16(body, "input") ?? "";
|
|
17349
18393
|
const attachments = readMessageAttachments(body.attachments ?? body.blobs);
|
|
17350
18394
|
if (!content && attachments.length === 0) {
|
|
17351
18395
|
throw new LinkHttpError(
|
|
@@ -17361,7 +18405,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17361
18405
|
conversationId: ctx.params.conversationId,
|
|
17362
18406
|
content,
|
|
17363
18407
|
attachments,
|
|
17364
|
-
clientMessageId:
|
|
18408
|
+
clientMessageId: readString16(body, "client_message_id") ?? readString16(body, "clientMessageId") ?? void 0,
|
|
17365
18409
|
idempotencyKey: readHeader(ctx, "idempotency-key") ?? void 0,
|
|
17366
18410
|
profileName: readOptionalProfileName(body)
|
|
17367
18411
|
})
|
|
@@ -17370,7 +18414,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17370
18414
|
router.patch("/api/v1/conversations/:conversationId/model", async (ctx) => {
|
|
17371
18415
|
await authenticateRequest(ctx, paths);
|
|
17372
18416
|
const body = await readJsonBody(ctx.req);
|
|
17373
|
-
const modelId =
|
|
18417
|
+
const modelId = readString16(body, "model_id") ?? readString16(body, "modelId") ?? readString16(body, "model");
|
|
17374
18418
|
if (!modelId) {
|
|
17375
18419
|
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
17376
18420
|
}
|
|
@@ -17400,7 +18444,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17400
18444
|
router.patch("/api/v1/conversations/:conversationId/title", async (ctx) => {
|
|
17401
18445
|
await authenticateRequest(ctx, paths);
|
|
17402
18446
|
const body = await readJsonBody(ctx.req);
|
|
17403
|
-
const title =
|
|
18447
|
+
const title = readString16(body, "title") ?? readString16(body, "name") ?? readString16(body, "display_name");
|
|
17404
18448
|
if (!title) {
|
|
17405
18449
|
throw new LinkHttpError(400, "title_required", "title is required");
|
|
17406
18450
|
}
|
|
@@ -17539,7 +18583,7 @@ function registerConversationRoutes(router, options) {
|
|
|
17539
18583
|
async (ctx) => {
|
|
17540
18584
|
await authenticateRequest(ctx, paths);
|
|
17541
18585
|
const body = await readJsonBody(ctx.req);
|
|
17542
|
-
const scope =
|
|
18586
|
+
const scope = readString16(body, "scope") ?? "always";
|
|
17543
18587
|
ctx.body = {
|
|
17544
18588
|
ok: true,
|
|
17545
18589
|
...await conversations.resolveApproval({
|
|
@@ -17640,7 +18684,7 @@ function resolveConversationEventCursor(input) {
|
|
|
17640
18684
|
return Math.max(queryAfter, headerAfter);
|
|
17641
18685
|
}
|
|
17642
18686
|
function readConversationClearPlanTargetStatus(body) {
|
|
17643
|
-
const raw =
|
|
18687
|
+
const raw = readString16(body, "target_status") ?? readString16(body, "targetStatus") ?? "active";
|
|
17644
18688
|
if (raw === "active" || raw === "archived") {
|
|
17645
18689
|
return raw;
|
|
17646
18690
|
}
|
|
@@ -17731,8 +18775,8 @@ function createHttpErrorMiddleware(logger) {
|
|
|
17731
18775
|
|
|
17732
18776
|
// src/hermes/profiles.ts
|
|
17733
18777
|
import { execFile as execFile4 } from "child_process";
|
|
17734
|
-
import { readdir as readdir9, readFile as
|
|
17735
|
-
import
|
|
18778
|
+
import { readdir as readdir9, readFile as readFile13, rename as rename3, stat as stat13 } from "fs/promises";
|
|
18779
|
+
import path20 from "path";
|
|
17736
18780
|
import { setTimeout as delay2 } from "timers/promises";
|
|
17737
18781
|
import { promisify as promisify4 } from "util";
|
|
17738
18782
|
import YAML2 from "yaml";
|
|
@@ -17749,7 +18793,7 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
|
|
|
17749
18793
|
const profilesDir = resolveHermesProfilesDir();
|
|
17750
18794
|
const entries = await readdir9(profilesDir, { withFileTypes: true }).catch(
|
|
17751
18795
|
(error) => {
|
|
17752
|
-
if (
|
|
18796
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
17753
18797
|
return [];
|
|
17754
18798
|
}
|
|
17755
18799
|
throw error;
|
|
@@ -17773,8 +18817,8 @@ async function listHermesProfiles(paths = resolveRuntimePaths()) {
|
|
|
17773
18817
|
async function getHermesProfileStatus(name, paths = resolveRuntimePaths()) {
|
|
17774
18818
|
assertProfileName(name);
|
|
17775
18819
|
const profile = await profileInfo(name, paths);
|
|
17776
|
-
const exists = await
|
|
17777
|
-
if (
|
|
18820
|
+
const exists = await stat13(profile.path).then((value) => value.isDirectory()).catch((error) => {
|
|
18821
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
17778
18822
|
return false;
|
|
17779
18823
|
}
|
|
17780
18824
|
throw error;
|
|
@@ -17843,7 +18887,7 @@ async function readHermesProfileCapabilities(name) {
|
|
|
17843
18887
|
return {
|
|
17844
18888
|
defaultModel: listedModels?.defaultModel ?? null,
|
|
17845
18889
|
modelCount: listedModels?.models.length ?? 0,
|
|
17846
|
-
skillCount: await countSkills(
|
|
18890
|
+
skillCount: await countSkills(path20.join(profileDir, "skills")).catch(
|
|
17847
18891
|
() => 0
|
|
17848
18892
|
),
|
|
17849
18893
|
toolCount: await countConfiguredTools(name).catch(() => 0)
|
|
@@ -17886,8 +18930,8 @@ function assertProfileName(name) {
|
|
|
17886
18930
|
}
|
|
17887
18931
|
}
|
|
17888
18932
|
async function pathExists(targetPath) {
|
|
17889
|
-
return await
|
|
17890
|
-
if (
|
|
18933
|
+
return await stat13(targetPath).then(() => true).catch((error) => {
|
|
18934
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
17891
18935
|
return false;
|
|
17892
18936
|
}
|
|
17893
18937
|
throw error;
|
|
@@ -18004,7 +19048,7 @@ function isProcessRunning(pid) {
|
|
|
18004
19048
|
process.kill(pid, 0);
|
|
18005
19049
|
return true;
|
|
18006
19050
|
} catch (error) {
|
|
18007
|
-
return
|
|
19051
|
+
return isNodeError15(error, "EPERM");
|
|
18008
19052
|
}
|
|
18009
19053
|
}
|
|
18010
19054
|
async function waitForProfilePathToRemainAbsent(profilePath) {
|
|
@@ -18041,7 +19085,7 @@ function readExecErrorOutput2(error) {
|
|
|
18041
19085
|
}
|
|
18042
19086
|
return parts.join("\n");
|
|
18043
19087
|
}
|
|
18044
|
-
function
|
|
19088
|
+
function isNodeError15(error, code) {
|
|
18045
19089
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
18046
19090
|
}
|
|
18047
19091
|
function escapeRegExp2(value) {
|
|
@@ -18050,7 +19094,7 @@ function escapeRegExp2(value) {
|
|
|
18050
19094
|
async function countSkills(root) {
|
|
18051
19095
|
const entries = await readdir9(root, { withFileTypes: true }).catch(
|
|
18052
19096
|
(error) => {
|
|
18053
|
-
if (
|
|
19097
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
18054
19098
|
return [];
|
|
18055
19099
|
}
|
|
18056
19100
|
throw error;
|
|
@@ -18058,7 +19102,7 @@ async function countSkills(root) {
|
|
|
18058
19102
|
);
|
|
18059
19103
|
let count = 0;
|
|
18060
19104
|
for (const entry of entries) {
|
|
18061
|
-
const entryPath =
|
|
19105
|
+
const entryPath = path20.join(root, entry.name);
|
|
18062
19106
|
if (entry.name === ".git" || entry.name === ".hub") {
|
|
18063
19107
|
continue;
|
|
18064
19108
|
}
|
|
@@ -18073,11 +19117,11 @@ async function countSkills(root) {
|
|
|
18073
19117
|
return count;
|
|
18074
19118
|
}
|
|
18075
19119
|
async function countConfiguredTools(profileName) {
|
|
18076
|
-
const raw = await
|
|
19120
|
+
const raw = await readFile13(
|
|
18077
19121
|
resolveHermesConfigPath(profileName),
|
|
18078
19122
|
"utf8"
|
|
18079
19123
|
).catch((error) => {
|
|
18080
|
-
if (
|
|
19124
|
+
if (isNodeError15(error, "ENOENT")) {
|
|
18081
19125
|
return "";
|
|
18082
19126
|
}
|
|
18083
19127
|
throw error;
|
|
@@ -18085,14 +19129,14 @@ async function countConfiguredTools(profileName) {
|
|
|
18085
19129
|
if (!raw.trim()) {
|
|
18086
19130
|
return 0;
|
|
18087
19131
|
}
|
|
18088
|
-
const config =
|
|
19132
|
+
const config = toRecord14(YAML2.parse(raw));
|
|
18089
19133
|
const toolsets = /* @__PURE__ */ new Set();
|
|
18090
19134
|
collectToolsetValues(config.toolsets, toolsets);
|
|
18091
|
-
const platformToolsets =
|
|
19135
|
+
const platformToolsets = toRecord14(config.platform_toolsets);
|
|
18092
19136
|
for (const value of Object.values(platformToolsets)) {
|
|
18093
19137
|
collectToolsetValues(value, toolsets);
|
|
18094
19138
|
}
|
|
18095
|
-
const mcpServers = Object.keys(
|
|
19139
|
+
const mcpServers = Object.keys(toRecord14(config.mcp_servers)).length;
|
|
18096
19140
|
return toolsets.size + mcpServers;
|
|
18097
19141
|
}
|
|
18098
19142
|
function collectToolsetValues(value, target) {
|
|
@@ -18106,7 +19150,7 @@ function collectToolsetValues(value, target) {
|
|
|
18106
19150
|
target.add(value.trim());
|
|
18107
19151
|
}
|
|
18108
19152
|
}
|
|
18109
|
-
function
|
|
19153
|
+
function toRecord14(value) {
|
|
18110
19154
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
18111
19155
|
}
|
|
18112
19156
|
|
|
@@ -18303,7 +19347,7 @@ function toHermesCronJobInput(input) {
|
|
|
18303
19347
|
};
|
|
18304
19348
|
}
|
|
18305
19349
|
async function bindAndDecorateCronJobForHermesLink(input) {
|
|
18306
|
-
const jobId =
|
|
19350
|
+
const jobId = readString16(input.job, "id") ?? readString16(input.job, "job_id");
|
|
18307
19351
|
if (!jobId) {
|
|
18308
19352
|
return input.job;
|
|
18309
19353
|
}
|
|
@@ -18320,9 +19364,9 @@ async function bindAndDecorateCronJobForHermesLink(input) {
|
|
|
18320
19364
|
}
|
|
18321
19365
|
function readCronJobCreateInput(body) {
|
|
18322
19366
|
const input = {};
|
|
18323
|
-
const name =
|
|
18324
|
-
const prompt =
|
|
18325
|
-
const schedule =
|
|
19367
|
+
const name = readString16(body, "name") ?? readString16(body, "title");
|
|
19368
|
+
const prompt = readString16(body, "prompt") ?? readString16(body, "description") ?? readString16(body, "task");
|
|
19369
|
+
const schedule = readString16(body, "schedule");
|
|
18326
19370
|
if (!name) {
|
|
18327
19371
|
throw new LinkHttpError(400, "cron_job_name_required", "name is required");
|
|
18328
19372
|
}
|
|
@@ -18343,7 +19387,7 @@ function readCronJobCreateInput(body) {
|
|
|
18343
19387
|
input.name = name;
|
|
18344
19388
|
input.prompt = prompt;
|
|
18345
19389
|
input.schedule = schedule;
|
|
18346
|
-
input.deliver =
|
|
19390
|
+
input.deliver = readString16(body, "deliver") ?? HERMES_LINK_CRON_DELIVER;
|
|
18347
19391
|
const skills = readOptionalCronSkills(body);
|
|
18348
19392
|
if (skills) {
|
|
18349
19393
|
input.skills = skills;
|
|
@@ -18587,7 +19631,7 @@ function registerModelConfigRoutes(router, options) {
|
|
|
18587
19631
|
router.delete("/api/v1/model-configs", async (ctx) => {
|
|
18588
19632
|
await authenticateRequest(ctx, paths);
|
|
18589
19633
|
const body = await readJsonBody(ctx.req);
|
|
18590
|
-
const modelId =
|
|
19634
|
+
const modelId = readString16(body, "model_id") ?? readString16(body, "modelId");
|
|
18591
19635
|
if (!modelId) {
|
|
18592
19636
|
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
18593
19637
|
}
|
|
@@ -18659,7 +19703,7 @@ function registerModelConfigRoutes(router, options) {
|
|
|
18659
19703
|
await authenticateRequest(ctx, paths);
|
|
18660
19704
|
await getHermesProfileStatus(ctx.params.name, paths);
|
|
18661
19705
|
const body = await readJsonBody(ctx.req);
|
|
18662
|
-
const modelId =
|
|
19706
|
+
const modelId = readString16(body, "model_id") ?? readString16(body, "modelId");
|
|
18663
19707
|
if (!modelId) {
|
|
18664
19708
|
throw new LinkHttpError(400, "model_id_required", "model_id is required");
|
|
18665
19709
|
}
|
|
@@ -18676,9 +19720,9 @@ function registerModelConfigRoutes(router, options) {
|
|
|
18676
19720
|
});
|
|
18677
19721
|
}
|
|
18678
19722
|
function readModelConfigInput(body) {
|
|
18679
|
-
const id =
|
|
18680
|
-
const provider =
|
|
18681
|
-
const baseUrl =
|
|
19723
|
+
const id = readString16(body, "id") ?? readString16(body, "model_id") ?? readString16(body, "modelId");
|
|
19724
|
+
const provider = readString16(body, "provider") ?? readString16(body, "provider_key") ?? readString16(body, "providerKey");
|
|
19725
|
+
const baseUrl = readString16(body, "base_url") ?? readString16(body, "baseUrl");
|
|
18682
19726
|
if (!id || !provider || !baseUrl) {
|
|
18683
19727
|
throw new LinkHttpError(
|
|
18684
19728
|
400,
|
|
@@ -18688,29 +19732,29 @@ function readModelConfigInput(body) {
|
|
|
18688
19732
|
}
|
|
18689
19733
|
return {
|
|
18690
19734
|
id,
|
|
18691
|
-
originalModelId:
|
|
19735
|
+
originalModelId: readString16(body, "original_model_id") ?? readString16(body, "originalModelId") ?? readString16(body, "original_id") ?? void 0,
|
|
18692
19736
|
provider,
|
|
18693
|
-
providerName:
|
|
19737
|
+
providerName: readString16(body, "provider_name") ?? readString16(body, "providerName") ?? void 0,
|
|
18694
19738
|
baseUrl,
|
|
18695
|
-
apiKey:
|
|
18696
|
-
apiMode:
|
|
19739
|
+
apiKey: readString16(body, "api_key") ?? readString16(body, "apiKey") ?? void 0,
|
|
19740
|
+
apiMode: readString16(body, "api_mode") ?? readString16(body, "apiMode") ?? void 0,
|
|
18697
19741
|
contextLength: readPositiveInteger2(
|
|
18698
19742
|
body.context_length ?? body.contextLength
|
|
18699
19743
|
),
|
|
18700
|
-
keyEnv:
|
|
19744
|
+
keyEnv: readString16(body, "key_env") ?? readString16(body, "keyEnv") ?? void 0,
|
|
18701
19745
|
setDefault: readBoolean3(body.set_default ?? body.setDefault),
|
|
18702
|
-
reasoningEffort:
|
|
19746
|
+
reasoningEffort: readString16(body, "reasoning_effort") ?? readString16(body, "reasoningEffort") ?? void 0
|
|
18703
19747
|
};
|
|
18704
19748
|
}
|
|
18705
19749
|
function readModelDefaultsInput(body) {
|
|
18706
19750
|
return {
|
|
18707
|
-
taskModelId:
|
|
18708
|
-
compressionModelId:
|
|
19751
|
+
taskModelId: readString16(body, "task_model_id") ?? readString16(body, "taskModelId") ?? readString16(body, "default_model_id") ?? readString16(body, "defaultModelId") ?? void 0,
|
|
19752
|
+
compressionModelId: readString16(body, "compression_model_id") ?? readString16(body, "compressionModelId") ?? void 0
|
|
18709
19753
|
};
|
|
18710
19754
|
}
|
|
18711
19755
|
function readModelConfigImportInput(body) {
|
|
18712
|
-
const sourceProfileName =
|
|
18713
|
-
const modelId =
|
|
19756
|
+
const sourceProfileName = readString16(body, "source_profile") ?? readString16(body, "sourceProfile") ?? readString16(body, "source_profile_name") ?? readString16(body, "sourceProfileName");
|
|
19757
|
+
const modelId = readString16(body, "model_id") ?? readString16(body, "modelId") ?? readString16(body, "id");
|
|
18714
19758
|
if (!sourceProfileName || !modelId) {
|
|
18715
19759
|
throw new LinkHttpError(
|
|
18716
19760
|
400,
|
|
@@ -18721,9 +19765,9 @@ function readModelConfigImportInput(body) {
|
|
|
18721
19765
|
return {
|
|
18722
19766
|
sourceProfileName,
|
|
18723
19767
|
modelId,
|
|
18724
|
-
provider:
|
|
18725
|
-
baseUrl:
|
|
18726
|
-
apiMode:
|
|
19768
|
+
provider: readString16(body, "provider") ?? readString16(body, "provider_key") ?? readString16(body, "providerKey") ?? void 0,
|
|
19769
|
+
baseUrl: readString16(body, "base_url") ?? readString16(body, "baseUrl") ?? void 0,
|
|
19770
|
+
apiMode: readString16(body, "api_mode") ?? readString16(body, "apiMode") ?? void 0,
|
|
18727
19771
|
setDefault: readBoolean3(body.set_default ?? body.setDefault)
|
|
18728
19772
|
};
|
|
18729
19773
|
}
|
|
@@ -18808,11 +19852,11 @@ import { EventEmitter as EventEmitter2 } from "events";
|
|
|
18808
19852
|
import {
|
|
18809
19853
|
cp,
|
|
18810
19854
|
mkdir as mkdir11,
|
|
18811
|
-
readFile as
|
|
19855
|
+
readFile as readFile14,
|
|
18812
19856
|
rm as rm6,
|
|
18813
|
-
stat as
|
|
19857
|
+
stat as stat14
|
|
18814
19858
|
} from "fs/promises";
|
|
18815
|
-
import
|
|
19859
|
+
import path21 from "path";
|
|
18816
19860
|
import YAML3 from "yaml";
|
|
18817
19861
|
var PROFILE_CREATE_LOG_FILE = "profile-create.log";
|
|
18818
19862
|
var PROFILE_CREATE_LOG_MAX_FILES = 3;
|
|
@@ -19202,7 +20246,7 @@ function copyModelConfig(source, target) {
|
|
|
19202
20246
|
copied[key] = cloneJson(source[key]);
|
|
19203
20247
|
}
|
|
19204
20248
|
}
|
|
19205
|
-
const sourceAuxiliary =
|
|
20249
|
+
const sourceAuxiliary = toRecord15(source.auxiliary);
|
|
19206
20250
|
if (Object.prototype.hasOwnProperty.call(sourceAuxiliary, "compression")) {
|
|
19207
20251
|
const targetAuxiliary = ensureRecord2(target, "auxiliary");
|
|
19208
20252
|
targetAuxiliary.compression = cloneJson(sourceAuxiliary.compression);
|
|
@@ -19211,12 +20255,12 @@ function copyModelConfig(source, target) {
|
|
|
19211
20255
|
return copied;
|
|
19212
20256
|
}
|
|
19213
20257
|
function copyToolPermissionsConfig(source, target) {
|
|
19214
|
-
const sourcePlatformToolsets =
|
|
20258
|
+
const sourcePlatformToolsets = toRecord15(source.platform_toolsets);
|
|
19215
20259
|
if (Object.prototype.hasOwnProperty.call(sourcePlatformToolsets, "api_server")) {
|
|
19216
20260
|
const targetPlatformToolsets = ensureRecord2(target, "platform_toolsets");
|
|
19217
20261
|
targetPlatformToolsets.api_server = cloneJson(sourcePlatformToolsets.api_server);
|
|
19218
20262
|
}
|
|
19219
|
-
const sourceStt =
|
|
20263
|
+
const sourceStt = toRecord15(source.stt);
|
|
19220
20264
|
if (Object.prototype.hasOwnProperty.call(sourceStt, "enabled")) {
|
|
19221
20265
|
const targetStt = ensureRecord2(target, "stt");
|
|
19222
20266
|
targetStt.enabled = cloneJson(sourceStt.enabled);
|
|
@@ -19263,9 +20307,9 @@ function collectEnvKeys(value, keys = /* @__PURE__ */ new Set()) {
|
|
|
19263
20307
|
return keys;
|
|
19264
20308
|
}
|
|
19265
20309
|
async function writeEnvValues(profileName, values) {
|
|
19266
|
-
const envPath =
|
|
19267
|
-
const existingRaw = await
|
|
19268
|
-
if (
|
|
20310
|
+
const envPath = path21.join(resolveHermesProfileDir(profileName), ".env");
|
|
20311
|
+
const existingRaw = await readFile14(envPath, "utf8").catch((error) => {
|
|
20312
|
+
if (isNodeError16(error, "ENOENT")) {
|
|
19269
20313
|
return "";
|
|
19270
20314
|
}
|
|
19271
20315
|
throw error;
|
|
@@ -19300,8 +20344,8 @@ async function writeEnvValues(profileName, values) {
|
|
|
19300
20344
|
await atomicWriteFilePreservingMetadata(envPath, nextRaw);
|
|
19301
20345
|
}
|
|
19302
20346
|
async function copySkills(sourceProfile, targetProfile) {
|
|
19303
|
-
const sourceSkills =
|
|
19304
|
-
const targetSkills =
|
|
20347
|
+
const sourceSkills = path21.join(resolveHermesProfileDir(sourceProfile), "skills");
|
|
20348
|
+
const targetSkills = path21.join(resolveHermesProfileDir(targetProfile), "skills");
|
|
19305
20349
|
if (!await pathExists2(sourceSkills)) {
|
|
19306
20350
|
return;
|
|
19307
20351
|
}
|
|
@@ -19324,16 +20368,16 @@ function copyProperty(source, target, key) {
|
|
|
19324
20368
|
}
|
|
19325
20369
|
}
|
|
19326
20370
|
async function readYamlConfig(configPath) {
|
|
19327
|
-
const existingRaw = await
|
|
20371
|
+
const existingRaw = await readFile14(configPath, "utf8").catch(
|
|
19328
20372
|
(error) => {
|
|
19329
|
-
if (
|
|
20373
|
+
if (isNodeError16(error, "ENOENT")) {
|
|
19330
20374
|
return null;
|
|
19331
20375
|
}
|
|
19332
20376
|
throw error;
|
|
19333
20377
|
}
|
|
19334
20378
|
);
|
|
19335
20379
|
return {
|
|
19336
|
-
config:
|
|
20380
|
+
config: toRecord15(existingRaw ? YAML3.parse(existingRaw) : {}),
|
|
19337
20381
|
existingRaw
|
|
19338
20382
|
};
|
|
19339
20383
|
}
|
|
@@ -19387,7 +20431,7 @@ async function writeProfileCreationState(paths, state) {
|
|
|
19387
20431
|
await writeJsonFile(profileCreationStatePath(paths), state);
|
|
19388
20432
|
}
|
|
19389
20433
|
async function readProfileCreationLogLines(paths) {
|
|
19390
|
-
const raw = await
|
|
20434
|
+
const raw = await readFile14(profileCreationLogPath(paths), "utf8").catch(() => "");
|
|
19391
20435
|
if (!raw.trim()) {
|
|
19392
20436
|
return [];
|
|
19393
20437
|
}
|
|
@@ -19396,10 +20440,10 @@ async function readProfileCreationLogLines(paths) {
|
|
|
19396
20440
|
);
|
|
19397
20441
|
}
|
|
19398
20442
|
function profileCreationStatePath(paths) {
|
|
19399
|
-
return
|
|
20443
|
+
return path21.join(paths.runDir, "profile-create-state.json");
|
|
19400
20444
|
}
|
|
19401
20445
|
function profileCreationLogPath(paths) {
|
|
19402
|
-
return
|
|
20446
|
+
return path21.join(paths.logsDir, PROFILE_CREATE_LOG_FILE);
|
|
19403
20447
|
}
|
|
19404
20448
|
async function clearProfileCreationLogFiles(paths) {
|
|
19405
20449
|
const primary = profileCreationLogPath(paths);
|
|
@@ -19412,8 +20456,8 @@ async function clearProfileCreationLogFiles(paths) {
|
|
|
19412
20456
|
]);
|
|
19413
20457
|
}
|
|
19414
20458
|
async function pathExists2(targetPath) {
|
|
19415
|
-
return await
|
|
19416
|
-
if (
|
|
20459
|
+
return await stat14(targetPath).then(() => true).catch((error) => {
|
|
20460
|
+
if (isNodeError16(error, "ENOENT")) {
|
|
19417
20461
|
return false;
|
|
19418
20462
|
}
|
|
19419
20463
|
throw error;
|
|
@@ -19445,7 +20489,7 @@ function ensureRecord2(target, key) {
|
|
|
19445
20489
|
target[key] = next;
|
|
19446
20490
|
return next;
|
|
19447
20491
|
}
|
|
19448
|
-
function
|
|
20492
|
+
function toRecord15(value) {
|
|
19449
20493
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
19450
20494
|
}
|
|
19451
20495
|
function cloneJson(value) {
|
|
@@ -19460,7 +20504,7 @@ function formatEnvValue2(value) {
|
|
|
19460
20504
|
function escapeRegExp3(value) {
|
|
19461
20505
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
19462
20506
|
}
|
|
19463
|
-
function
|
|
20507
|
+
function isNodeError16(error, code) {
|
|
19464
20508
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
19465
20509
|
}
|
|
19466
20510
|
|
|
@@ -19545,16 +20589,16 @@ function readProfilePermissionsInput(body) {
|
|
|
19545
20589
|
const approvals = readOptionalObject(body, "approvals");
|
|
19546
20590
|
if (approvals) {
|
|
19547
20591
|
input.approvals = {
|
|
19548
|
-
mode:
|
|
20592
|
+
mode: readString16(approvals, "mode") ?? readString16(approvals, "approval_mode") ?? readString16(approvals, "approvalMode") ?? void 0,
|
|
19549
20593
|
timeout: readPositiveInteger2(approvals.timeout),
|
|
19550
|
-
cronMode:
|
|
20594
|
+
cronMode: readString16(approvals, "cron_mode") ?? readString16(approvals, "cronMode") ?? void 0
|
|
19551
20595
|
};
|
|
19552
20596
|
}
|
|
19553
20597
|
const terminal = readOptionalObject(body, "terminal");
|
|
19554
20598
|
if (terminal) {
|
|
19555
20599
|
input.terminal = {
|
|
19556
|
-
backend:
|
|
19557
|
-
cwd:
|
|
20600
|
+
backend: readString16(terminal, "backend") ?? void 0,
|
|
20601
|
+
cwd: readString16(terminal, "cwd") ?? void 0,
|
|
19558
20602
|
containerCpu: readPositiveInteger2(
|
|
19559
20603
|
terminal.container_cpu ?? terminal.containerCpu
|
|
19560
20604
|
),
|
|
@@ -19670,10 +20714,10 @@ function toProfileToolConfigHttpError(error) {
|
|
|
19670
20714
|
import {
|
|
19671
20715
|
access as access3,
|
|
19672
20716
|
readdir as readdir10,
|
|
19673
|
-
readFile as
|
|
19674
|
-
stat as
|
|
20717
|
+
readFile as readFile15,
|
|
20718
|
+
stat as stat15
|
|
19675
20719
|
} from "fs/promises";
|
|
19676
|
-
import
|
|
20720
|
+
import path22 from "path";
|
|
19677
20721
|
import YAML4 from "yaml";
|
|
19678
20722
|
var ENTRY_DELIMITER = "\n\xA7\n";
|
|
19679
20723
|
var DEFAULT_MEMORY_LIMIT = 2200;
|
|
@@ -19861,9 +20905,9 @@ async function testHindsightProviderSettings(profileName, patch) {
|
|
|
19861
20905
|
const mode = normalizeHindsightMode(
|
|
19862
20906
|
patch.mode ?? config.mode ?? env.HINDSIGHT_MODE
|
|
19863
20907
|
);
|
|
19864
|
-
const apiUrl =
|
|
19865
|
-
const bankId =
|
|
19866
|
-
const apiKey =
|
|
20908
|
+
const apiUrl = readString17(patch.apiUrl) ?? readString17(config.api_url) ?? env.HINDSIGHT_API_URL ?? (mode === "cloud" ? HINDSIGHT_DEFAULT_API_URL : HINDSIGHT_DEFAULT_LOCAL_URL);
|
|
20909
|
+
const bankId = readString17(patch.bankId) ?? readString17(config.bank_id) ?? "hermes";
|
|
20910
|
+
const apiKey = readString17(patch.apiKey) ?? env.HINDSIGHT_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key);
|
|
19867
20911
|
const baseUrl = normalizeHttpUrl(apiUrl);
|
|
19868
20912
|
if (!baseUrl) {
|
|
19869
20913
|
return {
|
|
@@ -19995,7 +21039,7 @@ async function saveProviderSettings(profileName, provider, patch) {
|
|
|
19995
21039
|
});
|
|
19996
21040
|
await patchJsonProviderConfig(
|
|
19997
21041
|
profileName,
|
|
19998
|
-
|
|
21042
|
+
path22.join("hindsight", "config.json"),
|
|
19999
21043
|
{
|
|
20000
21044
|
mode: patch.mode,
|
|
20001
21045
|
api_url: patch.apiUrl,
|
|
@@ -20052,7 +21096,7 @@ async function patchCustomProviderConfig(profileName, provider, patch) {
|
|
|
20052
21096
|
"\u81EA\u5B9A\u4E49 memory provider \u914D\u7F6E\u5FC5\u987B\u662F\u6709\u6548\u7684 JSON object\u3002"
|
|
20053
21097
|
);
|
|
20054
21098
|
}
|
|
20055
|
-
const config =
|
|
21099
|
+
const config = toRecord16(parsed);
|
|
20056
21100
|
if (Object.keys(config).length === 0 && parsed !== null) {
|
|
20057
21101
|
throw new HermesMemoryError(
|
|
20058
21102
|
"memory_provider_config_invalid",
|
|
@@ -20143,17 +21187,17 @@ function normalizeCustomProviderId(provider) {
|
|
|
20143
21187
|
}
|
|
20144
21188
|
async function patchHermesMemoryProvider(profileName, provider) {
|
|
20145
21189
|
const configPath = resolveHermesConfigPath(profileName);
|
|
20146
|
-
const existingRaw = await
|
|
21190
|
+
const existingRaw = await readFile15(configPath, "utf8").catch(
|
|
20147
21191
|
(error) => {
|
|
20148
|
-
if (
|
|
21192
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20149
21193
|
return null;
|
|
20150
21194
|
}
|
|
20151
21195
|
throw error;
|
|
20152
21196
|
}
|
|
20153
21197
|
);
|
|
20154
21198
|
const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
|
|
20155
|
-
const config =
|
|
20156
|
-
const memory =
|
|
21199
|
+
const config = toRecord16(document.toJSON());
|
|
21200
|
+
const memory = toRecord16(config.memory);
|
|
20157
21201
|
memory.provider = provider === "built-in" ? "" : provider;
|
|
20158
21202
|
config.memory = memory;
|
|
20159
21203
|
const backupPath = existingRaw ? `${configPath}.bak.${Date.now()}` : null;
|
|
@@ -20166,13 +21210,13 @@ async function patchHermesMemoryProvider(profileName, provider) {
|
|
|
20166
21210
|
await atomicWriteFilePreservingMetadata(configPath, document.toString());
|
|
20167
21211
|
}
|
|
20168
21212
|
function resolveMemoryDir(profileName) {
|
|
20169
|
-
return
|
|
21213
|
+
return path22.join(resolveHermesProfileDir(profileName), "memories");
|
|
20170
21214
|
}
|
|
20171
21215
|
async function readMemoryStore(profileName, target, limits) {
|
|
20172
21216
|
const filePath = memoryFilePath(profileName, target);
|
|
20173
21217
|
const entries = await readMemoryEntries(filePath);
|
|
20174
|
-
const fileStat = await
|
|
20175
|
-
if (
|
|
21218
|
+
const fileStat = await stat15(filePath).catch((error) => {
|
|
21219
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20176
21220
|
return null;
|
|
20177
21221
|
}
|
|
20178
21222
|
throw error;
|
|
@@ -20200,8 +21244,8 @@ async function readMemoryStore(profileName, target, limits) {
|
|
|
20200
21244
|
};
|
|
20201
21245
|
}
|
|
20202
21246
|
async function readMemoryEntries(filePath) {
|
|
20203
|
-
const raw = await
|
|
20204
|
-
if (
|
|
21247
|
+
const raw = await readFile15(filePath, "utf8").catch((error) => {
|
|
21248
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20205
21249
|
return "";
|
|
20206
21250
|
}
|
|
20207
21251
|
throw error;
|
|
@@ -20227,7 +21271,7 @@ async function writeMemoryEntries(profileName, target, entries) {
|
|
|
20227
21271
|
);
|
|
20228
21272
|
}
|
|
20229
21273
|
function memoryFilePath(profileName, target) {
|
|
20230
|
-
return
|
|
21274
|
+
return path22.join(
|
|
20231
21275
|
resolveMemoryDir(profileName),
|
|
20232
21276
|
target === "user" ? "USER.md" : "MEMORY.md"
|
|
20233
21277
|
);
|
|
@@ -20287,7 +21331,7 @@ async function readCustomProviderSetupSummary(profileName) {
|
|
|
20287
21331
|
configurable: true,
|
|
20288
21332
|
configured: true,
|
|
20289
21333
|
configurationIssue: null,
|
|
20290
|
-
providerConfigPath:
|
|
21334
|
+
providerConfigPath: path22.join(
|
|
20291
21335
|
resolveHermesProfileDir(profileName),
|
|
20292
21336
|
"<provider>.json"
|
|
20293
21337
|
),
|
|
@@ -20365,7 +21409,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20365
21409
|
const config2 = await readJsonObject(
|
|
20366
21410
|
memoryProviderConfigPath(profileName, "honcho") ?? ""
|
|
20367
21411
|
);
|
|
20368
|
-
return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(
|
|
21412
|
+
return isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString17(config2.apiKey)) || isConfiguredEnvValue(readString17(config2.api_key)) || isConfiguredEnvValue(readString17(config2.baseUrl)) ? { configured: true, issue: null } : {
|
|
20369
21413
|
configured: false,
|
|
20370
21414
|
issue: "Honcho \u9700\u8981\u5148\u586B\u5199 API Key\uFF0C\u6216\u5728 honcho.json \u914D\u7F6E self-hosted baseUrl\u3002"
|
|
20371
21415
|
};
|
|
@@ -20374,7 +21418,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20374
21418
|
const config2 = await readJsonObject(
|
|
20375
21419
|
memoryProviderConfigPath(profileName, "mem0") ?? ""
|
|
20376
21420
|
);
|
|
20377
|
-
return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(
|
|
21421
|
+
return isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString17(config2.api_key)) ? { configured: true, issue: null } : {
|
|
20378
21422
|
configured: false,
|
|
20379
21423
|
issue: "Mem0 \u9700\u8981\u5148\u5728\u672C\u9875\u586B\u5199 API Key\uFF0CLink \u4F1A\u5199\u5165\u5F53\u524D Profile \u7684 .env\u3002"
|
|
20380
21424
|
};
|
|
@@ -20416,7 +21460,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20416
21460
|
memoryProviderConfigPath(profileName, provider) ?? ""
|
|
20417
21461
|
);
|
|
20418
21462
|
const mode = normalizeHindsightMode(config.mode ?? env.HINDSIGHT_MODE);
|
|
20419
|
-
const apiKey =
|
|
21463
|
+
const apiKey = readString17(config.apiKey) ?? readString17(config.api_key) ?? env.HINDSIGHT_API_KEY;
|
|
20420
21464
|
if (mode === "cloud") {
|
|
20421
21465
|
return isConfiguredEnvValue(apiKey) ? { configured: true, issue: null } : {
|
|
20422
21466
|
configured: false,
|
|
@@ -20424,15 +21468,15 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20424
21468
|
};
|
|
20425
21469
|
}
|
|
20426
21470
|
if (mode === "local_external") {
|
|
20427
|
-
const apiUrl =
|
|
21471
|
+
const apiUrl = readString17(config.api_url) ?? env.HINDSIGHT_API_URL ?? HINDSIGHT_DEFAULT_LOCAL_URL;
|
|
20428
21472
|
return isConfiguredEnvValue(apiUrl) ? { configured: true, issue: null } : {
|
|
20429
21473
|
configured: false,
|
|
20430
21474
|
issue: "Hindsight local_external \u9700\u8981\u914D\u7F6E\u53EF\u8BBF\u95EE\u7684 API URL\u3002"
|
|
20431
21475
|
};
|
|
20432
21476
|
}
|
|
20433
21477
|
if (mode === "local_embedded") {
|
|
20434
|
-
const llmProvider =
|
|
20435
|
-
const llmModel =
|
|
21478
|
+
const llmProvider = readString17(config.llm_provider) ?? "openai";
|
|
21479
|
+
const llmModel = readString17(config.llm_model);
|
|
20436
21480
|
if (!llmModel) {
|
|
20437
21481
|
return {
|
|
20438
21482
|
configured: false,
|
|
@@ -20440,7 +21484,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20440
21484
|
};
|
|
20441
21485
|
}
|
|
20442
21486
|
if (llmProvider === "openai_compatible" && !isConfiguredEnvValue(
|
|
20443
|
-
|
|
21487
|
+
readString17(config.llm_base_url) ?? env.HINDSIGHT_API_LLM_BASE_URL
|
|
20444
21488
|
)) {
|
|
20445
21489
|
return {
|
|
20446
21490
|
configured: false,
|
|
@@ -20448,7 +21492,7 @@ async function readProviderConfigurationStatus(profileName, provider) {
|
|
|
20448
21492
|
};
|
|
20449
21493
|
}
|
|
20450
21494
|
if (!["ollama", "lmstudio", "openai_compatible"].includes(llmProvider) && !isConfiguredEnvValue(
|
|
20451
|
-
|
|
21495
|
+
readString17(config.llmApiKey) ?? readString17(config.llm_api_key) ?? env.HINDSIGHT_LLM_API_KEY
|
|
20452
21496
|
)) {
|
|
20453
21497
|
return {
|
|
20454
21498
|
configured: false,
|
|
@@ -20504,8 +21548,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20504
21548
|
secretSetting(
|
|
20505
21549
|
"apiKey",
|
|
20506
21550
|
"API Key",
|
|
20507
|
-
env.HONCHO_API_KEY ??
|
|
20508
|
-
isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(
|
|
21551
|
+
env.HONCHO_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
|
|
21552
|
+
isConfiguredEnvValue(env.HONCHO_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
|
|
20509
21553
|
),
|
|
20510
21554
|
stringSetting("workspace", "Workspace", config.workspace ?? "hermes"),
|
|
20511
21555
|
stringSetting("peerName", "\u7528\u6237 Peer", config.peerName ?? ""),
|
|
@@ -20547,8 +21591,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20547
21591
|
secretSetting(
|
|
20548
21592
|
"apiKey",
|
|
20549
21593
|
"API Key",
|
|
20550
|
-
env.MEM0_API_KEY ??
|
|
20551
|
-
isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(
|
|
21594
|
+
env.MEM0_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
|
|
21595
|
+
isConfiguredEnvValue(env.MEM0_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
|
|
20552
21596
|
),
|
|
20553
21597
|
stringSetting("userId", "User ID", config.user_id ?? "hermes-user"),
|
|
20554
21598
|
stringSetting("agentId", "Agent ID", config.agent_id ?? "hermes"),
|
|
@@ -20616,8 +21660,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20616
21660
|
memoryProviderConfigPath(profileName, provider) ?? ""
|
|
20617
21661
|
);
|
|
20618
21662
|
const env = await readHermesMemoryEnv(profileName);
|
|
20619
|
-
const banks =
|
|
20620
|
-
const hermesBank =
|
|
21663
|
+
const banks = toRecord16(config.banks);
|
|
21664
|
+
const hermesBank = toRecord16(banks.hermes);
|
|
20621
21665
|
const mode = normalizeHindsightMode(config.mode);
|
|
20622
21666
|
return [
|
|
20623
21667
|
selectSetting("mode", "\u8FDE\u63A5\u6A21\u5F0F", mode, [
|
|
@@ -20633,8 +21677,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20633
21677
|
secretSetting(
|
|
20634
21678
|
"apiKey",
|
|
20635
21679
|
"Hindsight API Key",
|
|
20636
|
-
env.HINDSIGHT_API_KEY ??
|
|
20637
|
-
isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(
|
|
21680
|
+
env.HINDSIGHT_API_KEY ?? readString17(config.apiKey) ?? readString17(config.api_key),
|
|
21681
|
+
isConfiguredEnvValue(env.HINDSIGHT_API_KEY) || isConfiguredEnvValue(readString17(config.apiKey)) || isConfiguredEnvValue(readString17(config.api_key))
|
|
20638
21682
|
),
|
|
20639
21683
|
stringSetting(
|
|
20640
21684
|
"bankId",
|
|
@@ -20656,8 +21700,8 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20656
21700
|
secretSetting(
|
|
20657
21701
|
"llmApiKey",
|
|
20658
21702
|
"LLM API Key",
|
|
20659
|
-
env.HINDSIGHT_LLM_API_KEY ??
|
|
20660
|
-
isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(
|
|
21703
|
+
env.HINDSIGHT_LLM_API_KEY ?? readString17(config.llmApiKey) ?? readString17(config.llm_api_key),
|
|
21704
|
+
isConfiguredEnvValue(env.HINDSIGHT_LLM_API_KEY) || isConfiguredEnvValue(readString17(config.llmApiKey)) || isConfiguredEnvValue(readString17(config.llm_api_key))
|
|
20661
21705
|
),
|
|
20662
21706
|
booleanSetting("autoRecall", "\u81EA\u52A8\u56DE\u5FC6", config.auto_recall ?? true),
|
|
20663
21707
|
booleanSetting("autoRetain", "\u81EA\u52A8\u6C89\u6DC0", config.auto_retain ?? true),
|
|
@@ -20681,7 +21725,7 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20681
21725
|
stringSetting(
|
|
20682
21726
|
"dbPath",
|
|
20683
21727
|
"SQLite \u6570\u636E\u5E93\u8DEF\u5F84",
|
|
20684
|
-
config.db_path ??
|
|
21728
|
+
config.db_path ?? path22.join(resolveHermesProfileDir(profileName), "memory_store.db")
|
|
20685
21729
|
),
|
|
20686
21730
|
booleanSetting("autoExtract", "\u4F1A\u8BDD\u7ED3\u675F\u81EA\u52A8\u62BD\u53D6", config.auto_extract ?? false),
|
|
20687
21731
|
numberSetting("defaultTrust", "\u9ED8\u8BA4\u4FE1\u4EFB\u5206", config.default_trust ?? 0.5),
|
|
@@ -20717,7 +21761,7 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20717
21761
|
stringSetting(
|
|
20718
21762
|
"workingDirectory",
|
|
20719
21763
|
"\u5DE5\u4F5C\u76EE\u5F55",
|
|
20720
|
-
|
|
21764
|
+
path22.join(resolveHermesProfileDir(profileName), "byterover"),
|
|
20721
21765
|
false
|
|
20722
21766
|
)
|
|
20723
21767
|
];
|
|
@@ -20726,16 +21770,16 @@ async function readProviderSettings(profileName, provider) {
|
|
|
20726
21770
|
}
|
|
20727
21771
|
function memoryProviderConfigPath(profileName, provider) {
|
|
20728
21772
|
if (provider === "honcho") {
|
|
20729
|
-
return
|
|
21773
|
+
return path22.join(resolveHermesProfileDir(profileName), "honcho.json");
|
|
20730
21774
|
}
|
|
20731
21775
|
if (provider === "mem0") {
|
|
20732
|
-
return
|
|
21776
|
+
return path22.join(resolveHermesProfileDir(profileName), "mem0.json");
|
|
20733
21777
|
}
|
|
20734
21778
|
if (provider === "supermemory") {
|
|
20735
|
-
return
|
|
21779
|
+
return path22.join(resolveHermesProfileDir(profileName), "supermemory.json");
|
|
20736
21780
|
}
|
|
20737
21781
|
if (provider === "hindsight") {
|
|
20738
|
-
return
|
|
21782
|
+
return path22.join(
|
|
20739
21783
|
resolveHermesProfileDir(profileName),
|
|
20740
21784
|
"hindsight",
|
|
20741
21785
|
"config.json"
|
|
@@ -20744,21 +21788,21 @@ function memoryProviderConfigPath(profileName, provider) {
|
|
|
20744
21788
|
return null;
|
|
20745
21789
|
}
|
|
20746
21790
|
function customProviderConfigPath(profileName, provider) {
|
|
20747
|
-
return
|
|
21791
|
+
return path22.join(
|
|
20748
21792
|
resolveHermesProfileDir(profileName),
|
|
20749
21793
|
`${normalizeCustomProviderId(provider)}.json`
|
|
20750
21794
|
);
|
|
20751
21795
|
}
|
|
20752
21796
|
function customProviderRegistryPath(profileName) {
|
|
20753
|
-
return
|
|
21797
|
+
return path22.join(
|
|
20754
21798
|
resolveHermesProfileDir(profileName),
|
|
20755
21799
|
CUSTOM_PROVIDER_REGISTRY_FILE
|
|
20756
21800
|
);
|
|
20757
21801
|
}
|
|
20758
21802
|
async function readCustomProviderRegistry(profileName) {
|
|
20759
|
-
const raw = await
|
|
21803
|
+
const raw = await readFile15(customProviderRegistryPath(profileName), "utf8").catch(
|
|
20760
21804
|
(error) => {
|
|
20761
|
-
if (
|
|
21805
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20762
21806
|
return "";
|
|
20763
21807
|
}
|
|
20764
21808
|
throw error;
|
|
@@ -20769,18 +21813,18 @@ async function readCustomProviderRegistry(profileName) {
|
|
|
20769
21813
|
}
|
|
20770
21814
|
try {
|
|
20771
21815
|
const parsed = JSON.parse(raw);
|
|
20772
|
-
const providers = Array.isArray(parsed) ? parsed : Array.isArray(
|
|
21816
|
+
const providers = Array.isArray(parsed) ? parsed : Array.isArray(toRecord16(parsed).providers) ? toRecord16(parsed).providers : [];
|
|
20773
21817
|
return providers.map((item) => {
|
|
20774
21818
|
if (typeof item === "string") {
|
|
20775
21819
|
const id2 = normalizeCustomProviderId(item);
|
|
20776
21820
|
return { id: id2, label: id2, description: "\u81EA\u5B9A\u4E49 memory provider\u3002" };
|
|
20777
21821
|
}
|
|
20778
|
-
const record =
|
|
20779
|
-
const id = normalizeCustomProviderId(
|
|
21822
|
+
const record = toRecord16(item);
|
|
21823
|
+
const id = normalizeCustomProviderId(readString17(record.id) ?? "");
|
|
20780
21824
|
return {
|
|
20781
21825
|
id,
|
|
20782
|
-
label:
|
|
20783
|
-
description:
|
|
21826
|
+
label: readString17(record.label) ?? id,
|
|
21827
|
+
description: readString17(record.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
|
|
20784
21828
|
};
|
|
20785
21829
|
}).filter((item) => item.id);
|
|
20786
21830
|
} catch {
|
|
@@ -20802,10 +21846,10 @@ async function saveCustomProviderRegistryEntry(profileName, provider) {
|
|
|
20802
21846
|
);
|
|
20803
21847
|
}
|
|
20804
21848
|
async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
20805
|
-
const pluginsDir =
|
|
21849
|
+
const pluginsDir = path22.join(resolveHermesProfileDir(profileName), "plugins");
|
|
20806
21850
|
const entries = await readdir10(pluginsDir, { withFileTypes: true }).catch(
|
|
20807
21851
|
(error) => {
|
|
20808
|
-
if (
|
|
21852
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20809
21853
|
return [];
|
|
20810
21854
|
}
|
|
20811
21855
|
throw error;
|
|
@@ -20822,21 +21866,21 @@ async function discoverUserMemoryProviderDescriptors(profileName) {
|
|
|
20822
21866
|
} catch {
|
|
20823
21867
|
continue;
|
|
20824
21868
|
}
|
|
20825
|
-
const providerDir =
|
|
21869
|
+
const providerDir = path22.join(pluginsDir, entry.name);
|
|
20826
21870
|
if (!await isMemoryProviderPluginDir(providerDir)) {
|
|
20827
21871
|
continue;
|
|
20828
21872
|
}
|
|
20829
21873
|
const meta = await readPluginMetadata(providerDir);
|
|
20830
21874
|
descriptors.push({
|
|
20831
21875
|
id: providerId,
|
|
20832
|
-
label:
|
|
20833
|
-
description:
|
|
21876
|
+
label: readString17(meta.name) ?? providerId,
|
|
21877
|
+
description: readString17(meta.description) ?? "\u81EA\u5B9A\u4E49 memory provider\u3002"
|
|
20834
21878
|
});
|
|
20835
21879
|
}
|
|
20836
21880
|
return descriptors;
|
|
20837
21881
|
}
|
|
20838
21882
|
async function isUserMemoryProviderInstalled(profileName, provider) {
|
|
20839
|
-
const providerDir =
|
|
21883
|
+
const providerDir = path22.join(
|
|
20840
21884
|
resolveHermesProfileDir(profileName),
|
|
20841
21885
|
"plugins",
|
|
20842
21886
|
normalizeCustomProviderId(provider)
|
|
@@ -20844,9 +21888,9 @@ async function isUserMemoryProviderInstalled(profileName, provider) {
|
|
|
20844
21888
|
return isMemoryProviderPluginDir(providerDir);
|
|
20845
21889
|
}
|
|
20846
21890
|
async function isMemoryProviderPluginDir(providerDir) {
|
|
20847
|
-
const source = await
|
|
21891
|
+
const source = await readFile15(path22.join(providerDir, "__init__.py"), "utf8").catch(
|
|
20848
21892
|
(error) => {
|
|
20849
|
-
if (
|
|
21893
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20850
21894
|
return "";
|
|
20851
21895
|
}
|
|
20852
21896
|
throw error;
|
|
@@ -20856,22 +21900,22 @@ async function isMemoryProviderPluginDir(providerDir) {
|
|
|
20856
21900
|
return sample.includes("register_memory_provider") || sample.includes("MemoryProvider");
|
|
20857
21901
|
}
|
|
20858
21902
|
async function readPluginMetadata(providerDir) {
|
|
20859
|
-
const raw = await
|
|
21903
|
+
const raw = await readFile15(path22.join(providerDir, "plugin.yaml"), "utf8").catch(
|
|
20860
21904
|
(error) => {
|
|
20861
|
-
if (
|
|
21905
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20862
21906
|
return "";
|
|
20863
21907
|
}
|
|
20864
21908
|
throw error;
|
|
20865
21909
|
}
|
|
20866
21910
|
);
|
|
20867
|
-
return raw ?
|
|
21911
|
+
return raw ? toRecord16(YAML4.parse(raw)) : {};
|
|
20868
21912
|
}
|
|
20869
21913
|
async function resolveByteRoverCli() {
|
|
20870
21914
|
const candidates = [
|
|
20871
|
-
...(process.env.PATH ?? "").split(
|
|
20872
|
-
|
|
21915
|
+
...(process.env.PATH ?? "").split(path22.delimiter).filter(Boolean).map((dir) => path22.join(dir, "brv")),
|
|
21916
|
+
path22.join(process.env.HOME ?? "", ".brv-cli", "bin", "brv"),
|
|
20873
21917
|
"/usr/local/bin/brv",
|
|
20874
|
-
|
|
21918
|
+
path22.join(process.env.HOME ?? "", ".npm-global", "bin", "brv")
|
|
20875
21919
|
].filter(Boolean);
|
|
20876
21920
|
for (const candidate of candidates) {
|
|
20877
21921
|
const found = await access3(candidate).then(() => true).catch(() => false);
|
|
@@ -20882,32 +21926,32 @@ async function resolveByteRoverCli() {
|
|
|
20882
21926
|
return null;
|
|
20883
21927
|
}
|
|
20884
21928
|
async function readHolographicProviderConfig(profileName) {
|
|
20885
|
-
const raw = await
|
|
21929
|
+
const raw = await readFile15(resolveHermesConfigPath(profileName), "utf8").catch(
|
|
20886
21930
|
(error) => {
|
|
20887
|
-
if (
|
|
21931
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20888
21932
|
return "";
|
|
20889
21933
|
}
|
|
20890
21934
|
throw error;
|
|
20891
21935
|
}
|
|
20892
21936
|
);
|
|
20893
|
-
const config = raw ?
|
|
20894
|
-
const plugins =
|
|
20895
|
-
return
|
|
21937
|
+
const config = raw ? toRecord16(YAML4.parse(raw)) : {};
|
|
21938
|
+
const plugins = toRecord16(config.plugins);
|
|
21939
|
+
return toRecord16(plugins["hermes-memory-store"]);
|
|
20896
21940
|
}
|
|
20897
21941
|
async function patchHolographicProviderConfig(profileName, patch) {
|
|
20898
21942
|
const configPath = resolveHermesConfigPath(profileName);
|
|
20899
|
-
const existingRaw = await
|
|
21943
|
+
const existingRaw = await readFile15(configPath, "utf8").catch(
|
|
20900
21944
|
(error) => {
|
|
20901
|
-
if (
|
|
21945
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20902
21946
|
return null;
|
|
20903
21947
|
}
|
|
20904
21948
|
throw error;
|
|
20905
21949
|
}
|
|
20906
21950
|
);
|
|
20907
21951
|
const document = existingRaw ? YAML4.parseDocument(existingRaw) : new YAML4.Document({});
|
|
20908
|
-
const config =
|
|
20909
|
-
const plugins =
|
|
20910
|
-
const memoryStore =
|
|
21952
|
+
const config = toRecord16(document.toJSON());
|
|
21953
|
+
const plugins = toRecord16(config.plugins);
|
|
21954
|
+
const memoryStore = toRecord16(plugins["hermes-memory-store"]);
|
|
20911
21955
|
for (const [key, value] of Object.entries(patch)) {
|
|
20912
21956
|
if (value !== void 0) {
|
|
20913
21957
|
memoryStore[key] = value;
|
|
@@ -20932,9 +21976,9 @@ async function patchHermesMemoryEnv(profileName, patch) {
|
|
|
20932
21976
|
if (entries.length === 0) {
|
|
20933
21977
|
return;
|
|
20934
21978
|
}
|
|
20935
|
-
const envPath =
|
|
20936
|
-
const existingRaw = await
|
|
20937
|
-
if (
|
|
21979
|
+
const envPath = path22.join(resolveHermesProfileDir(profileName), ".env");
|
|
21980
|
+
const existingRaw = await readFile15(envPath, "utf8").catch((error) => {
|
|
21981
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
20938
21982
|
return "";
|
|
20939
21983
|
}
|
|
20940
21984
|
throw error;
|
|
@@ -20992,7 +22036,7 @@ function isMemoryEnvKeyWritable(key) {
|
|
|
20992
22036
|
].includes(key);
|
|
20993
22037
|
}
|
|
20994
22038
|
function normalizeHindsightMode(value) {
|
|
20995
|
-
const mode =
|
|
22039
|
+
const mode = readString17(value) ?? "cloud";
|
|
20996
22040
|
return mode === "local" ? "local_embedded" : mode;
|
|
20997
22041
|
}
|
|
20998
22042
|
function normalizeHttpUrl(value) {
|
|
@@ -21055,55 +22099,55 @@ function joinHindsightUrl(baseUrl, pathName) {
|
|
|
21055
22099
|
}
|
|
21056
22100
|
function parseJsonObject2(text) {
|
|
21057
22101
|
try {
|
|
21058
|
-
return
|
|
22102
|
+
return toRecord16(JSON.parse(text));
|
|
21059
22103
|
} catch {
|
|
21060
22104
|
return {};
|
|
21061
22105
|
}
|
|
21062
22106
|
}
|
|
21063
22107
|
function readHindsightError(json) {
|
|
21064
|
-
const detail =
|
|
22108
|
+
const detail = readString17(json.detail) ?? readString17(json.error);
|
|
21065
22109
|
return detail ? `\uFF1A${detail}` : "";
|
|
21066
22110
|
}
|
|
21067
22111
|
function hindsightSemanticIssue(pathName, json) {
|
|
21068
22112
|
if (pathName === "/health") {
|
|
21069
|
-
const status =
|
|
22113
|
+
const status = readString17(json.status);
|
|
21070
22114
|
return status && ["healthy", "ok"].includes(status.toLowerCase()) ? null : `\u5065\u5EB7\u72B6\u6001\u5F02\u5E38\uFF1A${status ?? "unknown"}`;
|
|
21071
22115
|
}
|
|
21072
22116
|
return null;
|
|
21073
22117
|
}
|
|
21074
22118
|
function summarizeHindsightProbe(pathName, json) {
|
|
21075
22119
|
if (pathName === "/health") {
|
|
21076
|
-
const status =
|
|
21077
|
-
const database =
|
|
22120
|
+
const status = readString17(json.status) ?? "ok";
|
|
22121
|
+
const database = readString17(json.database);
|
|
21078
22122
|
return database ? `${status}, database ${database}` : status;
|
|
21079
22123
|
}
|
|
21080
22124
|
if (pathName === "/version") {
|
|
21081
|
-
const version =
|
|
22125
|
+
const version = readString17(json.api_version);
|
|
21082
22126
|
return version ? `API ${version}` : "version endpoint reachable";
|
|
21083
22127
|
}
|
|
21084
|
-
const bankId =
|
|
22128
|
+
const bankId = readString17(json.bank_id);
|
|
21085
22129
|
return bankId ? `bank ${bankId} reachable` : "bank config reachable";
|
|
21086
22130
|
}
|
|
21087
22131
|
async function readActiveMemoryProvider(profileName) {
|
|
21088
|
-
const raw = await
|
|
22132
|
+
const raw = await readFile15(
|
|
21089
22133
|
resolveHermesConfigPath(profileName),
|
|
21090
22134
|
"utf8"
|
|
21091
22135
|
).catch((error) => {
|
|
21092
|
-
if (
|
|
22136
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
21093
22137
|
return "";
|
|
21094
22138
|
}
|
|
21095
22139
|
throw error;
|
|
21096
22140
|
});
|
|
21097
|
-
const config = raw ?
|
|
21098
|
-
const memory =
|
|
21099
|
-
const provider =
|
|
22141
|
+
const config = raw ? toRecord16(YAML4.parse(raw)) : {};
|
|
22142
|
+
const memory = toRecord16(config.memory);
|
|
22143
|
+
const provider = readString17(memory.provider);
|
|
21100
22144
|
if (!provider || provider === "built-in" || provider === "builtin" || provider === "built_in") {
|
|
21101
22145
|
return null;
|
|
21102
22146
|
}
|
|
21103
22147
|
return provider;
|
|
21104
22148
|
}
|
|
21105
22149
|
async function patchJsonProviderConfig(profileName, relativePath, patch) {
|
|
21106
|
-
const configPath =
|
|
22150
|
+
const configPath = path22.join(
|
|
21107
22151
|
resolveHermesProfileDir(profileName),
|
|
21108
22152
|
relativePath
|
|
21109
22153
|
);
|
|
@@ -21121,18 +22165,18 @@ async function patchJsonProviderConfig(profileName, relativePath, patch) {
|
|
|
21121
22165
|
);
|
|
21122
22166
|
}
|
|
21123
22167
|
async function readJsonObject(filePath) {
|
|
21124
|
-
const raw = await
|
|
21125
|
-
if (
|
|
22168
|
+
const raw = await readFile15(filePath, "utf8").catch((error) => {
|
|
22169
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
21126
22170
|
return "{}";
|
|
21127
22171
|
}
|
|
21128
22172
|
throw error;
|
|
21129
22173
|
});
|
|
21130
22174
|
try {
|
|
21131
|
-
return
|
|
22175
|
+
return toRecord16(JSON.parse(raw || "{}"));
|
|
21132
22176
|
} catch {
|
|
21133
22177
|
throw new HermesMemoryError(
|
|
21134
22178
|
"memory_provider_config_invalid",
|
|
21135
|
-
`${
|
|
22179
|
+
`${path22.basename(filePath)} \u4E0D\u662F\u6709\u6548\u7684 JSON \u914D\u7F6E\u6587\u4EF6\u3002`
|
|
21136
22180
|
);
|
|
21137
22181
|
}
|
|
21138
22182
|
}
|
|
@@ -21153,7 +22197,7 @@ function stringSetting(key, label, value, editable = true) {
|
|
|
21153
22197
|
return {
|
|
21154
22198
|
key,
|
|
21155
22199
|
label,
|
|
21156
|
-
value:
|
|
22200
|
+
value: readString17(value) ?? "",
|
|
21157
22201
|
editable,
|
|
21158
22202
|
kind: "string"
|
|
21159
22203
|
};
|
|
@@ -21165,7 +22209,7 @@ function secretSetting(key, label, value, configured) {
|
|
|
21165
22209
|
value: "",
|
|
21166
22210
|
editable: true,
|
|
21167
22211
|
kind: "secret",
|
|
21168
|
-
configured: configured || isConfiguredEnvValue(
|
|
22212
|
+
configured: configured || isConfiguredEnvValue(readString17(value))
|
|
21169
22213
|
};
|
|
21170
22214
|
}
|
|
21171
22215
|
function textSetting(key, label, value, editable = true) {
|
|
@@ -21178,21 +22222,21 @@ function textSetting(key, label, value, editable = true) {
|
|
|
21178
22222
|
};
|
|
21179
22223
|
}
|
|
21180
22224
|
function selectSetting(key, label, value, options, editable = true) {
|
|
21181
|
-
const stringValue =
|
|
22225
|
+
const stringValue = readString17(value) ?? options[0] ?? null;
|
|
21182
22226
|
return { key, label, value: stringValue, editable, kind: "select", options };
|
|
21183
22227
|
}
|
|
21184
22228
|
async function readMemoryLimits(profileName) {
|
|
21185
|
-
const raw = await
|
|
22229
|
+
const raw = await readFile15(
|
|
21186
22230
|
resolveHermesConfigPath(profileName),
|
|
21187
22231
|
"utf8"
|
|
21188
22232
|
).catch((error) => {
|
|
21189
|
-
if (
|
|
22233
|
+
if (isNodeError17(error, "ENOENT")) {
|
|
21190
22234
|
return "";
|
|
21191
22235
|
}
|
|
21192
22236
|
throw error;
|
|
21193
22237
|
});
|
|
21194
|
-
const config = raw ?
|
|
21195
|
-
const memory =
|
|
22238
|
+
const config = raw ? toRecord16(YAML4.parse(raw)) : {};
|
|
22239
|
+
const memory = toRecord16(config.memory);
|
|
21196
22240
|
return {
|
|
21197
22241
|
memory: readPositiveInteger3(memory.memory_char_limit) ?? DEFAULT_MEMORY_LIMIT,
|
|
21198
22242
|
user: readPositiveInteger3(memory.user_char_limit) ?? DEFAULT_USER_LIMIT
|
|
@@ -21248,10 +22292,10 @@ function hashString(value) {
|
|
|
21248
22292
|
}
|
|
21249
22293
|
return hash.toString(16);
|
|
21250
22294
|
}
|
|
21251
|
-
function
|
|
22295
|
+
function toRecord16(value) {
|
|
21252
22296
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
21253
22297
|
}
|
|
21254
|
-
function
|
|
22298
|
+
function readString17(value) {
|
|
21255
22299
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
21256
22300
|
}
|
|
21257
22301
|
function readPositiveInteger3(value) {
|
|
@@ -21279,7 +22323,7 @@ function formatEnvValue3(value) {
|
|
|
21279
22323
|
function escapeRegExp4(value) {
|
|
21280
22324
|
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
21281
22325
|
}
|
|
21282
|
-
function
|
|
22326
|
+
function isNodeError17(error, code) {
|
|
21283
22327
|
return error instanceof Error && "code" in error && error.code === code;
|
|
21284
22328
|
}
|
|
21285
22329
|
|
|
@@ -21410,7 +22454,7 @@ function registerProfileMemoryRoutes(router, options) {
|
|
|
21410
22454
|
);
|
|
21411
22455
|
}
|
|
21412
22456
|
function readMemoryTarget(body) {
|
|
21413
|
-
const raw =
|
|
22457
|
+
const raw = readString16(body, "target");
|
|
21414
22458
|
if (raw === "memory" || raw === "user") {
|
|
21415
22459
|
return raw;
|
|
21416
22460
|
}
|
|
@@ -21421,7 +22465,7 @@ function readMemoryTarget(body) {
|
|
|
21421
22465
|
);
|
|
21422
22466
|
}
|
|
21423
22467
|
function readMemoryResetTarget(body) {
|
|
21424
|
-
const raw =
|
|
22468
|
+
const raw = readString16(body, "target") ?? "all";
|
|
21425
22469
|
if (raw === "all" || raw === "memory" || raw === "user") {
|
|
21426
22470
|
return raw;
|
|
21427
22471
|
}
|
|
@@ -21432,7 +22476,7 @@ function readMemoryResetTarget(body) {
|
|
|
21432
22476
|
);
|
|
21433
22477
|
}
|
|
21434
22478
|
function readRequiredMemoryContent(body) {
|
|
21435
|
-
const content =
|
|
22479
|
+
const content = readString16(body, "content") ?? readString16(body, "text");
|
|
21436
22480
|
if (!content) {
|
|
21437
22481
|
throw new LinkHttpError(
|
|
21438
22482
|
400,
|
|
@@ -21443,7 +22487,7 @@ function readRequiredMemoryContent(body) {
|
|
|
21443
22487
|
return content;
|
|
21444
22488
|
}
|
|
21445
22489
|
function readRequiredMemoryMatch(body) {
|
|
21446
|
-
const oldText =
|
|
22490
|
+
const oldText = readString16(body, "old_text") ?? readString16(body, "oldText") ?? readString16(body, "match");
|
|
21447
22491
|
if (!oldText) {
|
|
21448
22492
|
throw new LinkHttpError(
|
|
21449
22493
|
400,
|
|
@@ -21454,7 +22498,7 @@ function readRequiredMemoryMatch(body) {
|
|
|
21454
22498
|
return oldText;
|
|
21455
22499
|
}
|
|
21456
22500
|
function readRequiredMemoryProvider(body) {
|
|
21457
|
-
const provider =
|
|
22501
|
+
const provider = readString16(body, "provider") ?? readString16(body, "provider_id") ?? readString16(body, "providerId");
|
|
21458
22502
|
if (!provider) {
|
|
21459
22503
|
throw new LinkHttpError(
|
|
21460
22504
|
400,
|
|
@@ -21466,7 +22510,7 @@ function readRequiredMemoryProvider(body) {
|
|
|
21466
22510
|
}
|
|
21467
22511
|
function readMemorySettingsPatch(body) {
|
|
21468
22512
|
const input = {};
|
|
21469
|
-
const mode =
|
|
22513
|
+
const mode = readString16(body, "mode");
|
|
21470
22514
|
if (mode) {
|
|
21471
22515
|
input.mode = mode;
|
|
21472
22516
|
}
|
|
@@ -21482,7 +22526,7 @@ function readMemorySettingsPatch(body) {
|
|
|
21482
22526
|
if (bankId !== void 0) {
|
|
21483
22527
|
input.bankId = bankId;
|
|
21484
22528
|
}
|
|
21485
|
-
const llmProvider =
|
|
22529
|
+
const llmProvider = readString16(body, "llm_provider") ?? readString16(body, "llmProvider");
|
|
21486
22530
|
if (llmProvider) {
|
|
21487
22531
|
input.llmProvider = llmProvider;
|
|
21488
22532
|
}
|
|
@@ -21518,11 +22562,11 @@ function readMemorySettingsPatch(body) {
|
|
|
21518
22562
|
if (autoRetain !== void 0) {
|
|
21519
22563
|
input.autoRetain = autoRetain;
|
|
21520
22564
|
}
|
|
21521
|
-
const memoryMode =
|
|
22565
|
+
const memoryMode = readString16(body, "memory_mode") ?? readString16(body, "memoryMode");
|
|
21522
22566
|
if (memoryMode) {
|
|
21523
22567
|
input.memoryMode = memoryMode;
|
|
21524
22568
|
}
|
|
21525
|
-
const recallBudget =
|
|
22569
|
+
const recallBudget = readString16(body, "recall_budget") ?? readString16(body, "recallBudget");
|
|
21526
22570
|
if (recallBudget) {
|
|
21527
22571
|
input.recallBudget = recallBudget;
|
|
21528
22572
|
}
|
|
@@ -21538,11 +22582,11 @@ function readMemorySettingsPatch(body) {
|
|
|
21538
22582
|
if (profileFrequency !== void 0) {
|
|
21539
22583
|
input.profileFrequency = profileFrequency;
|
|
21540
22584
|
}
|
|
21541
|
-
const captureMode =
|
|
22585
|
+
const captureMode = readString16(body, "capture_mode") ?? readString16(body, "captureMode");
|
|
21542
22586
|
if (captureMode) {
|
|
21543
22587
|
input.captureMode = captureMode;
|
|
21544
22588
|
}
|
|
21545
|
-
const searchMode =
|
|
22589
|
+
const searchMode = readString16(body, "search_mode") ?? readString16(body, "searchMode");
|
|
21546
22590
|
if (searchMode) {
|
|
21547
22591
|
input.searchMode = searchMode;
|
|
21548
22592
|
}
|
|
@@ -21576,11 +22620,11 @@ function readMemorySettingsPatch(body) {
|
|
|
21576
22620
|
if (aiPeer !== void 0) {
|
|
21577
22621
|
input.aiPeer = aiPeer;
|
|
21578
22622
|
}
|
|
21579
|
-
const recallMode =
|
|
22623
|
+
const recallMode = readString16(body, "recall_mode") ?? readString16(body, "recallMode");
|
|
21580
22624
|
if (recallMode) {
|
|
21581
22625
|
input.recallMode = recallMode;
|
|
21582
22626
|
}
|
|
21583
|
-
const writeFrequency =
|
|
22627
|
+
const writeFrequency = readString16(body, "write_frequency") ?? readString16(body, "writeFrequency");
|
|
21584
22628
|
if (writeFrequency) {
|
|
21585
22629
|
input.writeFrequency = writeFrequency;
|
|
21586
22630
|
}
|
|
@@ -21588,7 +22632,7 @@ function readMemorySettingsPatch(body) {
|
|
|
21588
22632
|
if (saveMessages !== void 0) {
|
|
21589
22633
|
input.saveMessages = saveMessages;
|
|
21590
22634
|
}
|
|
21591
|
-
const sessionStrategy =
|
|
22635
|
+
const sessionStrategy = readString16(body, "session_strategy") ?? readString16(body, "sessionStrategy");
|
|
21592
22636
|
if (sessionStrategy) {
|
|
21593
22637
|
input.sessionStrategy = sessionStrategy;
|
|
21594
22638
|
}
|
|
@@ -21720,8 +22764,8 @@ function toMemoryHttpError(error) {
|
|
|
21720
22764
|
}
|
|
21721
22765
|
|
|
21722
22766
|
// src/hermes/skills.ts
|
|
21723
|
-
import { readFile as
|
|
21724
|
-
import
|
|
22767
|
+
import { readFile as readFile16, readdir as readdir11 } from "fs/promises";
|
|
22768
|
+
import path23 from "path";
|
|
21725
22769
|
import YAML5 from "yaml";
|
|
21726
22770
|
var HermesSkillNotFoundError = class extends Error {
|
|
21727
22771
|
constructor(skillName) {
|
|
@@ -21735,7 +22779,7 @@ var EXCLUDED_SKILL_DIRS = /* @__PURE__ */ new Set([".git", ".github", ".hub"]);
|
|
|
21735
22779
|
async function listHermesProfileSkills(profileName, paths = resolveRuntimePaths()) {
|
|
21736
22780
|
const profile = await readExistingProfile(profileName, paths);
|
|
21737
22781
|
const profileDir = resolveHermesProfileDir(profile.name);
|
|
21738
|
-
const skillsRoot =
|
|
22782
|
+
const skillsRoot = path23.join(profileDir, "skills");
|
|
21739
22783
|
const [skillFiles, disabled, provenance] = await Promise.all([
|
|
21740
22784
|
findSkillFiles(skillsRoot),
|
|
21741
22785
|
readDisabledSkillNames(resolveHermesConfigPath(profile.name)),
|
|
@@ -21814,7 +22858,7 @@ async function findSkillFiles(root) {
|
|
|
21814
22858
|
async function collectSkillFiles(directory, results) {
|
|
21815
22859
|
const entries = await readdir11(directory, { withFileTypes: true }).catch(
|
|
21816
22860
|
(error) => {
|
|
21817
|
-
if (
|
|
22861
|
+
if (isNodeError18(error, "ENOENT")) {
|
|
21818
22862
|
return [];
|
|
21819
22863
|
}
|
|
21820
22864
|
throw error;
|
|
@@ -21826,7 +22870,7 @@ async function collectSkillFiles(directory, results) {
|
|
|
21826
22870
|
if (EXCLUDED_SKILL_DIRS.has(entry.name)) {
|
|
21827
22871
|
continue;
|
|
21828
22872
|
}
|
|
21829
|
-
const entryPath =
|
|
22873
|
+
const entryPath = path23.join(directory, entry.name);
|
|
21830
22874
|
if (entry.isDirectory()) {
|
|
21831
22875
|
await collectSkillFiles(entryPath, results);
|
|
21832
22876
|
continue;
|
|
@@ -21837,9 +22881,9 @@ async function collectSkillFiles(directory, results) {
|
|
|
21837
22881
|
}
|
|
21838
22882
|
}
|
|
21839
22883
|
async function readSkillMetadata(input) {
|
|
21840
|
-
const raw = await
|
|
22884
|
+
const raw = await readFile16(input.skillFile, "utf8").catch(
|
|
21841
22885
|
(error) => {
|
|
21842
|
-
if (
|
|
22886
|
+
if (isNodeError18(error, "ENOENT") || isNodeError18(error, "EACCES")) {
|
|
21843
22887
|
return null;
|
|
21844
22888
|
}
|
|
21845
22889
|
throw error;
|
|
@@ -21848,16 +22892,16 @@ async function readSkillMetadata(input) {
|
|
|
21848
22892
|
if (raw === null) {
|
|
21849
22893
|
return null;
|
|
21850
22894
|
}
|
|
21851
|
-
const skillDir =
|
|
22895
|
+
const skillDir = path23.dirname(input.skillFile);
|
|
21852
22896
|
const { frontmatter, body } = parseSkillDocument(raw.slice(0, 4e3));
|
|
21853
22897
|
const name = normalizeSkillName(
|
|
21854
|
-
|
|
22898
|
+
readString18(frontmatter.name) ?? path23.basename(skillDir)
|
|
21855
22899
|
);
|
|
21856
22900
|
if (!name) {
|
|
21857
22901
|
return null;
|
|
21858
22902
|
}
|
|
21859
22903
|
const description = normalizeDescription(
|
|
21860
|
-
|
|
22904
|
+
readString18(frontmatter.description) ?? firstBodyDescription(body)
|
|
21861
22905
|
);
|
|
21862
22906
|
const provenance = input.provenance.get(name) ?? {
|
|
21863
22907
|
source: "local",
|
|
@@ -21870,7 +22914,7 @@ async function readSkillMetadata(input) {
|
|
|
21870
22914
|
enabled: !input.disabled.has(name),
|
|
21871
22915
|
source: provenance.source,
|
|
21872
22916
|
trust: provenance.trust,
|
|
21873
|
-
relativePath:
|
|
22917
|
+
relativePath: path23.relative(input.skillsRoot, skillDir)
|
|
21874
22918
|
};
|
|
21875
22919
|
}
|
|
21876
22920
|
function parseSkillDocument(raw) {
|
|
@@ -21883,7 +22927,7 @@ function parseSkillDocument(raw) {
|
|
|
21883
22927
|
}
|
|
21884
22928
|
try {
|
|
21885
22929
|
return {
|
|
21886
|
-
frontmatter:
|
|
22930
|
+
frontmatter: toRecord17(YAML5.parse(match[1] ?? "")),
|
|
21887
22931
|
body: content.slice(match[0].length)
|
|
21888
22932
|
};
|
|
21889
22933
|
} catch {
|
|
@@ -21891,8 +22935,8 @@ function parseSkillDocument(raw) {
|
|
|
21891
22935
|
}
|
|
21892
22936
|
}
|
|
21893
22937
|
function categoryFromPath(skillsRoot, skillFile) {
|
|
21894
|
-
const relative =
|
|
21895
|
-
const parts = relative.split(
|
|
22938
|
+
const relative = path23.relative(skillsRoot, skillFile);
|
|
22939
|
+
const parts = relative.split(path23.sep).filter(Boolean);
|
|
21896
22940
|
return parts.length >= 3 ? parts[0] : null;
|
|
21897
22941
|
}
|
|
21898
22942
|
function firstBodyDescription(body) {
|
|
@@ -21915,8 +22959,8 @@ function normalizeDescription(value) {
|
|
|
21915
22959
|
return `${description.slice(0, MAX_DESCRIPTION_LENGTH - 3)}...`;
|
|
21916
22960
|
}
|
|
21917
22961
|
async function readDisabledSkillNames(configPath) {
|
|
21918
|
-
const raw = await
|
|
21919
|
-
if (
|
|
22962
|
+
const raw = await readFile16(configPath, "utf8").catch((error) => {
|
|
22963
|
+
if (isNodeError18(error, "ENOENT")) {
|
|
21920
22964
|
return "";
|
|
21921
22965
|
}
|
|
21922
22966
|
throw error;
|
|
@@ -21924,8 +22968,8 @@ async function readDisabledSkillNames(configPath) {
|
|
|
21924
22968
|
if (!raw.trim()) {
|
|
21925
22969
|
return /* @__PURE__ */ new Set();
|
|
21926
22970
|
}
|
|
21927
|
-
const config =
|
|
21928
|
-
const skills =
|
|
22971
|
+
const config = toRecord17(YAML5.parse(raw));
|
|
22972
|
+
const skills = toRecord17(config.skills);
|
|
21929
22973
|
return new Set(readStringList3(skills.disabled));
|
|
21930
22974
|
}
|
|
21931
22975
|
async function readSkillProvenance(root) {
|
|
@@ -21939,9 +22983,9 @@ async function readSkillProvenance(root) {
|
|
|
21939
22983
|
return provenance;
|
|
21940
22984
|
}
|
|
21941
22985
|
async function readBundledSkillNames(root) {
|
|
21942
|
-
const raw = await
|
|
22986
|
+
const raw = await readFile16(path23.join(root, ".bundled_manifest"), "utf8").catch(
|
|
21943
22987
|
(error) => {
|
|
21944
|
-
if (
|
|
22988
|
+
if (isNodeError18(error, "ENOENT")) {
|
|
21945
22989
|
return "";
|
|
21946
22990
|
}
|
|
21947
22991
|
throw error;
|
|
@@ -21962,9 +23006,9 @@ async function readBundledSkillNames(root) {
|
|
|
21962
23006
|
return names;
|
|
21963
23007
|
}
|
|
21964
23008
|
async function readHubInstalledSkills(root) {
|
|
21965
|
-
const raw = await
|
|
23009
|
+
const raw = await readFile16(path23.join(root, ".hub", "lock.json"), "utf8").catch(
|
|
21966
23010
|
(error) => {
|
|
21967
|
-
if (
|
|
23011
|
+
if (isNodeError18(error, "ENOENT")) {
|
|
21968
23012
|
return "";
|
|
21969
23013
|
}
|
|
21970
23014
|
throw error;
|
|
@@ -21975,17 +23019,17 @@ async function readHubInstalledSkills(root) {
|
|
|
21975
23019
|
}
|
|
21976
23020
|
let lock;
|
|
21977
23021
|
try {
|
|
21978
|
-
lock =
|
|
23022
|
+
lock = toRecord17(JSON.parse(raw));
|
|
21979
23023
|
} catch {
|
|
21980
23024
|
return /* @__PURE__ */ new Map();
|
|
21981
23025
|
}
|
|
21982
|
-
const installed =
|
|
23026
|
+
const installed = toRecord17(lock.installed);
|
|
21983
23027
|
const result = /* @__PURE__ */ new Map();
|
|
21984
23028
|
for (const [name, rawEntry] of Object.entries(installed)) {
|
|
21985
|
-
const entry =
|
|
23029
|
+
const entry = toRecord17(rawEntry);
|
|
21986
23030
|
result.set(normalizeSkillName(name), {
|
|
21987
|
-
source:
|
|
21988
|
-
trust:
|
|
23031
|
+
source: readString18(entry.source) ?? "hub",
|
|
23032
|
+
trust: readString18(entry.trust_level) ?? null
|
|
21989
23033
|
});
|
|
21990
23034
|
}
|
|
21991
23035
|
return result;
|
|
@@ -22034,9 +23078,9 @@ function compareCategoryNames(left, right) {
|
|
|
22034
23078
|
return left.localeCompare(right);
|
|
22035
23079
|
}
|
|
22036
23080
|
async function readHermesConfigDocument2(configPath) {
|
|
22037
|
-
const existingRaw = await
|
|
23081
|
+
const existingRaw = await readFile16(configPath, "utf8").catch(
|
|
22038
23082
|
(error) => {
|
|
22039
|
-
if (
|
|
23083
|
+
if (isNodeError18(error, "ENOENT")) {
|
|
22040
23084
|
return null;
|
|
22041
23085
|
}
|
|
22042
23086
|
throw error;
|
|
@@ -22045,7 +23089,7 @@ async function readHermesConfigDocument2(configPath) {
|
|
|
22045
23089
|
const document = existingRaw ? YAML5.parseDocument(existingRaw) : new YAML5.Document({});
|
|
22046
23090
|
return {
|
|
22047
23091
|
document,
|
|
22048
|
-
config:
|
|
23092
|
+
config: toRecord17(document.toJSON()),
|
|
22049
23093
|
existingRaw
|
|
22050
23094
|
};
|
|
22051
23095
|
}
|
|
@@ -22069,21 +23113,21 @@ function readStringList3(value) {
|
|
|
22069
23113
|
}
|
|
22070
23114
|
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
22071
23115
|
}
|
|
22072
|
-
function
|
|
23116
|
+
function readString18(value) {
|
|
22073
23117
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
22074
23118
|
}
|
|
22075
|
-
function
|
|
23119
|
+
function toRecord17(value) {
|
|
22076
23120
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
22077
23121
|
}
|
|
22078
23122
|
function ensureRecord3(target, key) {
|
|
22079
|
-
const current =
|
|
23123
|
+
const current = toRecord17(target[key]);
|
|
22080
23124
|
if (current === target[key]) {
|
|
22081
23125
|
return current;
|
|
22082
23126
|
}
|
|
22083
23127
|
target[key] = current;
|
|
22084
23128
|
return current;
|
|
22085
23129
|
}
|
|
22086
|
-
function
|
|
23130
|
+
function isNodeError18(error, code) {
|
|
22087
23131
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
22088
23132
|
}
|
|
22089
23133
|
|
|
@@ -22382,7 +23426,7 @@ function registerRunRoutes(router, options) {
|
|
|
22382
23426
|
router.post("/api/v1/runs", async (ctx) => {
|
|
22383
23427
|
await authenticateRequest(ctx, paths);
|
|
22384
23428
|
const body = await readJsonBody(ctx.req);
|
|
22385
|
-
const input =
|
|
23429
|
+
const input = readString16(body, "input");
|
|
22386
23430
|
if (!input) {
|
|
22387
23431
|
throw new LinkHttpError(400, "run_input_required", "input is required");
|
|
22388
23432
|
}
|
|
@@ -22390,12 +23434,12 @@ function registerRunRoutes(router, options) {
|
|
|
22390
23434
|
ctx.body = await createHermesRun(
|
|
22391
23435
|
{
|
|
22392
23436
|
input,
|
|
22393
|
-
instructions:
|
|
23437
|
+
instructions: readString16(body, "instructions") ?? void 0,
|
|
22394
23438
|
conversation_history: readConversationHistory(
|
|
22395
23439
|
body.conversation_history ?? body.conversationHistory
|
|
22396
23440
|
),
|
|
22397
|
-
session_id:
|
|
22398
|
-
session_key:
|
|
23441
|
+
session_id: readString16(body, "session_id") ?? readString16(body, "sessionId") ?? void 0,
|
|
23442
|
+
session_key: readString16(body, "session_key") ?? readString16(body, "sessionKey") ?? void 0
|
|
22399
23443
|
},
|
|
22400
23444
|
{ logger, profileName: readOptionalProfileName(body) }
|
|
22401
23445
|
);
|
|
@@ -22566,8 +23610,8 @@ function readModelList(payload) {
|
|
|
22566
23610
|
// src/hermes/updates.ts
|
|
22567
23611
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
22568
23612
|
import { spawn as spawn3 } from "child_process";
|
|
22569
|
-
import { mkdir as mkdir12, readFile as
|
|
22570
|
-
import
|
|
23613
|
+
import { mkdir as mkdir12, readFile as readFile17, rm as rm7 } from "fs/promises";
|
|
23614
|
+
import path24 from "path";
|
|
22571
23615
|
var SERVER_HERMES_RELEASES_LATEST_PATH = "/api/v1/hermes-agent/releases/latest";
|
|
22572
23616
|
var RELEASE_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
22573
23617
|
var RELEASE_FETCH_TIMEOUT_MS = 5e3;
|
|
@@ -22800,24 +23844,24 @@ async function readRemoteRelease(options, now) {
|
|
|
22800
23844
|
}
|
|
22801
23845
|
}
|
|
22802
23846
|
function normalizeServerReleaseSnapshot(payload) {
|
|
22803
|
-
const snapshot =
|
|
23847
|
+
const snapshot = toRecord18(payload);
|
|
22804
23848
|
const remote = toNullableRecord(snapshot.remote);
|
|
22805
23849
|
return {
|
|
22806
23850
|
remote: remote ? normalizeServerRelease(remote) : null,
|
|
22807
|
-
cacheState:
|
|
22808
|
-
issue:
|
|
23851
|
+
cacheState: readString19(snapshot, "cache_state") ?? readString19(snapshot, "cacheState"),
|
|
23852
|
+
issue: readString19(snapshot, "issue")
|
|
22809
23853
|
};
|
|
22810
23854
|
}
|
|
22811
23855
|
function normalizeServerRelease(payload) {
|
|
22812
|
-
const tag =
|
|
22813
|
-
const name =
|
|
23856
|
+
const tag = readString19(payload, "tag");
|
|
23857
|
+
const name = readString19(payload, "name");
|
|
22814
23858
|
return {
|
|
22815
|
-
version:
|
|
23859
|
+
version: readString19(payload, "version") ?? extractSemver(name) ?? extractTagSemver(tag),
|
|
22816
23860
|
tag,
|
|
22817
23861
|
name,
|
|
22818
|
-
releaseUrl:
|
|
22819
|
-
publishedAt:
|
|
22820
|
-
fetchedAt:
|
|
23862
|
+
releaseUrl: readString19(payload, "releaseUrl") ?? readString19(payload, "release_url"),
|
|
23863
|
+
publishedAt: readString19(payload, "publishedAt") ?? readString19(payload, "published_at"),
|
|
23864
|
+
fetchedAt: readString19(payload, "fetchedAt") ?? readString19(payload, "fetched_at") ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
22821
23865
|
};
|
|
22822
23866
|
}
|
|
22823
23867
|
async function readReleaseCache(paths) {
|
|
@@ -22836,7 +23880,7 @@ async function writeUpdateState(paths, state) {
|
|
|
22836
23880
|
await writeJsonFile(updateStatePath(paths), state);
|
|
22837
23881
|
}
|
|
22838
23882
|
async function readUpdateLogLines(paths) {
|
|
22839
|
-
const raw = await
|
|
23883
|
+
const raw = await readFile17(updateLogPath(paths), "utf8").catch(() => "");
|
|
22840
23884
|
if (!raw.trim()) {
|
|
22841
23885
|
return [];
|
|
22842
23886
|
}
|
|
@@ -22845,13 +23889,13 @@ async function readUpdateLogLines(paths) {
|
|
|
22845
23889
|
);
|
|
22846
23890
|
}
|
|
22847
23891
|
function releaseCachePath(paths) {
|
|
22848
|
-
return
|
|
23892
|
+
return path24.join(paths.indexesDir, "hermes-release-check.json");
|
|
22849
23893
|
}
|
|
22850
23894
|
function updateStatePath(paths) {
|
|
22851
|
-
return
|
|
23895
|
+
return path24.join(paths.runDir, "hermes-update-state.json");
|
|
22852
23896
|
}
|
|
22853
23897
|
function updateLogPath(paths) {
|
|
22854
|
-
return
|
|
23898
|
+
return path24.join(paths.logsDir, UPDATE_LOG_FILE);
|
|
22855
23899
|
}
|
|
22856
23900
|
async function clearUpdateLogFiles(paths) {
|
|
22857
23901
|
const primary = updateLogPath(paths);
|
|
@@ -22889,7 +23933,7 @@ function compareSemver2(left, right) {
|
|
|
22889
23933
|
}
|
|
22890
23934
|
return 0;
|
|
22891
23935
|
}
|
|
22892
|
-
function
|
|
23936
|
+
function toRecord18(value) {
|
|
22893
23937
|
return typeof value === "object" && value !== null ? value : {};
|
|
22894
23938
|
}
|
|
22895
23939
|
function toNullableRecord(value) {
|
|
@@ -22943,7 +23987,7 @@ function isRecentRunningState2(state) {
|
|
|
22943
23987
|
const startedAt = Date.parse(state.started_at);
|
|
22944
23988
|
return Number.isFinite(startedAt) && Date.now() - startedAt < 3e4;
|
|
22945
23989
|
}
|
|
22946
|
-
function
|
|
23990
|
+
function readString19(payload, key) {
|
|
22947
23991
|
const value = payload[key];
|
|
22948
23992
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
22949
23993
|
}
|
|
@@ -22951,13 +23995,13 @@ function readString17(payload, key) {
|
|
|
22951
23995
|
// src/link/updates.ts
|
|
22952
23996
|
import { spawn as spawn5 } from "child_process";
|
|
22953
23997
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
22954
|
-
import { mkdir as mkdir15, readFile as
|
|
22955
|
-
import
|
|
23998
|
+
import { mkdir as mkdir15, readFile as readFile19, rm as rm10 } from "fs/promises";
|
|
23999
|
+
import path26 from "path";
|
|
22956
24000
|
|
|
22957
24001
|
// src/daemon/process.ts
|
|
22958
24002
|
import { spawn as spawn4 } from "child_process";
|
|
22959
|
-
import { mkdir as mkdir14, readFile as
|
|
22960
|
-
import
|
|
24003
|
+
import { mkdir as mkdir14, readFile as readFile18, rm as rm9 } from "fs/promises";
|
|
24004
|
+
import path25 from "path";
|
|
22961
24005
|
|
|
22962
24006
|
// src/daemon/service.ts
|
|
22963
24007
|
import { createServer } from "http";
|
|
@@ -22968,8 +24012,8 @@ import WebSocket from "ws";
|
|
|
22968
24012
|
|
|
22969
24013
|
// src/relay/stream-policy.ts
|
|
22970
24014
|
var DEFAULT_RELAY_STREAM_BATCH_POLICY = {
|
|
22971
|
-
flushIntervalMs:
|
|
22972
|
-
flushBytes:
|
|
24015
|
+
flushIntervalMs: 1e3,
|
|
24016
|
+
flushBytes: 4 * 1024
|
|
22973
24017
|
};
|
|
22974
24018
|
var RELAY_STREAM_POLICY_CONSTRAINTS = {
|
|
22975
24019
|
flushIntervalMs: {
|
|
@@ -24291,7 +25335,7 @@ async function runDaemonSupervisor(paths = resolveRuntimePaths()) {
|
|
|
24291
25335
|
await mkdir14(paths.logsDir, { recursive: true, mode: 448 });
|
|
24292
25336
|
const log = createRotatingTextLogWriter({
|
|
24293
25337
|
paths,
|
|
24294
|
-
fileName:
|
|
25338
|
+
fileName: path25.basename(daemonLogFile(paths))
|
|
24295
25339
|
});
|
|
24296
25340
|
const scriptPath = currentCliScriptPath();
|
|
24297
25341
|
const child = spawn4(process.execPath, [scriptPath, "daemon", "--foreground"], {
|
|
@@ -24420,7 +25464,7 @@ function currentCliScriptPath() {
|
|
|
24420
25464
|
return process.argv[1];
|
|
24421
25465
|
}
|
|
24422
25466
|
async function readPid(filePath) {
|
|
24423
|
-
const raw = await
|
|
25467
|
+
const raw = await readFile18(filePath, "utf8").catch(() => null);
|
|
24424
25468
|
if (!raw) {
|
|
24425
25469
|
return null;
|
|
24426
25470
|
}
|
|
@@ -24849,21 +25893,21 @@ async function readRemoteLinkPolicy(options) {
|
|
|
24849
25893
|
}
|
|
24850
25894
|
}
|
|
24851
25895
|
function normalizeServerSnapshot(payload) {
|
|
24852
|
-
const snapshot =
|
|
25896
|
+
const snapshot = toRecord19(payload);
|
|
24853
25897
|
const policy = toNullableRecord2(snapshot.policy);
|
|
24854
25898
|
if (!policy) {
|
|
24855
25899
|
return {
|
|
24856
25900
|
remote: null,
|
|
24857
|
-
issue:
|
|
25901
|
+
issue: readString20(snapshot, "issue")
|
|
24858
25902
|
};
|
|
24859
25903
|
}
|
|
24860
25904
|
const release = toNullableRecord2(snapshot.release);
|
|
24861
|
-
const currentVersion =
|
|
24862
|
-
const minSafeVersion =
|
|
25905
|
+
const currentVersion = readString20(policy, "current_version") ?? readString20(policy, "currentVersion");
|
|
25906
|
+
const minSafeVersion = readString20(policy, "min_safe_version") ?? readString20(policy, "minSafeVersion");
|
|
24863
25907
|
if (!currentVersion) {
|
|
24864
25908
|
return {
|
|
24865
25909
|
remote: null,
|
|
24866
|
-
issue:
|
|
25910
|
+
issue: readString20(snapshot, "issue")
|
|
24867
25911
|
};
|
|
24868
25912
|
}
|
|
24869
25913
|
return {
|
|
@@ -24871,10 +25915,10 @@ function normalizeServerSnapshot(payload) {
|
|
|
24871
25915
|
current_version: currentVersion,
|
|
24872
25916
|
min_safe_version: minSafeVersion,
|
|
24873
25917
|
target_version: currentVersion,
|
|
24874
|
-
release_url: release ?
|
|
24875
|
-
published_at: release ?
|
|
25918
|
+
release_url: release ? readString20(release, "release_url") ?? readString20(release, "releaseUrl") : null,
|
|
25919
|
+
published_at: release ? readString20(release, "published_at") ?? readString20(release, "publishedAt") : null
|
|
24876
25920
|
},
|
|
24877
|
-
issue:
|
|
25921
|
+
issue: readString20(snapshot, "issue")
|
|
24878
25922
|
};
|
|
24879
25923
|
}
|
|
24880
25924
|
async function fetchCurrentLinkReleaseFromServer(options, fetcher, channel) {
|
|
@@ -25192,7 +26236,7 @@ async function writeUpdateState2(paths, state) {
|
|
|
25192
26236
|
await writeJsonFile(updateStatePath2(paths), state);
|
|
25193
26237
|
}
|
|
25194
26238
|
async function readUpdateLogLines2(paths) {
|
|
25195
|
-
const raw = await
|
|
26239
|
+
const raw = await readFile19(updateLogPath2(paths), "utf8").catch(() => "");
|
|
25196
26240
|
if (!raw.trim()) {
|
|
25197
26241
|
return [];
|
|
25198
26242
|
}
|
|
@@ -25201,10 +26245,10 @@ async function readUpdateLogLines2(paths) {
|
|
|
25201
26245
|
);
|
|
25202
26246
|
}
|
|
25203
26247
|
function updateStatePath2(paths) {
|
|
25204
|
-
return
|
|
26248
|
+
return path26.join(paths.runDir, "link-update-state.json");
|
|
25205
26249
|
}
|
|
25206
26250
|
function updateLogPath2(paths) {
|
|
25207
|
-
return
|
|
26251
|
+
return path26.join(paths.logsDir, UPDATE_LOG_FILE2);
|
|
25208
26252
|
}
|
|
25209
26253
|
async function clearUpdateLogFiles2(paths) {
|
|
25210
26254
|
const primary = updateLogPath2(paths);
|
|
@@ -25276,19 +26320,19 @@ function isProcessAlive4(pid) {
|
|
|
25276
26320
|
return false;
|
|
25277
26321
|
}
|
|
25278
26322
|
}
|
|
25279
|
-
function
|
|
26323
|
+
function toRecord19(value) {
|
|
25280
26324
|
return typeof value === "object" && value !== null ? value : {};
|
|
25281
26325
|
}
|
|
25282
26326
|
function toNullableRecord2(value) {
|
|
25283
26327
|
return typeof value === "object" && value !== null ? value : null;
|
|
25284
26328
|
}
|
|
25285
|
-
function
|
|
26329
|
+
function readString20(payload, key) {
|
|
25286
26330
|
const value = payload[key];
|
|
25287
26331
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
25288
26332
|
}
|
|
25289
26333
|
|
|
25290
26334
|
// src/pairing/pairing.ts
|
|
25291
|
-
import
|
|
26335
|
+
import path27 from "path";
|
|
25292
26336
|
import { rm as rm11 } from "fs/promises";
|
|
25293
26337
|
|
|
25294
26338
|
// src/relay/bootstrap.ts
|
|
@@ -25628,10 +26672,10 @@ async function loadRequiredIdentity2(paths) {
|
|
|
25628
26672
|
}
|
|
25629
26673
|
return identity;
|
|
25630
26674
|
}
|
|
25631
|
-
async function postServerJson(serverBaseUrl,
|
|
26675
|
+
async function postServerJson(serverBaseUrl, path28, body, options) {
|
|
25632
26676
|
let response;
|
|
25633
26677
|
try {
|
|
25634
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
26678
|
+
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path28}`, {
|
|
25635
26679
|
method: "POST",
|
|
25636
26680
|
headers: {
|
|
25637
26681
|
accept: "application/json",
|
|
@@ -25679,10 +26723,10 @@ function pairingErrorSnapshot(stage, error) {
|
|
|
25679
26723
|
occurred_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
25680
26724
|
};
|
|
25681
26725
|
}
|
|
25682
|
-
async function patchServerJson(serverBaseUrl,
|
|
26726
|
+
async function patchServerJson(serverBaseUrl, path28, token, body, options) {
|
|
25683
26727
|
let response;
|
|
25684
26728
|
try {
|
|
25685
|
-
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${
|
|
26729
|
+
response = await fetch(`${serverBaseUrl.replace(/\/+$/u, "")}${path28}`, {
|
|
25686
26730
|
method: "PATCH",
|
|
25687
26731
|
headers: {
|
|
25688
26732
|
accept: "application/json",
|
|
@@ -25730,10 +26774,10 @@ function createPairingNetworkError(input) {
|
|
|
25730
26774
|
);
|
|
25731
26775
|
}
|
|
25732
26776
|
function pairingClaimPath(sessionId, paths) {
|
|
25733
|
-
return
|
|
26777
|
+
return path27.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.claimed.json`);
|
|
25734
26778
|
}
|
|
25735
26779
|
function pairingSessionPath(sessionId, paths) {
|
|
25736
|
-
return
|
|
26780
|
+
return path27.join(paths.pairingDir, `${Buffer.from(sessionId).toString("base64url")}.json`);
|
|
25737
26781
|
}
|
|
25738
26782
|
function qrPreferredUrls(routes) {
|
|
25739
26783
|
return routes.preferredUrls.filter((url) => !url.includes("/api/v1/relay/links/")).slice(0, 1);
|
|
@@ -25809,8 +26853,8 @@ function registerSystemRoutes(router, options) {
|
|
|
25809
26853
|
});
|
|
25810
26854
|
router.post("/api/v1/pairing/claim", async (ctx) => {
|
|
25811
26855
|
const body = await readJsonBody(ctx.req);
|
|
25812
|
-
const sessionId =
|
|
25813
|
-
const claimToken =
|
|
26856
|
+
const sessionId = readString16(body, "session_id") ?? readString16(body, "sessionId");
|
|
26857
|
+
const claimToken = readString16(body, "claim_token") ?? readString16(body, "claimToken");
|
|
25814
26858
|
if (!sessionId || !claimToken) {
|
|
25815
26859
|
throw new LinkHttpError(
|
|
25816
26860
|
400,
|
|
@@ -25821,10 +26865,10 @@ function registerSystemRoutes(router, options) {
|
|
|
25821
26865
|
const claimed = await claimPairing({
|
|
25822
26866
|
sessionId,
|
|
25823
26867
|
claimToken,
|
|
25824
|
-
deviceLabel:
|
|
25825
|
-
devicePlatform:
|
|
25826
|
-
deviceModel:
|
|
25827
|
-
appInstanceId:
|
|
26868
|
+
deviceLabel: readString16(body, "device_label") ?? readString16(body, "deviceLabel") ?? "HermesPilot App",
|
|
26869
|
+
devicePlatform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform") ?? "unknown",
|
|
26870
|
+
deviceModel: readString16(body, "device_model") ?? readString16(body, "deviceModel"),
|
|
26871
|
+
appInstanceId: readString16(body, "app_instance_id") ?? readString16(body, "appInstanceId"),
|
|
25828
26872
|
paths
|
|
25829
26873
|
});
|
|
25830
26874
|
ctx.body = claimed;
|
|
@@ -25899,9 +26943,9 @@ function registerSystemRoutes(router, options) {
|
|
|
25899
26943
|
const body = await readJsonBody(ctx.req);
|
|
25900
26944
|
const session = await createDeviceSession(
|
|
25901
26945
|
{
|
|
25902
|
-
label:
|
|
25903
|
-
platform:
|
|
25904
|
-
model:
|
|
26946
|
+
label: readString16(body, "device_label") ?? readString16(body, "deviceLabel") ?? "HermesPilot App",
|
|
26947
|
+
platform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform") ?? "unknown",
|
|
26948
|
+
model: readString16(body, "device_model") ?? readString16(body, "deviceModel"),
|
|
25905
26949
|
appInstanceId: auth.appInstanceId
|
|
25906
26950
|
},
|
|
25907
26951
|
paths
|
|
@@ -25930,7 +26974,7 @@ function registerSystemRoutes(router, options) {
|
|
|
25930
26974
|
});
|
|
25931
26975
|
router.post("/api/v1/auth/refresh", async (ctx) => {
|
|
25932
26976
|
const body = await readJsonBody(ctx.req);
|
|
25933
|
-
const refreshToken =
|
|
26977
|
+
const refreshToken = readString16(body, "refresh_token") ?? readString16(body, "refreshToken");
|
|
25934
26978
|
if (!refreshToken) {
|
|
25935
26979
|
throw new LinkHttpError(
|
|
25936
26980
|
400,
|
|
@@ -25941,10 +26985,10 @@ function registerSystemRoutes(router, options) {
|
|
|
25941
26985
|
const session = await refreshDeviceSession(
|
|
25942
26986
|
refreshToken,
|
|
25943
26987
|
{
|
|
25944
|
-
appInstanceId:
|
|
25945
|
-
label:
|
|
25946
|
-
platform:
|
|
25947
|
-
model:
|
|
26988
|
+
appInstanceId: readString16(body, "app_instance_id") ?? readString16(body, "appInstanceId"),
|
|
26989
|
+
label: readString16(body, "device_label") ?? readString16(body, "deviceLabel"),
|
|
26990
|
+
platform: readString16(body, "device_platform") ?? readString16(body, "devicePlatform"),
|
|
26991
|
+
model: readString16(body, "device_model") ?? readString16(body, "deviceModel")
|
|
25948
26992
|
},
|
|
25949
26993
|
paths
|
|
25950
26994
|
);
|
|
@@ -25963,7 +27007,7 @@ function registerSystemRoutes(router, options) {
|
|
|
25963
27007
|
});
|
|
25964
27008
|
router.post("/api/v1/auth/logout", async (ctx) => {
|
|
25965
27009
|
const body = await readJsonBody(ctx.req);
|
|
25966
|
-
const refreshToken =
|
|
27010
|
+
const refreshToken = readString16(body, "refresh_token") ?? readString16(body, "refreshToken");
|
|
25967
27011
|
if (refreshToken) {
|
|
25968
27012
|
await revokeDeviceRefreshToken(refreshToken, paths);
|
|
25969
27013
|
}
|
|
@@ -26189,7 +27233,7 @@ function registerSystemRoutes(router, options) {
|
|
|
26189
27233
|
router.patch("/api/v1/devices/:deviceId", async (ctx) => {
|
|
26190
27234
|
const auth = await authenticateRequest(ctx, paths);
|
|
26191
27235
|
const body = await readJsonBody(ctx.req);
|
|
26192
|
-
const label =
|
|
27236
|
+
const label = readString16(body, "label") ?? readString16(body, "device_label");
|
|
26193
27237
|
if (!label) {
|
|
26194
27238
|
throw new LinkHttpError(
|
|
26195
27239
|
400,
|
|
@@ -26233,7 +27277,7 @@ function isActiveCronJob(job) {
|
|
|
26233
27277
|
if (!enabled) {
|
|
26234
27278
|
return false;
|
|
26235
27279
|
}
|
|
26236
|
-
const state =
|
|
27280
|
+
const state = readString16(job, "state")?.toLowerCase();
|
|
26237
27281
|
return !["paused", "disabled", "completed", "deleted"].includes(state ?? "");
|
|
26238
27282
|
}
|
|
26239
27283
|
function filterLogsWithinHours(logs, hours, now = Date.now()) {
|
|
@@ -26327,8 +27371,8 @@ function registerLinkUpdateRoutes(router, options) {
|
|
|
26327
27371
|
ctx.body = await startLinkUpdate({
|
|
26328
27372
|
paths,
|
|
26329
27373
|
logger,
|
|
26330
|
-
channel:
|
|
26331
|
-
targetVersion:
|
|
27374
|
+
channel: readString16(body, "channel"),
|
|
27375
|
+
targetVersion: readString16(body, "target_version") ?? readString16(body, "targetVersion")
|
|
26332
27376
|
});
|
|
26333
27377
|
});
|
|
26334
27378
|
router.get("/api/v1/link/update/events", async (ctx) => {
|
|
@@ -26358,7 +27402,7 @@ import QRCode from "qrcode";
|
|
|
26358
27402
|
function registerPairingRoutes(router, options) {
|
|
26359
27403
|
const { paths } = options;
|
|
26360
27404
|
router.get("/pair", async (ctx) => {
|
|
26361
|
-
const sessionId =
|
|
27405
|
+
const sessionId = readString16(ctx.query, "session_id");
|
|
26362
27406
|
if (!sessionId) {
|
|
26363
27407
|
throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
|
|
26364
27408
|
}
|
|
@@ -26383,7 +27427,7 @@ function registerPairingRoutes(router, options) {
|
|
|
26383
27427
|
ctx.body = page;
|
|
26384
27428
|
});
|
|
26385
27429
|
router.get("/api/v1/pairing/session", async (ctx) => {
|
|
26386
|
-
const sessionId =
|
|
27430
|
+
const sessionId = readString16(ctx.query, "session_id");
|
|
26387
27431
|
if (!sessionId) {
|
|
26388
27432
|
throw new LinkHttpError(400, "pairing_session_required", "session_id is required");
|
|
26389
27433
|
}
|
|
@@ -26834,7 +27878,7 @@ function registerInternalRoutes(router, options) {
|
|
|
26834
27878
|
router.post("/internal/deliver", async (ctx) => {
|
|
26835
27879
|
assertLoopbackRequest(ctx.req);
|
|
26836
27880
|
const body = await readJsonBody(ctx.req);
|
|
26837
|
-
const stagingDir =
|
|
27881
|
+
const stagingDir = readString16(body, "staging_dir") ?? readString16(body, "stagingDir");
|
|
26838
27882
|
if (!stagingDir) {
|
|
26839
27883
|
throw new LinkHttpError(
|
|
26840
27884
|
400,
|