@hermespilot/link 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2110,13 +2110,13 @@ async function ensureHermesApiServerConfigUnlocked(profileName = "default", conf
|
|
|
2110
2110
|
const envHost = envOverrides.host?.trim() ? envOverrides.host : null;
|
|
2111
2111
|
const configPort = readApiServerPort(configOnly.port);
|
|
2112
2112
|
const envPort = readApiServerPort(envOverrides.port);
|
|
2113
|
-
const desiredHost =
|
|
2113
|
+
const desiredHost = envHost ?? configHost ?? DEFAULT_HERMES_API_SERVER_HOST;
|
|
2114
2114
|
const desiredPort = await resolveDesiredApiServerPort({
|
|
2115
2115
|
profileName,
|
|
2116
2116
|
configPort,
|
|
2117
2117
|
envPort
|
|
2118
2118
|
});
|
|
2119
|
-
const desiredKey =
|
|
2119
|
+
const desiredKey = envKey ?? configKey ?? randomBytes(32).toString("base64url");
|
|
2120
2120
|
let changed = false;
|
|
2121
2121
|
let enabledAdded = false;
|
|
2122
2122
|
let hostAdded = false;
|
|
@@ -2210,7 +2210,7 @@ async function repairHermesApiServerConfigUnlocked(profileName = "default", conf
|
|
|
2210
2210
|
await readHermesApiServerEnvOverrides(profileName),
|
|
2211
2211
|
true
|
|
2212
2212
|
);
|
|
2213
|
-
const freshPort = await nextProfileApiServerPort(profileName);
|
|
2213
|
+
const freshPort = profileName === "default" ? DEFAULT_HERMES_API_SERVER_PORT : await nextProfileApiServerPort(profileName);
|
|
2214
2214
|
const freshKey = randomBytes(32).toString("base64url");
|
|
2215
2215
|
apiServer.enabled = true;
|
|
2216
2216
|
extra.host = DEFAULT_HERMES_API_SERVER_HOST;
|
|
@@ -2239,7 +2239,7 @@ async function repairHermesApiServerConfigUnlocked(profileName = "default", conf
|
|
|
2239
2239
|
hostAdded: previous.host !== DEFAULT_HERMES_API_SERVER_HOST,
|
|
2240
2240
|
portAdded: previous.port !== freshPort,
|
|
2241
2241
|
backupPath,
|
|
2242
|
-
notice: "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002"
|
|
2242
|
+
notice: profileName === "default" ? "\u5DF2\u4E3A Hermes API Server \u4FDD\u6301\u9ED8\u8BA4\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002" : "\u5DF2\u4E3A Hermes API Server \u91CD\u65B0\u5206\u914D\u672C\u673A\u7AEF\u53E3\u5E76\u8F6E\u6362 key\uFF0C\u7528\u4E8E\u4FEE\u590D\u65E7 Gateway \u6216 key \u4E0D\u4E00\u81F4\u5BFC\u81F4\u7684 401\u3002"
|
|
2243
2243
|
};
|
|
2244
2244
|
}
|
|
2245
2245
|
async function readHermesConfigDocument(configPath) {
|
|
@@ -3579,16 +3579,14 @@ function readApiServerPort(value) {
|
|
|
3579
3579
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
3580
3580
|
}
|
|
3581
3581
|
async function resolveDesiredApiServerPort(input) {
|
|
3582
|
+
const effectivePort = input.envPort ?? input.configPort;
|
|
3582
3583
|
if (shouldAssignDedicatedProfileApiServerPort(
|
|
3583
3584
|
input.profileName,
|
|
3584
|
-
|
|
3585
|
+
effectivePort ?? void 0
|
|
3585
3586
|
)) {
|
|
3586
|
-
if (input.profileName !== "default" && input.envPort !== null && input.envPort !== DEFAULT_HERMES_API_SERVER_PORT) {
|
|
3587
|
-
return input.envPort;
|
|
3588
|
-
}
|
|
3589
3587
|
return nextProfileApiServerPort(input.profileName);
|
|
3590
3588
|
}
|
|
3591
|
-
return
|
|
3589
|
+
return effectivePort ?? DEFAULT_HERMES_API_SERVER_PORT;
|
|
3592
3590
|
}
|
|
3593
3591
|
async function nextProfileApiServerPort(profileName) {
|
|
3594
3592
|
const usedPorts = await readConfiguredApiServerPorts(profileName);
|
|
@@ -3877,6 +3875,9 @@ function buildNotice(flags) {
|
|
|
3877
3875
|
if (flags.keyAdded) {
|
|
3878
3876
|
fields.push("key");
|
|
3879
3877
|
}
|
|
3878
|
+
if (fields.length === 0) {
|
|
3879
|
+
return "\u5DF2\u540C\u6B65 Hermes API Server config.yaml \u4E0E Profile .env \u7684\u6709\u6548\u914D\u7F6E\u3002";
|
|
3880
|
+
}
|
|
3880
3881
|
return `\u5DF2\u4E3A Hermes API Server \u81EA\u52A8\u8865\u5145 ${fields.join("\u3001")}\uFF1B\u672A\u8986\u76D6\u5DF2\u6709 port/host/key\u3002`;
|
|
3881
3882
|
}
|
|
3882
3883
|
function toRecord(value) {
|
|
@@ -4133,7 +4134,7 @@ import os2 from "os";
|
|
|
4133
4134
|
import path5 from "path";
|
|
4134
4135
|
|
|
4135
4136
|
// src/constants.ts
|
|
4136
|
-
var LINK_VERSION = "0.
|
|
4137
|
+
var LINK_VERSION = "0.5.0";
|
|
4137
4138
|
var LINK_COMMAND = "hermeslink";
|
|
4138
4139
|
var LINK_DEFAULT_PORT = 52379;
|
|
4139
4140
|
var LINK_RUNTIME_DIR_NAME = ".hermeslink";
|
|
@@ -7746,7 +7747,7 @@ var ConversationMaintenanceCoordinator = class {
|
|
|
7746
7747
|
hermesSessionIds,
|
|
7747
7748
|
manifest.profile_name_snapshot ?? manifest.profile ?? "default"
|
|
7748
7749
|
);
|
|
7749
|
-
if (
|
|
7750
|
+
if (hermesDeleteResults.some((result) => result.status === "unknown")) {
|
|
7750
7751
|
throw new LinkHttpError(
|
|
7751
7752
|
502,
|
|
7752
7753
|
"hermes_session_delete_not_confirmed",
|
|
@@ -13129,8 +13130,15 @@ function normalizeHermesResponseEvent(event) {
|
|
|
13129
13130
|
return normalizeResponseCompleted(event);
|
|
13130
13131
|
case "response.failed":
|
|
13131
13132
|
return normalizeResponseFailed(event);
|
|
13133
|
+
case "response.output_text.done": {
|
|
13134
|
+
const delta = readDelta(event.payload);
|
|
13135
|
+
return delta ? {
|
|
13136
|
+
...event,
|
|
13137
|
+
payloadType: "message.delta",
|
|
13138
|
+
payload: { type: "message.delta", delta }
|
|
13139
|
+
} : null;
|
|
13140
|
+
}
|
|
13132
13141
|
case "response.created":
|
|
13133
|
-
case "response.output_text.done":
|
|
13134
13142
|
return null;
|
|
13135
13143
|
default:
|
|
13136
13144
|
return null;
|
|
@@ -13160,6 +13168,14 @@ function normalizeResponseOutputItemAdded(event) {
|
|
|
13160
13168
|
}
|
|
13161
13169
|
function normalizeResponseOutputItemDone(event) {
|
|
13162
13170
|
const item = toRecord10(event.payload.item);
|
|
13171
|
+
if (readString12(item, "type") === "message") {
|
|
13172
|
+
const delta = extractResponseAssistantText({ output: [item] });
|
|
13173
|
+
return delta ? {
|
|
13174
|
+
...event,
|
|
13175
|
+
payloadType: "message.delta",
|
|
13176
|
+
payload: { type: "message.delta", delta }
|
|
13177
|
+
} : null;
|
|
13178
|
+
}
|
|
13163
13179
|
if (readString12(item, "type") !== "function_call_output") {
|
|
13164
13180
|
return null;
|
|
13165
13181
|
}
|
|
@@ -13234,6 +13250,30 @@ function readErrorMessage2(payload) {
|
|
|
13234
13250
|
function readDelta(payload) {
|
|
13235
13251
|
return readText2(payload, "delta") ?? readText2(payload, "text") ?? readText2(payload, "content");
|
|
13236
13252
|
}
|
|
13253
|
+
function extractResponseAssistantText(value) {
|
|
13254
|
+
if (typeof value === "string") {
|
|
13255
|
+
return value.trim().length > 0 ? value : null;
|
|
13256
|
+
}
|
|
13257
|
+
const payload = toRecord10(value);
|
|
13258
|
+
const response = toRecord10(payload.response ?? value);
|
|
13259
|
+
const directText = readText2(response, "output_text");
|
|
13260
|
+
if (directText?.trim()) {
|
|
13261
|
+
return directText;
|
|
13262
|
+
}
|
|
13263
|
+
const output = response.output;
|
|
13264
|
+
if (Array.isArray(output)) {
|
|
13265
|
+
const messages = output.map(readResponseOutputItemText).filter((text) => Boolean(text?.trim()));
|
|
13266
|
+
if (messages.length > 0) {
|
|
13267
|
+
return messages.join("\n\n");
|
|
13268
|
+
}
|
|
13269
|
+
}
|
|
13270
|
+
const choicesText = readAssistantTextFromChoices(response);
|
|
13271
|
+
if (choicesText) {
|
|
13272
|
+
return choicesText;
|
|
13273
|
+
}
|
|
13274
|
+
const fallbackText = readResponseMessageText(response);
|
|
13275
|
+
return fallbackText?.trim() ? fallbackText : null;
|
|
13276
|
+
}
|
|
13237
13277
|
function emptyHermesResponseMessage() {
|
|
13238
13278
|
return "Hermes \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\u3002\u8BF7\u5148\u770B Gateway / \u6A21\u578B\u914D\u7F6E\u662F\u5426\u6B63\u5E38\uFF0C\u6216\u67E5\u770B\u4E0B\u65B9\u5931\u8D25\u8BE6\u60C5\u3002";
|
|
13239
13279
|
}
|
|
@@ -13303,6 +13343,17 @@ function readFirstChoice(payload) {
|
|
|
13303
13343
|
}
|
|
13304
13344
|
return toRecord10(choices[0]);
|
|
13305
13345
|
}
|
|
13346
|
+
function readAssistantTextFromChoices(payload) {
|
|
13347
|
+
const choices = payload.choices;
|
|
13348
|
+
if (!Array.isArray(choices)) {
|
|
13349
|
+
return null;
|
|
13350
|
+
}
|
|
13351
|
+
const messages = choices.map(toRecord10).map((choice) => toRecord10(choice.message ?? choice.delta)).filter((message) => {
|
|
13352
|
+
const role = readString12(message, "role");
|
|
13353
|
+
return !role || role === "assistant";
|
|
13354
|
+
}).map(readResponseMessageText).filter((text) => Boolean(text?.trim()));
|
|
13355
|
+
return messages.length > 0 ? messages.join("\n\n") : null;
|
|
13356
|
+
}
|
|
13306
13357
|
function readInteger2(payload, key) {
|
|
13307
13358
|
const value = payload[key];
|
|
13308
13359
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -13322,6 +13373,50 @@ function readText2(payload, key) {
|
|
|
13322
13373
|
const value = payload[key];
|
|
13323
13374
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
13324
13375
|
}
|
|
13376
|
+
function readResponseOutputItemText(value) {
|
|
13377
|
+
if (typeof value === "string") {
|
|
13378
|
+
return value;
|
|
13379
|
+
}
|
|
13380
|
+
const item = toRecord10(value);
|
|
13381
|
+
const type = readString12(item, "type");
|
|
13382
|
+
const role = readString12(item, "role");
|
|
13383
|
+
if (type && type !== "message" && type !== "output_text" && type !== "text") {
|
|
13384
|
+
return null;
|
|
13385
|
+
}
|
|
13386
|
+
if (role && role !== "assistant") {
|
|
13387
|
+
return null;
|
|
13388
|
+
}
|
|
13389
|
+
return readResponseMessageText(item);
|
|
13390
|
+
}
|
|
13391
|
+
function readResponseMessageText(payload) {
|
|
13392
|
+
const contentText = readResponseContentText(payload.content);
|
|
13393
|
+
return contentText ?? readText2(payload, "output_text") ?? readText2(payload, "text") ?? readText2(payload, "content") ?? readText2(payload, "refusal");
|
|
13394
|
+
}
|
|
13395
|
+
function readResponseContentText(value) {
|
|
13396
|
+
if (typeof value === "string") {
|
|
13397
|
+
return value;
|
|
13398
|
+
}
|
|
13399
|
+
if (!Array.isArray(value)) {
|
|
13400
|
+
const record = toRecord10(value);
|
|
13401
|
+
return readText2(record, "text") ?? readText2(record, "content") ?? readText2(record, "output_text") ?? readText2(record, "refusal");
|
|
13402
|
+
}
|
|
13403
|
+
const chunks = value.map((partValue) => {
|
|
13404
|
+
if (typeof partValue === "string") {
|
|
13405
|
+
return partValue;
|
|
13406
|
+
}
|
|
13407
|
+
const part = toRecord10(partValue);
|
|
13408
|
+
const type = readString12(part, "type");
|
|
13409
|
+
if (type && !isVisibleResponseTextPart(type)) {
|
|
13410
|
+
return null;
|
|
13411
|
+
}
|
|
13412
|
+
return readText2(part, "text") ?? readText2(part, "content") ?? readText2(part, "output_text") ?? readText2(part, "refusal");
|
|
13413
|
+
}).filter((text2) => Boolean(text2));
|
|
13414
|
+
const text = chunks.join("");
|
|
13415
|
+
return text.trim() ? text : null;
|
|
13416
|
+
}
|
|
13417
|
+
function isVisibleResponseTextPart(type) {
|
|
13418
|
+
return type === "output_text" || type === "text" || type === "message_text" || type === "refusal";
|
|
13419
|
+
}
|
|
13325
13420
|
function readResponseItemOutput(value) {
|
|
13326
13421
|
if (typeof value === "string") {
|
|
13327
13422
|
return value;
|
|
@@ -13502,6 +13597,11 @@ var ConversationRunLifecycle = class {
|
|
|
13502
13597
|
error: error instanceof Error ? error.message : String(error)
|
|
13503
13598
|
});
|
|
13504
13599
|
});
|
|
13600
|
+
await this.appendAssistantTextFromCompletedResponse(
|
|
13601
|
+
conversationId,
|
|
13602
|
+
runId,
|
|
13603
|
+
event
|
|
13604
|
+
);
|
|
13505
13605
|
await this.importMediaReferencesForEvent(conversationId, runId, event);
|
|
13506
13606
|
if (!await this.runHasAssistantOutput(conversationId, runId)) {
|
|
13507
13607
|
await this.failRun(
|
|
@@ -13547,7 +13647,7 @@ var ConversationRunLifecycle = class {
|
|
|
13547
13647
|
conversationId,
|
|
13548
13648
|
runId,
|
|
13549
13649
|
await this.buildEmptyHermesResponseMessage({
|
|
13550
|
-
source: "
|
|
13650
|
+
source: "stream-ended-without-terminal-event"
|
|
13551
13651
|
})
|
|
13552
13652
|
);
|
|
13553
13653
|
}
|
|
@@ -13687,6 +13787,31 @@ ${attachmentLines.join("\n")}`
|
|
|
13687
13787
|
}
|
|
13688
13788
|
return messageText(assistant).length > 0 || (assistant.agent_events?.length ?? 0) > 0 || (assistant.approvals?.length ?? 0) > 0 || assistant.parts.some((part) => part.type !== "text");
|
|
13689
13789
|
}
|
|
13790
|
+
async appendAssistantTextFromCompletedResponse(conversationId, runId, event) {
|
|
13791
|
+
const terminalText = extractResponseAssistantText(event.payload);
|
|
13792
|
+
if (!terminalText?.trim()) {
|
|
13793
|
+
return;
|
|
13794
|
+
}
|
|
13795
|
+
await this.deps.withConversationLock(conversationId, async () => {
|
|
13796
|
+
const snapshot = await this.deps.readSnapshot(conversationId);
|
|
13797
|
+
const run = snapshot.runs.find((item) => item.id === runId);
|
|
13798
|
+
const assistant = snapshot.messages.find(
|
|
13799
|
+
(item) => item.id === run?.assistant_message_id
|
|
13800
|
+
);
|
|
13801
|
+
if (!assistant) {
|
|
13802
|
+
return;
|
|
13803
|
+
}
|
|
13804
|
+
const currentText = assistant.parts.find((part) => part.type === "text")?.text ?? "";
|
|
13805
|
+
const delta = normalizeTerminalResponseTextDelta(
|
|
13806
|
+
currentText,
|
|
13807
|
+
terminalText
|
|
13808
|
+
);
|
|
13809
|
+
if (!delta) {
|
|
13810
|
+
return;
|
|
13811
|
+
}
|
|
13812
|
+
await this.appendAssistantDelta(conversationId, runId, delta, event);
|
|
13813
|
+
});
|
|
13814
|
+
}
|
|
13690
13815
|
async buildEmptyHermesResponseMessage(input) {
|
|
13691
13816
|
const runtime = await readCurrentConversationRuntime(this.deps.paths).catch(
|
|
13692
13817
|
() => null
|
|
@@ -13707,6 +13832,14 @@ ${attachmentLines.join("\n")}`
|
|
|
13707
13832
|
);
|
|
13708
13833
|
}
|
|
13709
13834
|
}
|
|
13835
|
+
if (input?.source === "stream-ended-without-terminal-event") {
|
|
13836
|
+
details.unshift(
|
|
13837
|
+
"Hermes \u7684\u8FD0\u884C\u4E8B\u4EF6\u6D41\u63D0\u524D\u7ED3\u675F\uFF0CLink \u6CA1\u6709\u6536\u5230\u5B8C\u6210\u6216\u5931\u8D25\u4E8B\u4EF6\u3002"
|
|
13838
|
+
);
|
|
13839
|
+
details.push(
|
|
13840
|
+
"\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"
|
|
13841
|
+
);
|
|
13842
|
+
}
|
|
13710
13843
|
return details.length > 0 ? `Hermes \u6CA1\u6709\u8FD4\u56DE\u6709\u6548\u5185\u5BB9\u3002
|
|
13711
13844
|
${details.join("\n")}` : emptyHermesResponseMessage();
|
|
13712
13845
|
}
|
|
@@ -14295,6 +14428,29 @@ function isVoicePart(part) {
|
|
|
14295
14428
|
function normalizeToolName(value) {
|
|
14296
14429
|
return value.trim().toLowerCase().replace(/[\s-]+/gu, "_");
|
|
14297
14430
|
}
|
|
14431
|
+
function normalizeTerminalResponseTextDelta(currentText, terminalText) {
|
|
14432
|
+
if (!terminalText.trim()) {
|
|
14433
|
+
return "";
|
|
14434
|
+
}
|
|
14435
|
+
if (!currentText) {
|
|
14436
|
+
return terminalText;
|
|
14437
|
+
}
|
|
14438
|
+
if (terminalText === currentText) {
|
|
14439
|
+
return "";
|
|
14440
|
+
}
|
|
14441
|
+
if (terminalText.startsWith(currentText)) {
|
|
14442
|
+
return terminalText.slice(currentText.length);
|
|
14443
|
+
}
|
|
14444
|
+
const normalizedCurrent = currentText.trim();
|
|
14445
|
+
const normalizedTerminal = terminalText.trim();
|
|
14446
|
+
if (!normalizedCurrent || normalizedTerminal === normalizedCurrent) {
|
|
14447
|
+
return "";
|
|
14448
|
+
}
|
|
14449
|
+
if (normalizedTerminal.startsWith(normalizedCurrent)) {
|
|
14450
|
+
return normalizedTerminal.slice(normalizedCurrent.length);
|
|
14451
|
+
}
|
|
14452
|
+
return "";
|
|
14453
|
+
}
|
|
14298
14454
|
function appendTextBlock2(message, delta, updatedAt) {
|
|
14299
14455
|
if (!delta) {
|
|
14300
14456
|
return;
|
package/dist/cli/index.js
CHANGED
package/dist/http/app.js
CHANGED