@liberseek/boft-cli-win32-arm64 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.txt +0 -4
- package/app/codexhost-distribution.json +1 -1
- package/app/desktop-controller.mjs +256 -179
- package/app/host-runtime.mjs +646 -323
- package/app/plugins/antigravity/plugin.mjs +123 -1
- package/app/plugins/claude-code/plugin.mjs +252 -46
- package/app/plugins/codebuddy/plugin.mjs +2287 -879
- package/app/plugins/cursor-cli/plugin.mjs +35756 -10755
- package/app/plugins/deepseek-harness/plugin.mjs +70 -0
- package/app/plugins/enabled.json +1 -0
- package/app/plugins/grok/plugin.mjs +193 -82
- package/app/plugins/hermes/plugin.mjs +2444 -94
- package/app/plugins/kiro-cli/plugin.mjs +70 -0
- package/app/plugins/muse/plugin.mjs +70 -0
- package/app/plugins/omp/plugin.mjs +92 -4
- package/app/plugins/opencode/plugin.mjs +70 -0
- package/app/plugins/pi/plugin.mjs +2139 -973
- package/app/plugins/qoder/plugin.mjs +71 -9
- package/app/plugins/qoder-cn/plugin.mjs +71 -9
- package/app/plugins/workbuddy/assets/icon.svg +29 -0
- package/app/plugins/workbuddy/manifest.json +14 -0
- package/app/plugins/workbuddy/plugin.mjs +25007 -0
- package/app/renderer-extension.js +2874 -1408
- package/bin/boft.exe +0 -0
- package/libexec/boft-node-repl.exe +0 -0
- package/libexec/boft-shim.exe +0 -0
- package/libexec/boft-updater.exe +0 -0
- package/package.json +1 -1
- package/licenses/opencodex-LICENSE.txt +0 -21
|
@@ -5,9 +5,6 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// dist/hermes-adapter.js
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
|
-
|
|
11
8
|
// ../../../node_modules/zod/v4/classic/external.js
|
|
12
9
|
var external_exports = {};
|
|
13
10
|
__export(external_exports, {
|
|
@@ -774,10 +771,10 @@ function mergeDefs(...defs) {
|
|
|
774
771
|
function cloneDef(schema) {
|
|
775
772
|
return mergeDefs(schema._zod.def);
|
|
776
773
|
}
|
|
777
|
-
function getElementAtPath(obj,
|
|
778
|
-
if (!
|
|
774
|
+
function getElementAtPath(obj, path7) {
|
|
775
|
+
if (!path7)
|
|
779
776
|
return obj;
|
|
780
|
-
return
|
|
777
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
781
778
|
}
|
|
782
779
|
function promiseAllObject(promisesObj) {
|
|
783
780
|
const keys = Object.keys(promisesObj);
|
|
@@ -1186,11 +1183,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1186
1183
|
}
|
|
1187
1184
|
return false;
|
|
1188
1185
|
}
|
|
1189
|
-
function prefixIssues(
|
|
1186
|
+
function prefixIssues(path7, issues) {
|
|
1190
1187
|
return issues.map((iss) => {
|
|
1191
1188
|
var _a3;
|
|
1192
1189
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1193
|
-
iss.path.unshift(
|
|
1190
|
+
iss.path.unshift(path7);
|
|
1194
1191
|
return iss;
|
|
1195
1192
|
});
|
|
1196
1193
|
}
|
|
@@ -1337,16 +1334,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1337
1334
|
}
|
|
1338
1335
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
1339
1336
|
const fieldErrors = { _errors: [] };
|
|
1340
|
-
const processError = (error52,
|
|
1337
|
+
const processError = (error52, path7 = []) => {
|
|
1341
1338
|
for (const issue2 of error52.issues) {
|
|
1342
1339
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1343
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1340
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
1344
1341
|
} else if (issue2.code === "invalid_key") {
|
|
1345
|
-
processError({ issues: issue2.issues }, [...
|
|
1342
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
1346
1343
|
} else if (issue2.code === "invalid_element") {
|
|
1347
|
-
processError({ issues: issue2.issues }, [...
|
|
1344
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
1348
1345
|
} else {
|
|
1349
|
-
const fullpath = [...
|
|
1346
|
+
const fullpath = [...path7, ...issue2.path];
|
|
1350
1347
|
if (fullpath.length === 0) {
|
|
1351
1348
|
fieldErrors._errors.push(mapper(issue2));
|
|
1352
1349
|
} else {
|
|
@@ -1373,17 +1370,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1373
1370
|
}
|
|
1374
1371
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
1375
1372
|
const result = { errors: [] };
|
|
1376
|
-
const processError = (error52,
|
|
1373
|
+
const processError = (error52, path7 = []) => {
|
|
1377
1374
|
var _a3, _b;
|
|
1378
1375
|
for (const issue2 of error52.issues) {
|
|
1379
1376
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1380
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1377
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
1381
1378
|
} else if (issue2.code === "invalid_key") {
|
|
1382
|
-
processError({ issues: issue2.issues }, [...
|
|
1379
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
1383
1380
|
} else if (issue2.code === "invalid_element") {
|
|
1384
|
-
processError({ issues: issue2.issues }, [...
|
|
1381
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
1385
1382
|
} else {
|
|
1386
|
-
const fullpath = [...
|
|
1383
|
+
const fullpath = [...path7, ...issue2.path];
|
|
1387
1384
|
if (fullpath.length === 0) {
|
|
1388
1385
|
result.errors.push(mapper(issue2));
|
|
1389
1386
|
continue;
|
|
@@ -1415,8 +1412,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
1415
1412
|
}
|
|
1416
1413
|
function toDotPath(_path) {
|
|
1417
1414
|
const segs = [];
|
|
1418
|
-
const
|
|
1419
|
-
for (const seg of
|
|
1415
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1416
|
+
for (const seg of path7) {
|
|
1420
1417
|
if (typeof seg === "number")
|
|
1421
1418
|
segs.push(`[${seg}]`);
|
|
1422
1419
|
else if (typeof seg === "symbol")
|
|
@@ -7646,8 +7643,8 @@ function ko_default() {
|
|
|
7646
7643
|
}
|
|
7647
7644
|
|
|
7648
7645
|
// ../../../node_modules/zod/v4/locales/lt.js
|
|
7649
|
-
var capitalizeFirstCharacter = (
|
|
7650
|
-
return
|
|
7646
|
+
var capitalizeFirstCharacter = (text2) => {
|
|
7647
|
+
return text2.charAt(0).toUpperCase() + text2.slice(1);
|
|
7651
7648
|
};
|
|
7652
7649
|
function getUnitTypeFromNumber(number4) {
|
|
7653
7650
|
const abs = Math.abs(number4);
|
|
@@ -14108,13 +14105,13 @@ function resolveRef(ref, ctx) {
|
|
|
14108
14105
|
if (!ref.startsWith("#")) {
|
|
14109
14106
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
14110
14107
|
}
|
|
14111
|
-
const
|
|
14112
|
-
if (
|
|
14108
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
14109
|
+
if (path7.length === 0) {
|
|
14113
14110
|
return ctx.rootSchema;
|
|
14114
14111
|
}
|
|
14115
14112
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
14116
|
-
if (
|
|
14117
|
-
const key =
|
|
14113
|
+
if (path7[0] === defsKey) {
|
|
14114
|
+
const key = path7[1];
|
|
14118
14115
|
if (!key || !ctx.defs[key]) {
|
|
14119
14116
|
throw new Error(`Reference not found: ${ref}`);
|
|
14120
14117
|
}
|
|
@@ -14522,6 +14519,61 @@ function date4(params) {
|
|
|
14522
14519
|
// ../../../node_modules/zod/v4/classic/external.js
|
|
14523
14520
|
config(en_default());
|
|
14524
14521
|
|
|
14522
|
+
// ../../shared-contracts/dist/credential-imports.js
|
|
14523
|
+
var credentialSourceSchema = external_exports.object({
|
|
14524
|
+
id: external_exports.string().min(1).max(256),
|
|
14525
|
+
harnessId: external_exports.string().min(1),
|
|
14526
|
+
label: external_exports.string().min(1).max(512),
|
|
14527
|
+
provider: external_exports.enum(["openai-codex", "xai"])
|
|
14528
|
+
}).strict();
|
|
14529
|
+
var credentialImportNameSchema = external_exports.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
|
|
14530
|
+
var credentialImportRecordSchema = external_exports.object({
|
|
14531
|
+
name: credentialImportNameSchema,
|
|
14532
|
+
source: credentialSourceSchema,
|
|
14533
|
+
importedAt: external_exports.string()
|
|
14534
|
+
}).strict();
|
|
14535
|
+
var credentialImportsRequestSchema = external_exports.discriminatedUnion("action", [
|
|
14536
|
+
external_exports.object({ action: external_exports.literal("list") }).strict(),
|
|
14537
|
+
external_exports.object({
|
|
14538
|
+
action: external_exports.literal("import"),
|
|
14539
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
14540
|
+
name: credentialImportNameSchema,
|
|
14541
|
+
confirmed: external_exports.literal(true)
|
|
14542
|
+
}).strict(),
|
|
14543
|
+
external_exports.object({
|
|
14544
|
+
action: external_exports.literal("reimport"),
|
|
14545
|
+
sourceId: external_exports.string().min(1).max(256),
|
|
14546
|
+
name: credentialImportNameSchema,
|
|
14547
|
+
confirmed: external_exports.literal(true)
|
|
14548
|
+
}).strict(),
|
|
14549
|
+
external_exports.object({
|
|
14550
|
+
action: external_exports.literal("remove"),
|
|
14551
|
+
name: credentialImportNameSchema,
|
|
14552
|
+
confirmed: external_exports.literal(true)
|
|
14553
|
+
}).strict()
|
|
14554
|
+
]);
|
|
14555
|
+
var credentialOtherLoginSchema = external_exports.object({
|
|
14556
|
+
provider: external_exports.string().min(1).max(128),
|
|
14557
|
+
type: external_exports.enum(["oauth", "api_key", "unknown"]),
|
|
14558
|
+
/** Best-effort account label (e.g. the email in a Codex token), derived locally when present. */
|
|
14559
|
+
label: external_exports.string().min(1).max(512).optional(),
|
|
14560
|
+
/** Recognized credential vendor, derived from the OAuth token issuer. Absent when unknown. */
|
|
14561
|
+
vendor: external_exports.enum(["openai-codex", "xai"]).optional()
|
|
14562
|
+
}).strict();
|
|
14563
|
+
var credentialImportsResultSchema = external_exports.object({
|
|
14564
|
+
sources: external_exports.array(credentialSourceSchema),
|
|
14565
|
+
targets: external_exports.array(external_exports.object({
|
|
14566
|
+
harnessId: external_exports.string(),
|
|
14567
|
+
providers: external_exports.array(external_exports.enum(["openai-codex", "xai"])),
|
|
14568
|
+
imports: external_exports.array(credentialImportRecordSchema),
|
|
14569
|
+
others: external_exports.array(credentialOtherLoginSchema).default([])
|
|
14570
|
+
}).strict())
|
|
14571
|
+
}).strict();
|
|
14572
|
+
var credentialImportsParamsSchema = external_exports.object({
|
|
14573
|
+
targetHarnessId: external_exports.string().min(1).max(128).optional(),
|
|
14574
|
+
request: credentialImportsRequestSchema
|
|
14575
|
+
}).strict();
|
|
14576
|
+
|
|
14525
14577
|
// ../../shared-contracts/dist/version.js
|
|
14526
14578
|
var WORKSPACE_CONTRACT_VERSION = 1;
|
|
14527
14579
|
|
|
@@ -15071,6 +15123,8 @@ var pluginPresentationShape = {
|
|
|
15071
15123
|
id: harnessPluginIdSchema,
|
|
15072
15124
|
name: external_exports.string().trim().min(1).max(128),
|
|
15073
15125
|
version: external_exports.string().min(1).max(128),
|
|
15126
|
+
/** The factory accepts a persisted local entrypoint through its construction context. */
|
|
15127
|
+
launchCommand: external_exports.literal(true).optional(),
|
|
15074
15128
|
links: external_exports.object({
|
|
15075
15129
|
documentation: documentationUrlSchema.optional(),
|
|
15076
15130
|
installation: documentationUrlSchema.optional()
|
|
@@ -15108,6 +15162,19 @@ var harnessPluginRouteSchema = external_exports.object({
|
|
|
15108
15162
|
permissionModeId: harnessPermissionModeIdSchema.optional()
|
|
15109
15163
|
}).strict();
|
|
15110
15164
|
|
|
15165
|
+
// ../../shared-contracts/dist/harness-launch-settings.js
|
|
15166
|
+
var harnessLaunchPathSchema = external_exports.string().trim().min(1).max(4096).refine((value) => !/[\u0000\r\n]/u.test(value), "Invalid entrypoint path");
|
|
15167
|
+
var harnessLaunchSettingsGetSchema = external_exports.object({
|
|
15168
|
+
harnessId: harnessPluginIdSchema
|
|
15169
|
+
}).strict();
|
|
15170
|
+
var harnessLaunchSettingsSetSchema = harnessLaunchSettingsGetSchema.extend({
|
|
15171
|
+
path: harnessLaunchPathSchema.nullable()
|
|
15172
|
+
});
|
|
15173
|
+
var harnessLaunchSettingsSchema = external_exports.object({
|
|
15174
|
+
path: harnessLaunchPathSchema.nullable(),
|
|
15175
|
+
restartRequired: external_exports.boolean()
|
|
15176
|
+
}).strict();
|
|
15177
|
+
|
|
15111
15178
|
// ../../shared-contracts/dist/codex-accounts.js
|
|
15112
15179
|
var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
|
|
15113
15180
|
var nonBlankTextSchema3 = external_exports.string().trim().min(1);
|
|
@@ -15341,6 +15408,8 @@ var nativeCheckpointRefV1RuntimeSchema = external_exports.strictObject({
|
|
|
15341
15408
|
locator: jsonValueSchema.optional(),
|
|
15342
15409
|
formatVersion: external_exports.literal(1)
|
|
15343
15410
|
}).superRefine(rejectExplicitUndefined(["locator"]));
|
|
15411
|
+
var nativeCheckpointRefV1Schema = nativeCheckpointRefV1RuntimeSchema;
|
|
15412
|
+
var nativeCheckpointRefSchema = nativeCheckpointRefV1Schema;
|
|
15344
15413
|
|
|
15345
15414
|
// ../../shared-contracts/dist/updates.js
|
|
15346
15415
|
var UPDATE_ERROR_MAX_LENGTH = 500;
|
|
@@ -15396,6 +15465,62 @@ var updateStatusResultSchema = external_exports.strictObject({
|
|
|
15396
15465
|
// ../../shared-contracts/dist/index.js
|
|
15397
15466
|
var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
|
|
15398
15467
|
|
|
15468
|
+
// dist/hermes-commands.js
|
|
15469
|
+
var SUPPORTED_COMMANDS = /* @__PURE__ */ new Set(["help", "tools", "context", "compress", "version"]);
|
|
15470
|
+
function hermesCommandCatalog(commands) {
|
|
15471
|
+
return harnessCommandCatalogSchema.parse({
|
|
15472
|
+
commands: commands.filter((command) => SUPPORTED_COMMANDS.has(command.name)).map((command) => ({
|
|
15473
|
+
id: `hermes.${command.name}`,
|
|
15474
|
+
invocation: `/${command.name}`,
|
|
15475
|
+
label: `/${command.name}`,
|
|
15476
|
+
description: command.description.slice(0, 512) || `Hermes /${command.name}`,
|
|
15477
|
+
argumentMode: command.input ? "text" : "none"
|
|
15478
|
+
}))
|
|
15479
|
+
});
|
|
15480
|
+
}
|
|
15481
|
+
var HERMES_GATEWAY_COMMANDS = [
|
|
15482
|
+
...["help", "tools", "context", "version"].map((name) => ({
|
|
15483
|
+
name,
|
|
15484
|
+
description: `Hermes /${name}`
|
|
15485
|
+
})),
|
|
15486
|
+
{
|
|
15487
|
+
name: "compress",
|
|
15488
|
+
description: "Compress conversation context",
|
|
15489
|
+
input: { hint: "Optional compression focus" }
|
|
15490
|
+
}
|
|
15491
|
+
];
|
|
15492
|
+
var HERMES_COMMAND_CATALOG = hermesCommandCatalog(HERMES_GATEWAY_COMMANDS);
|
|
15493
|
+
function hermesCommandText(command, catalog) {
|
|
15494
|
+
const descriptor = catalog.commands.find((entry) => entry.id === command.commandId);
|
|
15495
|
+
if (!descriptor)
|
|
15496
|
+
return {
|
|
15497
|
+
ok: false,
|
|
15498
|
+
error: {
|
|
15499
|
+
code: "unsupported",
|
|
15500
|
+
message: "Hermes did not advertise this command",
|
|
15501
|
+
retryable: false
|
|
15502
|
+
}
|
|
15503
|
+
};
|
|
15504
|
+
const args = command.arguments ?? {};
|
|
15505
|
+
if (Object.keys(args).some((key) => key !== "text") || args.text !== void 0 && typeof args.text !== "string" || descriptor.argumentMode === "none" && typeof args.text === "string" && args.text.trim()) {
|
|
15506
|
+
return {
|
|
15507
|
+
ok: false,
|
|
15508
|
+
error: {
|
|
15509
|
+
code: "invalidRequest",
|
|
15510
|
+
message: "Invalid Hermes command arguments",
|
|
15511
|
+
retryable: false
|
|
15512
|
+
}
|
|
15513
|
+
};
|
|
15514
|
+
}
|
|
15515
|
+
return {
|
|
15516
|
+
ok: true,
|
|
15517
|
+
value: `${descriptor.invocation}${typeof args.text === "string" && args.text.trim() ? ` ${args.text.trim()}` : ""}`
|
|
15518
|
+
};
|
|
15519
|
+
}
|
|
15520
|
+
|
|
15521
|
+
// dist/hermes-adapter.js
|
|
15522
|
+
import { createHash } from "node:crypto";
|
|
15523
|
+
|
|
15399
15524
|
// dist/acp-transport.js
|
|
15400
15525
|
import { spawn, spawnSync } from "node:child_process";
|
|
15401
15526
|
import { Readable, Writable } from "node:stream";
|
|
@@ -15408,6 +15533,42 @@ function validateHostApprovalResponse(interaction, response) {
|
|
|
15408
15533
|
return interaction.actions.some(({ id }) => id === response.actionId) ? null : invalidRequest("Approval Response contains an undeclared action ID");
|
|
15409
15534
|
}
|
|
15410
15535
|
|
|
15536
|
+
// ../../harness-adapter/dist/question.js
|
|
15537
|
+
function invalidRequest2(message) {
|
|
15538
|
+
return { code: "invalidRequest", message, retryable: false };
|
|
15539
|
+
}
|
|
15540
|
+
function validateHostQuestionResponse(interaction, response) {
|
|
15541
|
+
const questionIds = new Set(interaction.questions.map(({ id }) => id));
|
|
15542
|
+
if (response.cancelled) {
|
|
15543
|
+
return Object.keys(response.answers).length === 0 ? null : invalidRequest2("Cancelled Question Response must not contain answers");
|
|
15544
|
+
}
|
|
15545
|
+
for (const answerId of Object.keys(response.answers)) {
|
|
15546
|
+
if (!questionIds.has(answerId)) {
|
|
15547
|
+
return invalidRequest2("Question Response contains an unknown Question ID");
|
|
15548
|
+
}
|
|
15549
|
+
}
|
|
15550
|
+
for (const question2 of interaction.questions) {
|
|
15551
|
+
const answers = response.answers[question2.id] ?? [];
|
|
15552
|
+
if (!question2.optional && answers.length === 0) {
|
|
15553
|
+
return invalidRequest2("Question Response omits a required answer");
|
|
15554
|
+
}
|
|
15555
|
+
if (question2.type === "text") {
|
|
15556
|
+
if (answers.length > 1) {
|
|
15557
|
+
return invalidRequest2("Text Question accepts at most one answer");
|
|
15558
|
+
}
|
|
15559
|
+
continue;
|
|
15560
|
+
}
|
|
15561
|
+
if (!question2.multiple && answers.length > 1) {
|
|
15562
|
+
return invalidRequest2("Single-choice Question accepts at most one answer");
|
|
15563
|
+
}
|
|
15564
|
+
const declared = new Set(question2.options.map(({ value }) => value));
|
|
15565
|
+
if (!question2.allowOther && answers.some((answer) => !declared.has(answer))) {
|
|
15566
|
+
return invalidRequest2("Question Response contains an undeclared choice");
|
|
15567
|
+
}
|
|
15568
|
+
}
|
|
15569
|
+
return null;
|
|
15570
|
+
}
|
|
15571
|
+
|
|
15411
15572
|
// ../../harness-adapter/dist/output-channel.js
|
|
15412
15573
|
var HarnessOutputChannel = class {
|
|
15413
15574
|
outputs;
|
|
@@ -19984,8 +20145,8 @@ function classifyStartupError(error51) {
|
|
|
19984
20145
|
return new HermesTransportError("notInstalled", error51.message, { cause: error51 });
|
|
19985
20146
|
}
|
|
19986
20147
|
const detail = errorDetails2(error51);
|
|
19987
|
-
const
|
|
19988
|
-
if (
|
|
20148
|
+
const text2 = detail.toLowerCase();
|
|
20149
|
+
if (text2.includes("auth_required") || text2.includes("authentication") || text2.includes("not configured") || text2.includes("no provider") || text2.includes("no llm provider")) {
|
|
19989
20150
|
return new HermesTransportError("authenticationRequired", detail, {
|
|
19990
20151
|
cause: error51,
|
|
19991
20152
|
diagnostic: detail
|
|
@@ -20065,6 +20226,10 @@ var HermesAcpTransport = class {
|
|
|
20065
20226
|
#replay = null;
|
|
20066
20227
|
#sessionId = null;
|
|
20067
20228
|
#stderrTail = "";
|
|
20229
|
+
#availableCommands = [];
|
|
20230
|
+
get availableCommands() {
|
|
20231
|
+
return this.#availableCommands;
|
|
20232
|
+
}
|
|
20068
20233
|
/** Late binding: the Session registers its fault consumer on construction. */
|
|
20069
20234
|
onFault = () => void 0;
|
|
20070
20235
|
constructor(options) {
|
|
@@ -20203,7 +20368,7 @@ var HermesAcpTransport = class {
|
|
|
20203
20368
|
throw classifyStartupError(error51);
|
|
20204
20369
|
}
|
|
20205
20370
|
}
|
|
20206
|
-
async runTurn(
|
|
20371
|
+
async runTurn(text2, onEvent, onPermission) {
|
|
20207
20372
|
const connection = this.#connection;
|
|
20208
20373
|
if (!connection || !this.#sessionId || this.#closed || this.#closing) {
|
|
20209
20374
|
throw new HermesTransportError("unavailable", "Hermes ACP Session is unavailable");
|
|
@@ -20215,7 +20380,7 @@ var HermesAcpTransport = class {
|
|
|
20215
20380
|
try {
|
|
20216
20381
|
return await connection.prompt({
|
|
20217
20382
|
sessionId: this.#sessionId,
|
|
20218
|
-
prompt: [{ type: "text", text }]
|
|
20383
|
+
prompt: [{ type: "text", text: text2 }]
|
|
20219
20384
|
});
|
|
20220
20385
|
} finally {
|
|
20221
20386
|
if (this.#activePrompt === active)
|
|
@@ -20254,6 +20419,10 @@ var HermesAcpTransport = class {
|
|
|
20254
20419
|
#handleUpdate(notification) {
|
|
20255
20420
|
if (this.#sessionId && notification.sessionId !== this.#sessionId)
|
|
20256
20421
|
return;
|
|
20422
|
+
if (notification.update.sessionUpdate === "available_commands_update") {
|
|
20423
|
+
this.#availableCommands = notification.update.availableCommands;
|
|
20424
|
+
return;
|
|
20425
|
+
}
|
|
20257
20426
|
const event = transportEvent(notification.update);
|
|
20258
20427
|
if (!event)
|
|
20259
20428
|
return;
|
|
@@ -20316,9 +20485,6 @@ var HermesAcpTransport = class {
|
|
|
20316
20485
|
clientCapabilities: {},
|
|
20317
20486
|
clientInfo: { name: "codexhost", version: "0.1.0" }
|
|
20318
20487
|
}), this.#options.commandTimeoutMs, "Hermes ACP initialize");
|
|
20319
|
-
if (initialize.protocolVersion !== PROTOCOL_VERSION) {
|
|
20320
|
-
throw new HermesTransportError("protocolError", `Hermes ACP negotiated unsupported protocol version ${initialize.protocolVersion}`);
|
|
20321
|
-
}
|
|
20322
20488
|
this.#initialize = initialize;
|
|
20323
20489
|
return initialize;
|
|
20324
20490
|
}
|
|
@@ -20457,8 +20623,28 @@ for row in payload.get("providers") or []:
|
|
|
20457
20623
|
)
|
|
20458
20624
|
if slug and model_id:
|
|
20459
20625
|
available = slug.lower() != "moa" or bool(moa_availability.get(model_id, False))
|
|
20626
|
+
aliases = [
|
|
20627
|
+
alias.strip()
|
|
20628
|
+
for alias in row.get("aliases") or []
|
|
20629
|
+
if isinstance(alias, str) and alias.strip()
|
|
20630
|
+
]
|
|
20631
|
+
# Hermes names configured custom endpoints as custom:<key>.
|
|
20632
|
+
# The inventory row slug is the bare config key (pi-openai),
|
|
20633
|
+
# which is useful for display but is not a valid native model route.
|
|
20634
|
+
# Prefer the native custom identity for the actual model ref and
|
|
20635
|
+
# retain the bare slug as an alias for matching older snapshots.
|
|
20636
|
+
native_slug = next(
|
|
20637
|
+
(alias for alias in aliases if alias.lower().startswith("custom:")),
|
|
20638
|
+
slug,
|
|
20639
|
+
)
|
|
20640
|
+
native_model_id = native_slug + ":" + model_id
|
|
20460
20641
|
rows.append({
|
|
20461
|
-
"modelId":
|
|
20642
|
+
"modelId": native_model_id,
|
|
20643
|
+
"modelIdAliases": [
|
|
20644
|
+
alias + ":" + model_id
|
|
20645
|
+
for alias in aliases
|
|
20646
|
+
if alias + ":" + model_id != native_model_id
|
|
20647
|
+
],
|
|
20462
20648
|
"label": model_id,
|
|
20463
20649
|
"provider": provider,
|
|
20464
20650
|
"available": available,
|
|
@@ -20470,6 +20656,11 @@ print(json.dumps({"models": rows, "currentModelId": current_model_id}))
|
|
|
20470
20656
|
`;
|
|
20471
20657
|
var HermesInventoryError = class extends Error {
|
|
20472
20658
|
};
|
|
20659
|
+
var HermesInventoryTimeoutError = class extends HermesInventoryError {
|
|
20660
|
+
constructor() {
|
|
20661
|
+
super("Hermes model inventory probe timed out");
|
|
20662
|
+
}
|
|
20663
|
+
};
|
|
20473
20664
|
async function venvPythonFromShim(hermesExecutable, platform = process.platform) {
|
|
20474
20665
|
try {
|
|
20475
20666
|
const shim = await readFile(hermesExecutable, "utf8");
|
|
@@ -20508,7 +20699,7 @@ function runProbe(pythonExecutable, timeoutMs, environment) {
|
|
|
20508
20699
|
let stderr = "";
|
|
20509
20700
|
const timer = setTimeout(() => {
|
|
20510
20701
|
child.kill("SIGKILL");
|
|
20511
|
-
reject(new
|
|
20702
|
+
reject(new HermesInventoryTimeoutError());
|
|
20512
20703
|
}, timeoutMs);
|
|
20513
20704
|
child.stdout.on("data", (chunk) => {
|
|
20514
20705
|
stdout += chunk.toString("utf8");
|
|
@@ -20527,11 +20718,11 @@ function runProbe(pythonExecutable, timeoutMs, environment) {
|
|
|
20527
20718
|
return;
|
|
20528
20719
|
}
|
|
20529
20720
|
try {
|
|
20530
|
-
const
|
|
20531
|
-
const models = (
|
|
20721
|
+
const parsed2 = JSON.parse(stdout.trim());
|
|
20722
|
+
const models = (parsed2.models ?? []).filter((model) => typeof model?.modelId === "string" && model.modelId.length > 0);
|
|
20532
20723
|
resolve({
|
|
20533
20724
|
models,
|
|
20534
|
-
currentModelId: typeof
|
|
20725
|
+
currentModelId: typeof parsed2.currentModelId === "string" && parsed2.currentModelId.length > 0 ? parsed2.currentModelId : null
|
|
20535
20726
|
});
|
|
20536
20727
|
} catch {
|
|
20537
20728
|
reject(new HermesInventoryError("Hermes inventory probe returned malformed output"));
|
|
@@ -20565,10 +20756,11 @@ function catalogModelsFromInventory(inventory) {
|
|
|
20565
20756
|
for (const model of inventory.models) {
|
|
20566
20757
|
if (model.available === false)
|
|
20567
20758
|
continue;
|
|
20568
|
-
const
|
|
20759
|
+
const nativeModelId = model.modelIdAliases?.find((alias) => alias.toLowerCase().startsWith("custom:")) ?? model.modelId;
|
|
20760
|
+
const ref = encodeHermesModelRef(nativeModelId);
|
|
20569
20761
|
if (!ref)
|
|
20570
20762
|
continue;
|
|
20571
|
-
if (inventory.currentModelId && model.modelId === inventory.currentModelId) {
|
|
20763
|
+
if (inventory.currentModelId && (model.modelId === inventory.currentModelId || nativeModelId === inventory.currentModelId || model.modelIdAliases?.includes(inventory.currentModelId))) {
|
|
20572
20764
|
defaultModel = ref;
|
|
20573
20765
|
}
|
|
20574
20766
|
models.push({
|
|
@@ -20628,7 +20820,558 @@ async function resolveHermesSessionCandidate(input) {
|
|
|
20628
20820
|
}
|
|
20629
20821
|
|
|
20630
20822
|
// dist/hermes-session.js
|
|
20823
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20824
|
+
|
|
20825
|
+
// dist/hermes-questions.js
|
|
20631
20826
|
import { randomUUID } from "node:crypto";
|
|
20827
|
+
var HermesQuestions = class {
|
|
20828
|
+
emit;
|
|
20829
|
+
#waiters = /* @__PURE__ */ new Map();
|
|
20830
|
+
constructor(emit) {
|
|
20831
|
+
this.emit = emit;
|
|
20832
|
+
}
|
|
20833
|
+
open(turnId, request) {
|
|
20834
|
+
const interactionId = hostInteractionIdSchema.parse(randomUUID());
|
|
20835
|
+
const interaction = {
|
|
20836
|
+
type: "question",
|
|
20837
|
+
interactionId,
|
|
20838
|
+
turnId,
|
|
20839
|
+
questions: request.questions,
|
|
20840
|
+
...request.title ? { title: request.title } : {}
|
|
20841
|
+
};
|
|
20842
|
+
const pending = new Promise((resolve) => this.#waiters.set(interactionId, { interaction, resolve }));
|
|
20843
|
+
const abort = () => this.#cancel(interactionId, request.signal?.reason === "expired" ? "expired" : "cancelled");
|
|
20844
|
+
request.signal?.addEventListener("abort", abort, { once: true });
|
|
20845
|
+
this.emit({ kind: "interaction", interaction });
|
|
20846
|
+
if (request.signal?.aborted)
|
|
20847
|
+
abort();
|
|
20848
|
+
return pending.finally(() => request.signal?.removeEventListener("abort", abort));
|
|
20849
|
+
}
|
|
20850
|
+
respond(command) {
|
|
20851
|
+
const waiter = this.#waiters.get(command.interactionId);
|
|
20852
|
+
if (!waiter || command.response.type !== "question")
|
|
20853
|
+
return {
|
|
20854
|
+
ok: false,
|
|
20855
|
+
error: { code: "invalidRequest", message: "No pending Hermes question", retryable: false }
|
|
20856
|
+
};
|
|
20857
|
+
const error51 = validateHostQuestionResponse(waiter.interaction, command.response);
|
|
20858
|
+
if (error51)
|
|
20859
|
+
return { ok: false, error: { ...error51, retryable: false } };
|
|
20860
|
+
this.#waiters.delete(command.interactionId);
|
|
20861
|
+
waiter.resolve(command.response);
|
|
20862
|
+
this.emit({
|
|
20863
|
+
kind: "event",
|
|
20864
|
+
event: {
|
|
20865
|
+
type: "interaction.closed",
|
|
20866
|
+
interactionId: command.interactionId,
|
|
20867
|
+
turnId: waiter.interaction.turnId,
|
|
20868
|
+
reason: command.response.cancelled ? "cancelled" : "responded"
|
|
20869
|
+
}
|
|
20870
|
+
});
|
|
20871
|
+
return { ok: true, value: { accepted: true } };
|
|
20872
|
+
}
|
|
20873
|
+
cancel(turnId) {
|
|
20874
|
+
for (const [id, waiter] of this.#waiters)
|
|
20875
|
+
if (!turnId || waiter.interaction.turnId === turnId)
|
|
20876
|
+
this.#cancel(id, "cancelled");
|
|
20877
|
+
}
|
|
20878
|
+
#cancel(id, reason) {
|
|
20879
|
+
const waiter = this.#waiters.get(id);
|
|
20880
|
+
if (!waiter)
|
|
20881
|
+
return;
|
|
20882
|
+
this.#waiters.delete(id);
|
|
20883
|
+
waiter.resolve({ type: "question", answers: {}, cancelled: true });
|
|
20884
|
+
this.emit({
|
|
20885
|
+
kind: "event",
|
|
20886
|
+
event: {
|
|
20887
|
+
type: "interaction.closed",
|
|
20888
|
+
interactionId: waiter.interaction.interactionId,
|
|
20889
|
+
turnId: waiter.interaction.turnId,
|
|
20890
|
+
reason
|
|
20891
|
+
}
|
|
20892
|
+
});
|
|
20893
|
+
}
|
|
20894
|
+
};
|
|
20895
|
+
|
|
20896
|
+
// ../../../node_modules/diff/libesm/diff/base.js
|
|
20897
|
+
var Diff = class {
|
|
20898
|
+
diff(oldStr, newStr, options = {}) {
|
|
20899
|
+
let callback;
|
|
20900
|
+
if (typeof options === "function") {
|
|
20901
|
+
callback = options;
|
|
20902
|
+
options = {};
|
|
20903
|
+
} else if ("callback" in options) {
|
|
20904
|
+
callback = options.callback;
|
|
20905
|
+
}
|
|
20906
|
+
const oldString = this.castInput(oldStr, options);
|
|
20907
|
+
const newString = this.castInput(newStr, options);
|
|
20908
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
20909
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
20910
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
20911
|
+
}
|
|
20912
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
20913
|
+
var _a3;
|
|
20914
|
+
const done = (value) => {
|
|
20915
|
+
value = this.postProcess(value, options);
|
|
20916
|
+
if (callback) {
|
|
20917
|
+
setTimeout(function() {
|
|
20918
|
+
callback(value);
|
|
20919
|
+
}, 0);
|
|
20920
|
+
return void 0;
|
|
20921
|
+
} else {
|
|
20922
|
+
return value;
|
|
20923
|
+
}
|
|
20924
|
+
};
|
|
20925
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
20926
|
+
let editLength = 1;
|
|
20927
|
+
let maxEditLength = newLen + oldLen;
|
|
20928
|
+
if (options.maxEditLength != null) {
|
|
20929
|
+
maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
20930
|
+
}
|
|
20931
|
+
const maxExecutionTime = (_a3 = options.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
|
|
20932
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
20933
|
+
const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
|
|
20934
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
20935
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
20936
|
+
return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
20937
|
+
}
|
|
20938
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
20939
|
+
const execEditLength = () => {
|
|
20940
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
20941
|
+
let basePath;
|
|
20942
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
20943
|
+
if (removePath) {
|
|
20944
|
+
bestPath[diagonalPath - 1] = void 0;
|
|
20945
|
+
}
|
|
20946
|
+
let canAdd = false;
|
|
20947
|
+
if (addPath) {
|
|
20948
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
20949
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
20950
|
+
}
|
|
20951
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
20952
|
+
if (!canAdd && !canRemove) {
|
|
20953
|
+
bestPath[diagonalPath] = void 0;
|
|
20954
|
+
continue;
|
|
20955
|
+
}
|
|
20956
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
|
|
20957
|
+
basePath = this.addToPath(addPath, true, false, 0, options);
|
|
20958
|
+
} else {
|
|
20959
|
+
basePath = this.addToPath(removePath, false, true, 1, options);
|
|
20960
|
+
}
|
|
20961
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
20962
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
20963
|
+
return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
20964
|
+
} else {
|
|
20965
|
+
bestPath[diagonalPath] = basePath;
|
|
20966
|
+
if (basePath.oldPos + 1 >= oldLen) {
|
|
20967
|
+
maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
20968
|
+
}
|
|
20969
|
+
if (newPos + 1 >= newLen) {
|
|
20970
|
+
minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
20971
|
+
}
|
|
20972
|
+
}
|
|
20973
|
+
}
|
|
20974
|
+
editLength++;
|
|
20975
|
+
};
|
|
20976
|
+
if (callback) {
|
|
20977
|
+
(function exec() {
|
|
20978
|
+
setTimeout(function() {
|
|
20979
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
20980
|
+
return callback(void 0);
|
|
20981
|
+
}
|
|
20982
|
+
if (!execEditLength()) {
|
|
20983
|
+
exec();
|
|
20984
|
+
}
|
|
20985
|
+
}, 0);
|
|
20986
|
+
})();
|
|
20987
|
+
} else {
|
|
20988
|
+
while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
20989
|
+
const ret = execEditLength();
|
|
20990
|
+
if (ret) {
|
|
20991
|
+
return ret;
|
|
20992
|
+
}
|
|
20993
|
+
}
|
|
20994
|
+
}
|
|
20995
|
+
}
|
|
20996
|
+
addToPath(path7, added, removed, oldPosInc, options) {
|
|
20997
|
+
const last = path7.lastComponent;
|
|
20998
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
20999
|
+
return {
|
|
21000
|
+
oldPos: path7.oldPos + oldPosInc,
|
|
21001
|
+
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
21002
|
+
};
|
|
21003
|
+
} else {
|
|
21004
|
+
return {
|
|
21005
|
+
oldPos: path7.oldPos + oldPosInc,
|
|
21006
|
+
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
21007
|
+
};
|
|
21008
|
+
}
|
|
21009
|
+
}
|
|
21010
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
21011
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
21012
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
21013
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
21014
|
+
newPos++;
|
|
21015
|
+
oldPos++;
|
|
21016
|
+
commonCount++;
|
|
21017
|
+
if (options.oneChangePerToken) {
|
|
21018
|
+
basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
21019
|
+
}
|
|
21020
|
+
}
|
|
21021
|
+
if (commonCount && !options.oneChangePerToken) {
|
|
21022
|
+
basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
21023
|
+
}
|
|
21024
|
+
basePath.oldPos = oldPos;
|
|
21025
|
+
return newPos;
|
|
21026
|
+
}
|
|
21027
|
+
equals(left, right, options) {
|
|
21028
|
+
if (options.comparator) {
|
|
21029
|
+
return options.comparator(left, right);
|
|
21030
|
+
} else {
|
|
21031
|
+
return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
21032
|
+
}
|
|
21033
|
+
}
|
|
21034
|
+
removeEmpty(array2) {
|
|
21035
|
+
const ret = [];
|
|
21036
|
+
for (let i = 0; i < array2.length; i++) {
|
|
21037
|
+
if (array2[i]) {
|
|
21038
|
+
ret.push(array2[i]);
|
|
21039
|
+
}
|
|
21040
|
+
}
|
|
21041
|
+
return ret;
|
|
21042
|
+
}
|
|
21043
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21044
|
+
castInput(value, options) {
|
|
21045
|
+
return value;
|
|
21046
|
+
}
|
|
21047
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21048
|
+
tokenize(value, options) {
|
|
21049
|
+
return Array.from(value);
|
|
21050
|
+
}
|
|
21051
|
+
join(chars) {
|
|
21052
|
+
return chars.join("");
|
|
21053
|
+
}
|
|
21054
|
+
postProcess(changeObjects, options) {
|
|
21055
|
+
return changeObjects;
|
|
21056
|
+
}
|
|
21057
|
+
get useLongestToken() {
|
|
21058
|
+
return false;
|
|
21059
|
+
}
|
|
21060
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
21061
|
+
const components = [];
|
|
21062
|
+
let nextComponent;
|
|
21063
|
+
while (lastComponent) {
|
|
21064
|
+
components.push(lastComponent);
|
|
21065
|
+
nextComponent = lastComponent.previousComponent;
|
|
21066
|
+
delete lastComponent.previousComponent;
|
|
21067
|
+
lastComponent = nextComponent;
|
|
21068
|
+
}
|
|
21069
|
+
components.reverse();
|
|
21070
|
+
const componentLen = components.length;
|
|
21071
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
21072
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
21073
|
+
const component = components[componentPos];
|
|
21074
|
+
if (!component.removed) {
|
|
21075
|
+
if (!component.added && this.useLongestToken) {
|
|
21076
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
21077
|
+
value = value.map(function(value2, i) {
|
|
21078
|
+
const oldValue = oldTokens[oldPos + i];
|
|
21079
|
+
return oldValue.length > value2.length ? oldValue : value2;
|
|
21080
|
+
});
|
|
21081
|
+
component.value = this.join(value);
|
|
21082
|
+
} else {
|
|
21083
|
+
component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
21084
|
+
}
|
|
21085
|
+
newPos += component.count;
|
|
21086
|
+
if (!component.added) {
|
|
21087
|
+
oldPos += component.count;
|
|
21088
|
+
}
|
|
21089
|
+
} else {
|
|
21090
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
21091
|
+
oldPos += component.count;
|
|
21092
|
+
}
|
|
21093
|
+
}
|
|
21094
|
+
return components;
|
|
21095
|
+
}
|
|
21096
|
+
};
|
|
21097
|
+
|
|
21098
|
+
// ../../../node_modules/diff/libesm/diff/line.js
|
|
21099
|
+
var LineDiff = class extends Diff {
|
|
21100
|
+
constructor() {
|
|
21101
|
+
super(...arguments);
|
|
21102
|
+
this.tokenize = tokenize;
|
|
21103
|
+
}
|
|
21104
|
+
equals(left, right, options) {
|
|
21105
|
+
if (options.ignoreWhitespace) {
|
|
21106
|
+
if (!options.newlineIsToken || !left.includes("\n")) {
|
|
21107
|
+
left = left.trim();
|
|
21108
|
+
}
|
|
21109
|
+
if (!options.newlineIsToken || !right.includes("\n")) {
|
|
21110
|
+
right = right.trim();
|
|
21111
|
+
}
|
|
21112
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
21113
|
+
if (left.endsWith("\n")) {
|
|
21114
|
+
left = left.slice(0, -1);
|
|
21115
|
+
}
|
|
21116
|
+
if (right.endsWith("\n")) {
|
|
21117
|
+
right = right.slice(0, -1);
|
|
21118
|
+
}
|
|
21119
|
+
}
|
|
21120
|
+
return super.equals(left, right, options);
|
|
21121
|
+
}
|
|
21122
|
+
};
|
|
21123
|
+
var lineDiff = new LineDiff();
|
|
21124
|
+
function diffLines(oldStr, newStr, options) {
|
|
21125
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
21126
|
+
}
|
|
21127
|
+
function tokenize(value, options) {
|
|
21128
|
+
if (options.stripTrailingCr) {
|
|
21129
|
+
value = value.replace(/\r\n/g, "\n");
|
|
21130
|
+
}
|
|
21131
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
21132
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) {
|
|
21133
|
+
linesAndNewlines.pop();
|
|
21134
|
+
}
|
|
21135
|
+
for (let i = 0; i < linesAndNewlines.length; i++) {
|
|
21136
|
+
const line = linesAndNewlines[i];
|
|
21137
|
+
if (i % 2 && !options.newlineIsToken) {
|
|
21138
|
+
retLines[retLines.length - 1] += line;
|
|
21139
|
+
} else {
|
|
21140
|
+
retLines.push(line);
|
|
21141
|
+
}
|
|
21142
|
+
}
|
|
21143
|
+
return retLines;
|
|
21144
|
+
}
|
|
21145
|
+
|
|
21146
|
+
// ../../../node_modules/diff/libesm/patch/create.js
|
|
21147
|
+
function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
21148
|
+
let optionsObj;
|
|
21149
|
+
if (!options) {
|
|
21150
|
+
optionsObj = {};
|
|
21151
|
+
} else if (typeof options === "function") {
|
|
21152
|
+
optionsObj = { callback: options };
|
|
21153
|
+
} else {
|
|
21154
|
+
optionsObj = options;
|
|
21155
|
+
}
|
|
21156
|
+
if (typeof optionsObj.context === "undefined") {
|
|
21157
|
+
optionsObj.context = 4;
|
|
21158
|
+
}
|
|
21159
|
+
const context = optionsObj.context;
|
|
21160
|
+
if (optionsObj.newlineIsToken) {
|
|
21161
|
+
throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
|
|
21162
|
+
}
|
|
21163
|
+
if (!optionsObj.callback) {
|
|
21164
|
+
return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
|
|
21165
|
+
} else {
|
|
21166
|
+
const { callback } = optionsObj;
|
|
21167
|
+
diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
|
|
21168
|
+
const patch = diffLinesResultToPatch(diff);
|
|
21169
|
+
callback(patch);
|
|
21170
|
+
} }));
|
|
21171
|
+
}
|
|
21172
|
+
function diffLinesResultToPatch(diff) {
|
|
21173
|
+
if (!diff) {
|
|
21174
|
+
return;
|
|
21175
|
+
}
|
|
21176
|
+
diff.push({ value: "", lines: [] });
|
|
21177
|
+
function contextLines(lines) {
|
|
21178
|
+
return lines.map(function(entry) {
|
|
21179
|
+
return " " + entry;
|
|
21180
|
+
});
|
|
21181
|
+
}
|
|
21182
|
+
const hunks = [];
|
|
21183
|
+
let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
|
|
21184
|
+
for (let i = 0; i < diff.length; i++) {
|
|
21185
|
+
const current = diff[i], lines = current.lines || splitLines(current.value);
|
|
21186
|
+
current.lines = lines;
|
|
21187
|
+
if (current.added || current.removed) {
|
|
21188
|
+
if (!oldRangeStart) {
|
|
21189
|
+
const prev = diff[i - 1];
|
|
21190
|
+
oldRangeStart = oldLine;
|
|
21191
|
+
newRangeStart = newLine;
|
|
21192
|
+
if (prev) {
|
|
21193
|
+
curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
|
|
21194
|
+
oldRangeStart -= curRange.length;
|
|
21195
|
+
newRangeStart -= curRange.length;
|
|
21196
|
+
}
|
|
21197
|
+
}
|
|
21198
|
+
for (const line of lines) {
|
|
21199
|
+
curRange.push((current.added ? "+" : "-") + line);
|
|
21200
|
+
}
|
|
21201
|
+
if (current.added) {
|
|
21202
|
+
newLine += lines.length;
|
|
21203
|
+
} else {
|
|
21204
|
+
oldLine += lines.length;
|
|
21205
|
+
}
|
|
21206
|
+
} else {
|
|
21207
|
+
if (oldRangeStart) {
|
|
21208
|
+
if (lines.length <= context * 2 && i < diff.length - 2) {
|
|
21209
|
+
for (const line of contextLines(lines)) {
|
|
21210
|
+
curRange.push(line);
|
|
21211
|
+
}
|
|
21212
|
+
} else {
|
|
21213
|
+
const contextSize = Math.min(lines.length, context);
|
|
21214
|
+
for (const line of contextLines(lines.slice(0, contextSize))) {
|
|
21215
|
+
curRange.push(line);
|
|
21216
|
+
}
|
|
21217
|
+
const hunk = {
|
|
21218
|
+
oldStart: oldRangeStart,
|
|
21219
|
+
oldLines: oldLine - oldRangeStart + contextSize,
|
|
21220
|
+
newStart: newRangeStart,
|
|
21221
|
+
newLines: newLine - newRangeStart + contextSize,
|
|
21222
|
+
lines: curRange
|
|
21223
|
+
};
|
|
21224
|
+
hunks.push(hunk);
|
|
21225
|
+
oldRangeStart = 0;
|
|
21226
|
+
newRangeStart = 0;
|
|
21227
|
+
curRange = [];
|
|
21228
|
+
}
|
|
21229
|
+
}
|
|
21230
|
+
oldLine += lines.length;
|
|
21231
|
+
newLine += lines.length;
|
|
21232
|
+
}
|
|
21233
|
+
}
|
|
21234
|
+
for (const hunk of hunks) {
|
|
21235
|
+
for (let i = 0; i < hunk.lines.length; i++) {
|
|
21236
|
+
if (hunk.lines[i].endsWith("\n")) {
|
|
21237
|
+
hunk.lines[i] = hunk.lines[i].slice(0, -1);
|
|
21238
|
+
} else {
|
|
21239
|
+
hunk.lines.splice(i + 1, 0, "\");
|
|
21240
|
+
i++;
|
|
21241
|
+
}
|
|
21242
|
+
}
|
|
21243
|
+
}
|
|
21244
|
+
return {
|
|
21245
|
+
oldFileName,
|
|
21246
|
+
newFileName,
|
|
21247
|
+
oldHeader,
|
|
21248
|
+
newHeader,
|
|
21249
|
+
hunks
|
|
21250
|
+
};
|
|
21251
|
+
}
|
|
21252
|
+
}
|
|
21253
|
+
function formatPatch(patch) {
|
|
21254
|
+
if (Array.isArray(patch)) {
|
|
21255
|
+
return patch.map(formatPatch).join("\n");
|
|
21256
|
+
}
|
|
21257
|
+
const ret = [];
|
|
21258
|
+
if (patch.oldFileName == patch.newFileName) {
|
|
21259
|
+
ret.push("Index: " + patch.oldFileName);
|
|
21260
|
+
}
|
|
21261
|
+
ret.push("===================================================================");
|
|
21262
|
+
ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
|
|
21263
|
+
ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
|
|
21264
|
+
for (let i = 0; i < patch.hunks.length; i++) {
|
|
21265
|
+
const hunk = patch.hunks[i];
|
|
21266
|
+
if (hunk.oldLines === 0) {
|
|
21267
|
+
hunk.oldStart -= 1;
|
|
21268
|
+
}
|
|
21269
|
+
if (hunk.newLines === 0) {
|
|
21270
|
+
hunk.newStart -= 1;
|
|
21271
|
+
}
|
|
21272
|
+
ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
|
|
21273
|
+
for (const line of hunk.lines) {
|
|
21274
|
+
ret.push(line);
|
|
21275
|
+
}
|
|
21276
|
+
}
|
|
21277
|
+
return ret.join("\n") + "\n";
|
|
21278
|
+
}
|
|
21279
|
+
function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
|
|
21280
|
+
if (typeof options === "function") {
|
|
21281
|
+
options = { callback: options };
|
|
21282
|
+
}
|
|
21283
|
+
if (!(options === null || options === void 0 ? void 0 : options.callback)) {
|
|
21284
|
+
const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
|
|
21285
|
+
if (!patchObj) {
|
|
21286
|
+
return;
|
|
21287
|
+
}
|
|
21288
|
+
return formatPatch(patchObj);
|
|
21289
|
+
} else {
|
|
21290
|
+
const { callback } = options;
|
|
21291
|
+
structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
|
|
21292
|
+
if (!patchObj) {
|
|
21293
|
+
callback(void 0);
|
|
21294
|
+
} else {
|
|
21295
|
+
callback(formatPatch(patchObj));
|
|
21296
|
+
}
|
|
21297
|
+
} }));
|
|
21298
|
+
}
|
|
21299
|
+
}
|
|
21300
|
+
function splitLines(text2) {
|
|
21301
|
+
const hasTrailingNl = text2.endsWith("\n");
|
|
21302
|
+
const result = text2.split("\n").map((line) => line + "\n");
|
|
21303
|
+
if (hasTrailingNl) {
|
|
21304
|
+
result.pop();
|
|
21305
|
+
} else {
|
|
21306
|
+
result.push(result.pop().slice(0, -1));
|
|
21307
|
+
}
|
|
21308
|
+
return result;
|
|
21309
|
+
}
|
|
21310
|
+
|
|
21311
|
+
// dist/hermes-file-changes.js
|
|
21312
|
+
var MAX_DIFF_BYTES = 1024 * 1024;
|
|
21313
|
+
var MAX_DIFFS = 32;
|
|
21314
|
+
function hermesFileChanges(update) {
|
|
21315
|
+
const changes = [];
|
|
21316
|
+
let bytes = 0;
|
|
21317
|
+
for (const block of update.content ?? []) {
|
|
21318
|
+
if (block.type !== "diff")
|
|
21319
|
+
continue;
|
|
21320
|
+
const { path: path7, oldText, newText } = block;
|
|
21321
|
+
if (!path7.trim() || /[\0\r\n]/u.test(path7) || typeof newText !== "string")
|
|
21322
|
+
continue;
|
|
21323
|
+
if (oldText === newText)
|
|
21324
|
+
continue;
|
|
21325
|
+
bytes += Buffer.byteLength(oldText ?? "") + Buffer.byteLength(newText);
|
|
21326
|
+
if (bytes > MAX_DIFF_BYTES || changes.length === MAX_DIFFS)
|
|
21327
|
+
return [];
|
|
21328
|
+
changes.push({
|
|
21329
|
+
path: path7,
|
|
21330
|
+
kind: "update",
|
|
21331
|
+
diffScope: "fragment",
|
|
21332
|
+
unifiedDiff: createTwoFilesPatch(path7, path7, oldText ?? "", newText, "", "", {
|
|
21333
|
+
context: 3
|
|
21334
|
+
})
|
|
21335
|
+
});
|
|
21336
|
+
}
|
|
21337
|
+
return changes;
|
|
21338
|
+
}
|
|
21339
|
+
function hermesToolOutput(update) {
|
|
21340
|
+
const content = [];
|
|
21341
|
+
for (const block of update.content ?? []) {
|
|
21342
|
+
if (block.type !== "content")
|
|
21343
|
+
continue;
|
|
21344
|
+
if (block.content.type === "text" && block.content.text) {
|
|
21345
|
+
content.push({ type: "text", text: block.content.text });
|
|
21346
|
+
} else if (block.content.type === "image") {
|
|
21347
|
+
content.push({
|
|
21348
|
+
type: "image",
|
|
21349
|
+
mimeType: block.content.mimeType,
|
|
21350
|
+
base64Data: block.content.data
|
|
21351
|
+
});
|
|
21352
|
+
}
|
|
21353
|
+
}
|
|
21354
|
+
if (!content.length && typeof update.rawOutput === "string" && update.rawOutput) {
|
|
21355
|
+
content.push({ type: "text", text: update.rawOutput });
|
|
21356
|
+
}
|
|
21357
|
+
return content.length ? { content } : null;
|
|
21358
|
+
}
|
|
21359
|
+
|
|
21360
|
+
// dist/hermes-compaction.js
|
|
21361
|
+
function hermesCompactionOutcome(outcome, nativeText) {
|
|
21362
|
+
if (outcome.status !== "succeeded")
|
|
21363
|
+
return outcome;
|
|
21364
|
+
const text2 = nativeText.trim();
|
|
21365
|
+
if (/^Context compressed: \d+ -> \d+ messages\n~[\d,]+ -> ~[\d,]+ tokens$/u.test(text2)) {
|
|
21366
|
+
return { status: "succeeded" };
|
|
21367
|
+
}
|
|
21368
|
+
if (/^(?:Compression failed:|Error executing \/compress:|Context compression not available)/u.test(text2)) {
|
|
21369
|
+
return { status: "failed", error: { code: "nativeFailure", message: text2, retryable: false } };
|
|
21370
|
+
}
|
|
21371
|
+
return { status: "cancelled", reason: text2 || "Hermes did not confirm context compression" };
|
|
21372
|
+
}
|
|
21373
|
+
|
|
21374
|
+
// dist/hermes-session.js
|
|
20632
21375
|
var HOST_ERROR_CODES = {
|
|
20633
21376
|
notInstalled: "notInstalled",
|
|
20634
21377
|
authenticationRequired: "authenticationRequired",
|
|
@@ -20671,7 +21414,7 @@ function usageFromContext(used, size) {
|
|
|
20671
21414
|
...used !== void 0 ? { contextUsedTokens: used } : {}
|
|
20672
21415
|
};
|
|
20673
21416
|
}
|
|
20674
|
-
function projectPermissionOptions(options) {
|
|
21417
|
+
function projectPermissionOptions(options, effects) {
|
|
20675
21418
|
const actionEffects = {
|
|
20676
21419
|
allow_once: "allowOnce",
|
|
20677
21420
|
allow_always: "allowAlways",
|
|
@@ -20687,7 +21430,7 @@ function projectPermissionOptions(options) {
|
|
|
20687
21430
|
const actions = [];
|
|
20688
21431
|
const optionIdByAction = /* @__PURE__ */ new Map();
|
|
20689
21432
|
for (const option of options) {
|
|
20690
|
-
const effect = actionEffects[option.kind];
|
|
21433
|
+
const effect = effects?.[option.optionId] ?? actionEffects[option.kind];
|
|
20691
21434
|
if (!effect)
|
|
20692
21435
|
continue;
|
|
20693
21436
|
actions.push({
|
|
@@ -20703,18 +21446,47 @@ var ActiveTurn = class {
|
|
|
20703
21446
|
turnId;
|
|
20704
21447
|
turnKey;
|
|
20705
21448
|
input;
|
|
21449
|
+
persistsHistory;
|
|
21450
|
+
compactionItem;
|
|
21451
|
+
compactionText = "";
|
|
21452
|
+
nativeCompactionOutcome;
|
|
21453
|
+
nativeTurnSnapshot;
|
|
20706
21454
|
#currentText = null;
|
|
20707
21455
|
#toolItems = /* @__PURE__ */ new Map();
|
|
20708
21456
|
#finishedItems = [];
|
|
21457
|
+
#toolChanges = /* @__PURE__ */ new Map();
|
|
20709
21458
|
#emittedTerminalItemIds = /* @__PURE__ */ new Set();
|
|
20710
|
-
|
|
21459
|
+
rememberFileChanges(toolCallId, update) {
|
|
21460
|
+
const changes = hermesFileChanges(update);
|
|
21461
|
+
if (update.content?.some((block) => block.type === "diff"))
|
|
21462
|
+
this.#toolChanges.set(toolCallId, changes);
|
|
21463
|
+
}
|
|
21464
|
+
completeFileChanges(toolCallId, sourceItemId) {
|
|
21465
|
+
const changes = this.#toolChanges.get(toolCallId);
|
|
21466
|
+
this.#toolChanges.delete(toolCallId);
|
|
21467
|
+
if (!changes?.length)
|
|
21468
|
+
return null;
|
|
21469
|
+
const item = {
|
|
21470
|
+
type: "fileChange",
|
|
21471
|
+
itemId: hostItemIdSchema.parse(randomUUID2()),
|
|
21472
|
+
changes,
|
|
21473
|
+
sourceItemIds: [sourceItemId]
|
|
21474
|
+
};
|
|
21475
|
+
const snapshot = { item, outcome: { status: "succeeded" } };
|
|
21476
|
+
this.#finishedItems.push(snapshot);
|
|
21477
|
+
this.#emittedTerminalItemIds.add(item.itemId);
|
|
21478
|
+
return snapshot;
|
|
21479
|
+
}
|
|
21480
|
+
constructor(turnId, turnKey, input, persistsHistory, compaction) {
|
|
20711
21481
|
this.turnId = hostTurnIdSchema.parse(turnId);
|
|
20712
21482
|
this.turnKey = turnKey;
|
|
20713
21483
|
this.input = input;
|
|
21484
|
+
this.persistsHistory = persistsHistory;
|
|
21485
|
+
this.compactionItem = compaction ? { type: "contextCompaction", itemId: hostItemIdSchema.parse(randomUUID2()) } : null;
|
|
20714
21486
|
}
|
|
20715
|
-
appendText(kind,
|
|
21487
|
+
appendText(kind, text2) {
|
|
20716
21488
|
if (this.#currentText && this.#currentText.kind === kind) {
|
|
20717
|
-
const item2 = { ...this.#currentText.item, text: this.#currentText.item.text +
|
|
21489
|
+
const item2 = { ...this.#currentText.item, text: this.#currentText.item.text + text2 };
|
|
20718
21490
|
this.#currentText = { kind, item: item2 };
|
|
20719
21491
|
return { startedItem: null, item: item2 };
|
|
20720
21492
|
}
|
|
@@ -20724,8 +21496,8 @@ var ActiveTurn = class {
|
|
|
20724
21496
|
outcome: { status: "succeeded" }
|
|
20725
21497
|
});
|
|
20726
21498
|
}
|
|
20727
|
-
const item = kind === "reasoning" ? { type: "reasoning", itemId: hostItemIdSchema.parse(
|
|
20728
|
-
const appended = { ...item, text };
|
|
21499
|
+
const item = kind === "reasoning" ? { type: "reasoning", itemId: hostItemIdSchema.parse(randomUUID2()), text: "" } : { type: "agentMessage", itemId: hostItemIdSchema.parse(randomUUID2()), text: "" };
|
|
21500
|
+
const appended = { ...item, text: text2 };
|
|
20729
21501
|
this.#currentText = { kind, item: appended };
|
|
20730
21502
|
return { startedItem: item, item: appended };
|
|
20731
21503
|
}
|
|
@@ -20783,6 +21555,13 @@ var ActiveTurn = class {
|
|
|
20783
21555
|
}
|
|
20784
21556
|
this.#toolItems.clear();
|
|
20785
21557
|
}
|
|
21558
|
+
finishCompaction(outcome) {
|
|
21559
|
+
if (!this.compactionItem)
|
|
21560
|
+
return null;
|
|
21561
|
+
const itemOutcome = outcome.status === "succeeded" && this.nativeCompactionOutcome ? this.nativeCompactionOutcome : hermesCompactionOutcome(outcome, this.compactionText);
|
|
21562
|
+
this.#finishedItems.push({ item: this.compactionItem, outcome: itemOutcome });
|
|
21563
|
+
return itemOutcome;
|
|
21564
|
+
}
|
|
20786
21565
|
drainPendingItems() {
|
|
20787
21566
|
const pending = this.#finishedItems.filter((snapshot) => !this.#emittedTerminalItemIds.has(snapshot.item.itemId));
|
|
20788
21567
|
this.#finishedItems = [];
|
|
@@ -20801,25 +21580,30 @@ var ActiveTurn = class {
|
|
|
20801
21580
|
function isPlainObjectOrArray(value) {
|
|
20802
21581
|
return typeof value === "object" && value !== null;
|
|
20803
21582
|
}
|
|
20804
|
-
function toolOutputFromUpdate(update) {
|
|
20805
|
-
const content = [];
|
|
20806
|
-
if (Array.isArray(update.content)) {
|
|
20807
|
-
for (const block of update.content) {
|
|
20808
|
-
const candidate = block;
|
|
20809
|
-
if (candidate?.type === "text" && typeof candidate.text === "string" && candidate.text.length > 0) {
|
|
20810
|
-
content.push({ type: "text", text: candidate.text });
|
|
20811
|
-
}
|
|
20812
|
-
}
|
|
20813
|
-
}
|
|
20814
|
-
if (content.length === 0 && typeof update.rawOutput === "string" && update.rawOutput.length > 0) {
|
|
20815
|
-
content.push({ type: "text", text: update.rawOutput });
|
|
20816
|
-
}
|
|
20817
|
-
return content.length > 0 ? { content } : null;
|
|
20818
|
-
}
|
|
20819
21583
|
function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
20820
21584
|
const turns = [];
|
|
20821
21585
|
let current = null;
|
|
20822
21586
|
let toolItemIndexes = /* @__PURE__ */ new Map();
|
|
21587
|
+
const toolChanges = /* @__PURE__ */ new Map();
|
|
21588
|
+
const appendFileChanges = (toolCallId, update, sourceItemId) => {
|
|
21589
|
+
const changes = hermesFileChanges(update);
|
|
21590
|
+
if (update.content?.some((block) => block.type === "diff"))
|
|
21591
|
+
toolChanges.set(toolCallId, changes);
|
|
21592
|
+
const confirmedChanges = toolChanges.get(toolCallId);
|
|
21593
|
+
if (current && update.status === "completed" && confirmedChanges?.length) {
|
|
21594
|
+
current.items.push({
|
|
21595
|
+
item: {
|
|
21596
|
+
type: "fileChange",
|
|
21597
|
+
itemId: hostItemIdSchema.parse(randomUUID2()),
|
|
21598
|
+
changes: confirmedChanges,
|
|
21599
|
+
sourceItemIds: [sourceItemId]
|
|
21600
|
+
},
|
|
21601
|
+
outcome: { status: "succeeded" }
|
|
21602
|
+
});
|
|
21603
|
+
}
|
|
21604
|
+
if (update.status === "completed" || update.status === "failed")
|
|
21605
|
+
toolChanges.delete(toolCallId);
|
|
21606
|
+
};
|
|
20823
21607
|
const closeTurn = () => {
|
|
20824
21608
|
if (!current || current.items.length === 0) {
|
|
20825
21609
|
current = null;
|
|
@@ -20843,21 +21627,22 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
|
20843
21627
|
});
|
|
20844
21628
|
current = null;
|
|
20845
21629
|
toolItemIndexes = /* @__PURE__ */ new Map();
|
|
21630
|
+
toolChanges.clear();
|
|
20846
21631
|
};
|
|
20847
|
-
const pushText = (kind,
|
|
21632
|
+
const pushText = (kind, text2) => {
|
|
20848
21633
|
if (!current)
|
|
20849
21634
|
current = { inputText: "(resumed)", items: [], turnKey: `history-${turns.length + 1}` };
|
|
20850
21635
|
const last = current.items.at(-1);
|
|
20851
21636
|
if (last && last.item.type === kind) {
|
|
20852
21637
|
if (kind === "reasoning") {
|
|
20853
|
-
last.item.text +=
|
|
21638
|
+
last.item.text += text2;
|
|
20854
21639
|
} else {
|
|
20855
|
-
last.item.text +=
|
|
21640
|
+
last.item.text += text2;
|
|
20856
21641
|
}
|
|
20857
21642
|
return;
|
|
20858
21643
|
}
|
|
20859
21644
|
current.items.push({
|
|
20860
|
-
item: kind === "reasoning" ? { type: "reasoning", itemId: hostItemIdSchema.parse(
|
|
21645
|
+
item: kind === "reasoning" ? { type: "reasoning", itemId: hostItemIdSchema.parse(randomUUID2()), text: text2 } : { type: "agentMessage", itemId: hostItemIdSchema.parse(randomUUID2()), text: text2 },
|
|
20861
21646
|
outcome: { status: "succeeded" }
|
|
20862
21647
|
});
|
|
20863
21648
|
};
|
|
@@ -20882,12 +21667,12 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
|
20882
21667
|
if (!current)
|
|
20883
21668
|
current = { inputText: "(resumed)", items: [], turnKey: `history-${turns.length + 1}` };
|
|
20884
21669
|
const update = event.update;
|
|
20885
|
-
const output =
|
|
21670
|
+
const output = hermesToolOutput(update);
|
|
20886
21671
|
const toolName = typeof update.title === "string" && update.title.trim() || typeof update.name === "string" && update.name.trim() || event.toolCallId;
|
|
20887
21672
|
current.items.push({
|
|
20888
21673
|
item: {
|
|
20889
21674
|
type: "toolExecution",
|
|
20890
|
-
itemId: hostItemIdSchema.parse(
|
|
21675
|
+
itemId: hostItemIdSchema.parse(randomUUID2()),
|
|
20891
21676
|
toolName,
|
|
20892
21677
|
arguments: isPlainObjectOrArray(update.rawInput) ? update.rawInput : null,
|
|
20893
21678
|
...output ? { output } : {}
|
|
@@ -20898,6 +21683,9 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
|
20898
21683
|
} : { status: "cancelled", reason: "Turn ended before terminal tool update" }
|
|
20899
21684
|
});
|
|
20900
21685
|
toolItemIndexes.set(event.toolCallId, current.items.length - 1);
|
|
21686
|
+
const sourceItemId = current.items.at(-1)?.item.itemId;
|
|
21687
|
+
if (sourceItemId)
|
|
21688
|
+
appendFileChanges(event.toolCallId, update, sourceItemId);
|
|
20901
21689
|
break;
|
|
20902
21690
|
}
|
|
20903
21691
|
case "tool.update": {
|
|
@@ -20910,7 +21698,7 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
|
20910
21698
|
if (!prior || prior.item.type !== "toolExecution")
|
|
20911
21699
|
break;
|
|
20912
21700
|
const update = event.update;
|
|
20913
|
-
const output =
|
|
21701
|
+
const output = hermesToolOutput(update);
|
|
20914
21702
|
current.items[itemIndex] = {
|
|
20915
21703
|
item: { ...prior.item, ...output ? { output } : {} },
|
|
20916
21704
|
outcome: update.status === "completed" ? { status: "succeeded" } : update.status === "failed" ? {
|
|
@@ -20918,6 +21706,7 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
|
|
|
20918
21706
|
error: harnessError("nativeFailure", "Tool execution failed")
|
|
20919
21707
|
} : prior.outcome
|
|
20920
21708
|
};
|
|
21709
|
+
appendFileChanges(event.toolCallId, update, prior.item.itemId);
|
|
20921
21710
|
break;
|
|
20922
21711
|
}
|
|
20923
21712
|
default:
|
|
@@ -20956,6 +21745,7 @@ var HermesSession = class {
|
|
|
20956
21745
|
initialState;
|
|
20957
21746
|
initialUsage;
|
|
20958
21747
|
outputs;
|
|
21748
|
+
commands;
|
|
20959
21749
|
#channel = new HarnessOutputChannel();
|
|
20960
21750
|
#transport;
|
|
20961
21751
|
#nativeRef;
|
|
@@ -20969,16 +21759,37 @@ var HermesSession = class {
|
|
|
20969
21759
|
#completedTurns = [];
|
|
20970
21760
|
#historyTurns;
|
|
20971
21761
|
#latestUsage;
|
|
21762
|
+
#questions = new HermesQuestions((output) => this.#channel.emit(output));
|
|
20972
21763
|
#approvalWaiters = /* @__PURE__ */ new Map();
|
|
20973
21764
|
constructor(options) {
|
|
20974
21765
|
this.#transport = options.transport;
|
|
21766
|
+
this.capabilities.history.fork = options.supportsDerivation === true;
|
|
21767
|
+
this.capabilities.history.rollbackLastTurn = options.supportsDerivation === true;
|
|
21768
|
+
this.commands = {
|
|
21769
|
+
list: async () => this.#closed || this.#faulted ? err("invalidState", "Hermes Session is unavailable") : ok(hermesCommandCatalog(this.#transport.availableCommands ?? [])),
|
|
21770
|
+
execute: async (command) => {
|
|
21771
|
+
const text2 = hermesCommandText(command, hermesCommandCatalog(this.#transport.availableCommands ?? []));
|
|
21772
|
+
if (!text2.ok)
|
|
21773
|
+
return text2;
|
|
21774
|
+
return this.execute({
|
|
21775
|
+
type: "turn.start",
|
|
21776
|
+
turnId: command.turnId,
|
|
21777
|
+
input: [{ type: "text", text: text2.value }]
|
|
21778
|
+
});
|
|
21779
|
+
}
|
|
21780
|
+
};
|
|
20975
21781
|
this.#nativeRef = options.nativeRef;
|
|
20976
21782
|
this.#onSettle = options.onSettle;
|
|
20977
21783
|
const projected = projectHermesModelState(options.open.session.models);
|
|
20978
21784
|
const modes = options.open.session.modes;
|
|
20979
21785
|
this.#availableModels = options.open.session.models?.availableModels ?? [];
|
|
21786
|
+
this.capabilities.configuration.selectThinkingOption = !!this.#transport.setThinking;
|
|
20980
21787
|
this.#state = {
|
|
20981
21788
|
nativeRef: this.#nativeRef,
|
|
21789
|
+
...options.open.session.thinkingOptions ? { availableThinkingOptions: options.open.session.thinkingOptions } : {},
|
|
21790
|
+
...options.open.session.currentThinkingOptionId ? {
|
|
21791
|
+
effectiveThinkingOptionId: harnessThinkingOptionIdSchema.parse(options.open.session.currentThinkingOptionId)
|
|
21792
|
+
} : {},
|
|
20982
21793
|
...projected.effectiveModel ? { effectiveModel: projected.effectiveModel } : {},
|
|
20983
21794
|
...projected.resolvedModelLabel ? { resolvedModelLabel: projected.resolvedModelLabel } : {},
|
|
20984
21795
|
...modes ? { effectivePermissionModeId: harnessPermissionModeIdSchema.parse(modes.currentModeId) } : {}
|
|
@@ -20990,9 +21801,19 @@ var HermesSession = class {
|
|
|
20990
21801
|
this.outputs = this.#channel.outputs;
|
|
20991
21802
|
this.#transport.onFault = (error51) => this.#fault(transportErrorToHarness(error51));
|
|
20992
21803
|
}
|
|
21804
|
+
get busy() {
|
|
21805
|
+
return this.#activeTurn !== null;
|
|
21806
|
+
}
|
|
20993
21807
|
async readSnapshot() {
|
|
20994
21808
|
if (this.#closed)
|
|
20995
21809
|
return err("invalidState", "Hermes Session is closed");
|
|
21810
|
+
if (this.#transport.readNativeSnapshot) {
|
|
21811
|
+
try {
|
|
21812
|
+
return ok({ ...await this.#transport.readNativeSnapshot(), state: { ...this.#state } });
|
|
21813
|
+
} catch (error51) {
|
|
21814
|
+
return err("nativeFailure", error51 instanceof Error ? error51.message : String(error51));
|
|
21815
|
+
}
|
|
21816
|
+
}
|
|
20996
21817
|
return ok({
|
|
20997
21818
|
turns: [...this.#historyTurns, ...this.#completedTurns],
|
|
20998
21819
|
state: { ...this.#state }
|
|
@@ -21008,11 +21829,11 @@ var HermesSession = class {
|
|
|
21008
21829
|
case "turn.cancel":
|
|
21009
21830
|
return this.#cancelTurn(command);
|
|
21010
21831
|
case "interaction.respond":
|
|
21011
|
-
return Promise.resolve(this.#respondToApproval(command));
|
|
21832
|
+
return Promise.resolve(command.response.type === "question" ? this.#questions.respond(command) : this.#respondToApproval(command));
|
|
21012
21833
|
case "model.select":
|
|
21013
21834
|
return this.#selectModel(command);
|
|
21014
21835
|
case "thinking.select":
|
|
21015
|
-
return
|
|
21836
|
+
return this.#selectThinking(command);
|
|
21016
21837
|
case "permissionMode.select":
|
|
21017
21838
|
return this.#selectPermissionMode(command);
|
|
21018
21839
|
default: {
|
|
@@ -21026,13 +21847,14 @@ var HermesSession = class {
|
|
|
21026
21847
|
return;
|
|
21027
21848
|
this.#closed = true;
|
|
21028
21849
|
this.#cancelApprovalWaiters();
|
|
21029
|
-
this.#activeTurn
|
|
21030
|
-
|
|
21850
|
+
if (this.#activeTurn)
|
|
21851
|
+
this.#completeActiveTurn(this.#activeTurn, { status: "cancelled", reason: "Session closed" });
|
|
21031
21852
|
await this.#transport.close().catch(() => void 0);
|
|
21032
21853
|
this.#channel.end();
|
|
21033
21854
|
this.#onSettle(this);
|
|
21034
21855
|
}
|
|
21035
21856
|
#cancelApprovalWaiters() {
|
|
21857
|
+
this.#questions.cancel();
|
|
21036
21858
|
for (const [interactionId, waiter] of this.#approvalWaiters) {
|
|
21037
21859
|
waiter.resolve({ outcome: { outcome: "cancelled" } });
|
|
21038
21860
|
this.#emit({
|
|
@@ -21066,23 +21888,31 @@ var HermesSession = class {
|
|
|
21066
21888
|
if (this.#activeTurn) {
|
|
21067
21889
|
return err("sessionBusy", "Hermes Session already has an active Turn", true);
|
|
21068
21890
|
}
|
|
21069
|
-
const
|
|
21070
|
-
if (
|
|
21891
|
+
const text2 = command.input.flatMap((chunk) => chunk.type === "text" ? [chunk.text] : []).join("\n");
|
|
21892
|
+
if (text2.trim().length === 0) {
|
|
21071
21893
|
return err("invalidRequest", "turn.start requires non-empty text input");
|
|
21072
21894
|
}
|
|
21073
|
-
const turnKey =
|
|
21074
|
-
const
|
|
21895
|
+
const turnKey = randomUUID2();
|
|
21896
|
+
const firstToken = text2.trim().split(/\s/u)[0]?.replace(/^\/+/u, "").toLowerCase();
|
|
21897
|
+
const nativeCommand = this.#transport.nativeCommandName ? this.#transport.nativeCommandName(text2) : text2.trimStart().startsWith("/") && (this.#transport.availableCommands ?? []).some((entry) => entry.name === firstToken) ? firstToken : null;
|
|
21898
|
+
const isNativeCommand = nativeCommand != null;
|
|
21899
|
+
const active = new ActiveTurn(command.turnId, turnKey, command.input, !isNativeCommand, isNativeCommand && nativeCommand === "compress");
|
|
21075
21900
|
this.#activeTurn = active;
|
|
21076
21901
|
this.#activeTurnId = active.turnId;
|
|
21077
|
-
void this.#runTurn(active,
|
|
21902
|
+
void this.#runTurn(active, text2);
|
|
21078
21903
|
return ok({ turnId: active.turnId });
|
|
21079
21904
|
}
|
|
21080
|
-
async #runTurn(active,
|
|
21905
|
+
async #runTurn(active, text2) {
|
|
21081
21906
|
this.#emit({ type: "turn.started", turnId: active.turnId });
|
|
21907
|
+
if (active.compactionItem)
|
|
21908
|
+
this.#emit({ type: "item.started", turnId: active.turnId, item: active.compactionItem });
|
|
21082
21909
|
let promptResponse = null;
|
|
21083
21910
|
let failure2 = null;
|
|
21911
|
+
let previousNativeTurnKey;
|
|
21084
21912
|
try {
|
|
21085
|
-
|
|
21913
|
+
if (active.persistsHistory && this.#transport.readNativeSnapshot)
|
|
21914
|
+
previousNativeTurnKey = (await this.#transport.readNativeSnapshot()).turns.at(-1)?.nativeTurnRef.nativeTurnKey;
|
|
21915
|
+
promptResponse = await this.#transport.runTurn(text2, (event) => this.#handleTransportEvent(active, event), (request) => this.#handlePermissionRequest(active, request), (request) => this.#handleQuestionRequest(active, request));
|
|
21086
21916
|
} catch (error51) {
|
|
21087
21917
|
failure2 = error51 instanceof HermesTransportError ? transportErrorToHarness(error51) : harnessError("nativeFailure", error51 instanceof Error ? error51.message : String(error51));
|
|
21088
21918
|
}
|
|
@@ -21102,6 +21932,19 @@ var HermesSession = class {
|
|
|
21102
21932
|
} else {
|
|
21103
21933
|
outcome = { status: "succeeded" };
|
|
21104
21934
|
}
|
|
21935
|
+
active.nativeCompactionOutcome = promptResponse?.compactionOutcome;
|
|
21936
|
+
if (active.persistsHistory && this.#transport.readNativeSnapshot) {
|
|
21937
|
+
try {
|
|
21938
|
+
const latest = (await this.#transport.readNativeSnapshot()).turns.at(-1);
|
|
21939
|
+
if (latest?.nativeTurnRef.nativeTurnKey !== previousNativeTurnKey)
|
|
21940
|
+
active.nativeTurnSnapshot = latest;
|
|
21941
|
+
} catch (error51) {
|
|
21942
|
+
outcome = {
|
|
21943
|
+
status: "failed",
|
|
21944
|
+
error: harnessError("nativeFailure", error51 instanceof Error ? error51.message : String(error51))
|
|
21945
|
+
};
|
|
21946
|
+
}
|
|
21947
|
+
}
|
|
21105
21948
|
const terminalUsage = promptResponse ? usageFromPromptResponse(promptResponse.usage) : null;
|
|
21106
21949
|
const usage = terminalUsage ? this.#mergeUsage(terminalUsage) : null;
|
|
21107
21950
|
this.#completeActiveTurn(active, outcome, usage);
|
|
@@ -21109,10 +21952,17 @@ var HermesSession = class {
|
|
|
21109
21952
|
#completeActiveTurn(active, outcome, usage = null) {
|
|
21110
21953
|
if (this.#activeTurn !== active)
|
|
21111
21954
|
return;
|
|
21955
|
+
this.#cancelApprovalWaiters();
|
|
21112
21956
|
this.#activeTurn = null;
|
|
21113
21957
|
this.#activeTurnId = null;
|
|
21114
21958
|
active.finish();
|
|
21115
|
-
const
|
|
21959
|
+
const compactionOutcome = active.finishCompaction(outcome);
|
|
21960
|
+
if (outcome.status === "succeeded" && compactionOutcome?.status === "failed") {
|
|
21961
|
+
outcome = { status: "failed", error: compactionOutcome.error };
|
|
21962
|
+
}
|
|
21963
|
+
if (active.nativeTurnSnapshot?.checkpoint)
|
|
21964
|
+
outcome = { ...outcome, checkpoint: active.nativeTurnSnapshot.checkpoint };
|
|
21965
|
+
const nativeTurnRef = active.nativeTurnSnapshot?.nativeTurnRef ?? nativeTurnRefSchema.parse({
|
|
21116
21966
|
harnessId: this.#nativeRef.harnessId,
|
|
21117
21967
|
nativeSessionId: this.#nativeRef.nativeSessionId,
|
|
21118
21968
|
nativeTurnKey: active.turnKey,
|
|
@@ -21125,10 +21975,18 @@ var HermesSession = class {
|
|
|
21125
21975
|
if (usage) {
|
|
21126
21976
|
this.#emit({ type: "session.usage.changed", usage, observedForTurnId: active.turnId });
|
|
21127
21977
|
}
|
|
21128
|
-
this.#emit({
|
|
21129
|
-
|
|
21978
|
+
this.#emit({
|
|
21979
|
+
type: "turn.completed",
|
|
21980
|
+
turnId: active.turnId,
|
|
21981
|
+
...active.persistsHistory && (!this.#transport.readNativeSnapshot || active.nativeTurnSnapshot) ? { nativeTurnRef } : {},
|
|
21982
|
+
outcome
|
|
21983
|
+
});
|
|
21984
|
+
if (active.persistsHistory)
|
|
21985
|
+
this.#completedTurns.push(turnSnapshot);
|
|
21130
21986
|
}
|
|
21131
21987
|
#handleTransportEvent(active, event) {
|
|
21988
|
+
if (this.#activeTurn !== active)
|
|
21989
|
+
return;
|
|
21132
21990
|
switch (event.type) {
|
|
21133
21991
|
case "usage": {
|
|
21134
21992
|
const usage = usageFromContext(event.used, event.size);
|
|
@@ -21146,6 +22004,8 @@ var HermesSession = class {
|
|
|
21146
22004
|
this.#appendTextItem(active, "reasoning", event.text);
|
|
21147
22005
|
return;
|
|
21148
22006
|
case "agent.text":
|
|
22007
|
+
if (active.compactionItem)
|
|
22008
|
+
active.compactionText += event.text;
|
|
21149
22009
|
this.#appendTextItem(active, "agentMessage", event.text);
|
|
21150
22010
|
return;
|
|
21151
22011
|
case "tool.call": {
|
|
@@ -21161,8 +22021,8 @@ var HermesSession = class {
|
|
|
21161
22021
|
return;
|
|
21162
22022
|
}
|
|
21163
22023
|
}
|
|
21164
|
-
#appendTextItem(active, kind,
|
|
21165
|
-
const appended = active.appendText(kind,
|
|
22024
|
+
#appendTextItem(active, kind, text2) {
|
|
22025
|
+
const appended = active.appendText(kind, text2);
|
|
21166
22026
|
if (!appended)
|
|
21167
22027
|
return;
|
|
21168
22028
|
if (appended.startedItem) {
|
|
@@ -21172,7 +22032,7 @@ var HermesSession = class {
|
|
|
21172
22032
|
type: "item.updated",
|
|
21173
22033
|
turnId: active.turnId,
|
|
21174
22034
|
itemId: appended.item.itemId,
|
|
21175
|
-
update: { type: "text.append", text }
|
|
22035
|
+
update: { type: "text.append", text: text2 }
|
|
21176
22036
|
});
|
|
21177
22037
|
}
|
|
21178
22038
|
#startToolItem(active, toolCallId, title, name, rawInput) {
|
|
@@ -21182,7 +22042,7 @@ var HermesSession = class {
|
|
|
21182
22042
|
}
|
|
21183
22043
|
const item = {
|
|
21184
22044
|
type: "toolExecution",
|
|
21185
|
-
itemId: hostItemIdSchema.parse(
|
|
22045
|
+
itemId: hostItemIdSchema.parse(randomUUID2()),
|
|
21186
22046
|
toolName: (name ?? title ?? "").trim() || toolCallId,
|
|
21187
22047
|
arguments: isPlainObjectOrArray(rawInput) ? rawInput : null
|
|
21188
22048
|
};
|
|
@@ -21198,7 +22058,8 @@ var HermesSession = class {
|
|
|
21198
22058
|
const entry = active.getToolItem(update.toolCallId);
|
|
21199
22059
|
if (!entry)
|
|
21200
22060
|
return;
|
|
21201
|
-
|
|
22061
|
+
active.rememberFileChanges(update.toolCallId, update);
|
|
22062
|
+
const output = hermesToolOutput(update);
|
|
21202
22063
|
if (output && output.content.length > 0) {
|
|
21203
22064
|
active.updateToolOutput(update.toolCallId, output);
|
|
21204
22065
|
this.#emit({
|
|
@@ -21212,32 +22073,57 @@ var HermesSession = class {
|
|
|
21212
22073
|
const completed = active.completeToolItem(update.toolCallId, output, update.status === "failed");
|
|
21213
22074
|
if (completed) {
|
|
21214
22075
|
this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: completed });
|
|
22076
|
+
if (update.status === "completed") {
|
|
22077
|
+
const fileChange = active.completeFileChanges(update.toolCallId, completed.item.itemId);
|
|
22078
|
+
if (fileChange) {
|
|
22079
|
+
this.#emit({ type: "item.started", turnId: active.turnId, item: fileChange.item });
|
|
22080
|
+
this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: fileChange });
|
|
22081
|
+
}
|
|
22082
|
+
}
|
|
21215
22083
|
}
|
|
21216
22084
|
}
|
|
21217
22085
|
}
|
|
21218
22086
|
#handlePermissionRequest(active, request) {
|
|
21219
|
-
const projected = projectPermissionOptions(request.options);
|
|
22087
|
+
const projected = projectPermissionOptions(request.options, request.effects);
|
|
21220
22088
|
if (projected.actions.length === 0) {
|
|
21221
22089
|
return Promise.resolve({ outcome: { outcome: "cancelled" } });
|
|
21222
22090
|
}
|
|
21223
|
-
const interactionId = hostInteractionIdSchema.parse(
|
|
22091
|
+
const interactionId = hostInteractionIdSchema.parse(randomUUID2());
|
|
21224
22092
|
const interaction = {
|
|
21225
22093
|
type: "approval",
|
|
21226
22094
|
interactionId,
|
|
21227
22095
|
turnId: active.turnId,
|
|
21228
|
-
title: request.request.
|
|
22096
|
+
title: request.request.toolCall.title?.slice(0, 200) ?? "Hermes 请求批准",
|
|
22097
|
+
...request.description ? { description: request.description } : {},
|
|
21229
22098
|
subject: { type: "nativeAction" },
|
|
21230
22099
|
actions: projected.actions
|
|
21231
22100
|
};
|
|
21232
22101
|
this.#emitInteraction(interaction);
|
|
21233
|
-
|
|
22102
|
+
let abort = () => {
|
|
22103
|
+
};
|
|
22104
|
+
const pending = new Promise((resolve) => {
|
|
21234
22105
|
this.#approvalWaiters.set(interactionId, {
|
|
21235
22106
|
interaction,
|
|
21236
22107
|
turnId: active.turnId,
|
|
21237
22108
|
optionIdByAction: projected.optionIdByAction,
|
|
21238
22109
|
resolve
|
|
21239
22110
|
});
|
|
22111
|
+
abort = () => {
|
|
22112
|
+
if (!this.#approvalWaiters.delete(interactionId))
|
|
22113
|
+
return;
|
|
22114
|
+
resolve({ outcome: { outcome: "cancelled" } });
|
|
22115
|
+
this.#emit({
|
|
22116
|
+
type: "interaction.closed",
|
|
22117
|
+
interactionId,
|
|
22118
|
+
turnId: active.turnId,
|
|
22119
|
+
reason: request.signal?.reason === "expired" ? "expired" : "cancelled"
|
|
22120
|
+
});
|
|
22121
|
+
};
|
|
22122
|
+
request.signal?.addEventListener("abort", abort, { once: true });
|
|
22123
|
+
if (request.signal?.aborted)
|
|
22124
|
+
abort();
|
|
21240
22125
|
});
|
|
22126
|
+
return pending.finally(() => request.signal?.removeEventListener("abort", abort));
|
|
21241
22127
|
}
|
|
21242
22128
|
#respondToApproval(command) {
|
|
21243
22129
|
if (this.#faulted) {
|
|
@@ -21278,6 +22164,7 @@ var HermesSession = class {
|
|
|
21278
22164
|
}
|
|
21279
22165
|
try {
|
|
21280
22166
|
await this.#transport.cancel();
|
|
22167
|
+
this.#questions.cancel(command.turnId);
|
|
21281
22168
|
for (const [interactionId, waiter] of this.#approvalWaiters) {
|
|
21282
22169
|
if (waiter.turnId !== command.turnId)
|
|
21283
22170
|
continue;
|
|
@@ -21296,6 +22183,28 @@ var HermesSession = class {
|
|
|
21296
22183
|
return { ok: false, error: failure2 };
|
|
21297
22184
|
}
|
|
21298
22185
|
}
|
|
22186
|
+
#handleQuestionRequest(active, request) {
|
|
22187
|
+
if (this.#activeTurn !== active)
|
|
22188
|
+
return Promise.resolve({ type: "question", answers: {}, cancelled: true });
|
|
22189
|
+
return this.#questions.open(active.turnId, request);
|
|
22190
|
+
}
|
|
22191
|
+
async #selectThinking(command) {
|
|
22192
|
+
if (!this.#transport.setThinking)
|
|
22193
|
+
return err("unsupported", "Hermes does not expose Thinking options");
|
|
22194
|
+
if (!this.#state.availableThinkingOptions?.some(({ id }) => id === command.thinkingOptionId))
|
|
22195
|
+
return err("invalidRequest", "Unknown Hermes Thinking option");
|
|
22196
|
+
try {
|
|
22197
|
+
const selected = await this.#transport.setThinking(command.thinkingOptionId);
|
|
22198
|
+
this.#state = {
|
|
22199
|
+
...this.#state,
|
|
22200
|
+
effectiveThinkingOptionId: harnessThinkingOptionIdSchema.parse(selected)
|
|
22201
|
+
};
|
|
22202
|
+
this.#emit({ type: "session.state.changed", state: { ...this.#state } });
|
|
22203
|
+
return ok({ completed: true });
|
|
22204
|
+
} catch (error51) {
|
|
22205
|
+
return err("nativeFailure", error51 instanceof Error ? error51.message : String(error51));
|
|
22206
|
+
}
|
|
22207
|
+
}
|
|
21299
22208
|
async #selectModel(command) {
|
|
21300
22209
|
const native = decodeHermesModelRefId(command.model.id);
|
|
21301
22210
|
if (!native) {
|
|
@@ -21336,8 +22245,16 @@ var HermesSession = class {
|
|
|
21336
22245
|
}
|
|
21337
22246
|
return err("nativeFailure", error51 instanceof Error ? error51.message : "Hermes rejected Permission Mode selection");
|
|
21338
22247
|
}
|
|
22248
|
+
const locator = this.#nativeRef.locator;
|
|
22249
|
+
if (locator && typeof locator === "object" && !Array.isArray(locator) && locator.transport === "gateway") {
|
|
22250
|
+
this.#nativeRef = {
|
|
22251
|
+
...this.#nativeRef,
|
|
22252
|
+
locator: { ...locator, permissionModeId: command.permissionModeId }
|
|
22253
|
+
};
|
|
22254
|
+
}
|
|
21339
22255
|
this.#state = {
|
|
21340
22256
|
...this.#state,
|
|
22257
|
+
nativeRef: this.#nativeRef,
|
|
21341
22258
|
effectivePermissionModeId: harnessPermissionModeIdSchema.parse(command.permissionModeId)
|
|
21342
22259
|
};
|
|
21343
22260
|
this.#emit({ type: "session.state.changed", state: { ...this.#state } });
|
|
@@ -21345,11 +22262,1323 @@ var HermesSession = class {
|
|
|
21345
22262
|
}
|
|
21346
22263
|
};
|
|
21347
22264
|
|
|
22265
|
+
// dist/gateway-transport.js
|
|
22266
|
+
import { spawn as spawn3, spawnSync as spawnSync2 } from "node:child_process";
|
|
22267
|
+
import { access as access2 } from "node:fs/promises";
|
|
22268
|
+
import { createInterface } from "node:readline";
|
|
22269
|
+
|
|
22270
|
+
// dist/gateway-delegation.js
|
|
22271
|
+
import { mkdtemp, writeFile, rm } from "node:fs/promises";
|
|
22272
|
+
import os2 from "node:os";
|
|
22273
|
+
import path5 from "node:path";
|
|
22274
|
+
var HERMES_DELEGATION_GUIDANCE = `This Session runs inside codexhost.
|
|
22275
|
+
When the user authorizes cross-Harness delegation, discover the executable named by CODEXHOST_CLI_PATH through your native terminal tool. Read its --help and harness list, then use delegate start and thread send/read/wait/cancel as documented. Prefer --format compact. Preserve CODEXHOST_RUNTIME_ENDPOINT, CODEXHOST_RUNTIME_TOKEN and CODEXHOST_THREAD_ID in these calls: they identify the Runtime and parent Thread. Never print their values or substitute another executable. Native Hermes delegate_task remains available for Hermes subagents.`;
|
|
22276
|
+
var required2 = [
|
|
22277
|
+
"CODEXHOST_CLI_PATH",
|
|
22278
|
+
"CODEXHOST_RUNTIME_ENDPOINT",
|
|
22279
|
+
"CODEXHOST_RUNTIME_TOKEN",
|
|
22280
|
+
"CODEXHOST_THREAD_ID"
|
|
22281
|
+
];
|
|
22282
|
+
async function prepareGatewayDelegation(environment) {
|
|
22283
|
+
if (!required2.every((key) => environment[key]))
|
|
22284
|
+
return { environment, bootstrap: "", dispose: async () => {
|
|
22285
|
+
} };
|
|
22286
|
+
const directory = await mkdtemp(path5.join(os2.tmpdir(), "codexhost-hermes-delegation-"));
|
|
22287
|
+
const file2 = path5.join(directory, "SKILL.md");
|
|
22288
|
+
try {
|
|
22289
|
+
await writeFile(file2, `---
|
|
22290
|
+
name: delegation
|
|
22291
|
+
description: Discover authorized codexhost agent collaboration.
|
|
22292
|
+
---
|
|
22293
|
+
|
|
22294
|
+
${HERMES_DELEGATION_GUIDANCE}
|
|
22295
|
+
`, { mode: 384 });
|
|
22296
|
+
return {
|
|
22297
|
+
environment: {
|
|
22298
|
+
...environment,
|
|
22299
|
+
HERMES_TUI_SKILLS: [environment.HERMES_TUI_SKILLS, "codexhost-runtime:delegation"].filter(Boolean).join(",")
|
|
22300
|
+
},
|
|
22301
|
+
// Reserve RPC stdout before native plugin imports. The registration is
|
|
22302
|
+
// process-local; no plugin is installed and no user config is changed.
|
|
22303
|
+
bootstrap: `from tui_gateway import server
|
|
22304
|
+
from pathlib import Path
|
|
22305
|
+
from hermes_cli.plugins import PluginContext, PluginManifest, get_plugin_manager
|
|
22306
|
+
PluginContext(PluginManifest(name="codexhost-runtime"), get_plugin_manager()).register_skill(
|
|
22307
|
+
"delegation", Path(${JSON.stringify(file2)}))
|
|
22308
|
+
`,
|
|
22309
|
+
dispose: () => rm(directory, { recursive: true, force: true })
|
|
22310
|
+
};
|
|
22311
|
+
} catch (error51) {
|
|
22312
|
+
await rm(directory, { recursive: true, force: true });
|
|
22313
|
+
throw error51;
|
|
22314
|
+
}
|
|
22315
|
+
}
|
|
22316
|
+
|
|
22317
|
+
// dist/gateway-transport.js
|
|
22318
|
+
function gatewayRecord(value) {
|
|
22319
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
22320
|
+
}
|
|
22321
|
+
function gatewayString(value) {
|
|
22322
|
+
return typeof value === "string" ? value : "";
|
|
22323
|
+
}
|
|
22324
|
+
var GATEWAY_LAUNCH = `import runpy
|
|
22325
|
+
runpy.run_module('tui_gateway.entry', run_name='__main__')`;
|
|
22326
|
+
var HermesGatewayTransport = class _HermesGatewayTransport {
|
|
22327
|
+
python;
|
|
22328
|
+
cwd;
|
|
22329
|
+
environment;
|
|
22330
|
+
timeoutMs;
|
|
22331
|
+
onEvent = () => void 0;
|
|
22332
|
+
onRequest = (id) => this.rejectRequest(id);
|
|
22333
|
+
onFault = () => void 0;
|
|
22334
|
+
#child = null;
|
|
22335
|
+
#nextId = 0;
|
|
22336
|
+
#pending = /* @__PURE__ */ new Map();
|
|
22337
|
+
#closed = false;
|
|
22338
|
+
#closePromise = null;
|
|
22339
|
+
#processClosed = Promise.resolve();
|
|
22340
|
+
#sessionErrors = /* @__PURE__ */ new Map();
|
|
22341
|
+
#sessionReady = /* @__PURE__ */ new Map();
|
|
22342
|
+
#sessionWaiters = /* @__PURE__ */ new Map();
|
|
22343
|
+
#stderr = "";
|
|
22344
|
+
#delegation;
|
|
22345
|
+
constructor(python, cwd, environment, timeoutMs = 3e4) {
|
|
22346
|
+
this.python = python;
|
|
22347
|
+
this.cwd = cwd;
|
|
22348
|
+
this.environment = environment;
|
|
22349
|
+
this.timeoutMs = timeoutMs;
|
|
22350
|
+
}
|
|
22351
|
+
static async probe(executable, cwd, environment) {
|
|
22352
|
+
const shim = await venvPythonFromShim(executable);
|
|
22353
|
+
const candidates = [
|
|
22354
|
+
...new Set([
|
|
22355
|
+
environment.CODEXHOST_HERMES_GATEWAY_PYTHON,
|
|
22356
|
+
shim,
|
|
22357
|
+
...inventoryPythonCandidates(executable)
|
|
22358
|
+
].filter((candidate) => !!candidate))
|
|
22359
|
+
];
|
|
22360
|
+
for (const candidate of candidates) {
|
|
22361
|
+
try {
|
|
22362
|
+
await access2(candidate);
|
|
22363
|
+
} catch {
|
|
22364
|
+
continue;
|
|
22365
|
+
}
|
|
22366
|
+
const transport = new _HermesGatewayTransport(candidate, cwd, environment, 2e4);
|
|
22367
|
+
try {
|
|
22368
|
+
await transport.start();
|
|
22369
|
+
return candidate;
|
|
22370
|
+
} catch {
|
|
22371
|
+
} finally {
|
|
22372
|
+
await transport.close();
|
|
22373
|
+
}
|
|
22374
|
+
}
|
|
22375
|
+
return null;
|
|
22376
|
+
}
|
|
22377
|
+
async prepareSession() {
|
|
22378
|
+
if (this.#child || this.#closed)
|
|
22379
|
+
throw new Error("Hermes gateway Session cannot be prepared after start");
|
|
22380
|
+
const prepared = await prepareGatewayDelegation(this.environment);
|
|
22381
|
+
if (this.#closed) {
|
|
22382
|
+
await prepared.dispose();
|
|
22383
|
+
throw new Error("Hermes gateway closed during Session preparation");
|
|
22384
|
+
}
|
|
22385
|
+
this.#delegation = prepared;
|
|
22386
|
+
}
|
|
22387
|
+
async start() {
|
|
22388
|
+
if (this.#child || this.#closed)
|
|
22389
|
+
throw new Error("Hermes gateway cannot be started twice");
|
|
22390
|
+
const child = spawn3(this.python, ["-I", "-u", "-c", (this.#delegation?.bootstrap ?? "") + GATEWAY_LAUNCH], {
|
|
22391
|
+
cwd: this.cwd,
|
|
22392
|
+
env: {
|
|
22393
|
+
...process.env,
|
|
22394
|
+
...this.#delegation?.environment ?? this.environment,
|
|
22395
|
+
HERMES_TUI_TOOL_PROGRESS: "all"
|
|
22396
|
+
},
|
|
22397
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
22398
|
+
windowsHide: true,
|
|
22399
|
+
detached: process.platform !== "win32"
|
|
22400
|
+
});
|
|
22401
|
+
this.#child = child;
|
|
22402
|
+
this.#processClosed = new Promise((resolve) => child.once("close", () => resolve()));
|
|
22403
|
+
child.stderr.on("data", (data) => {
|
|
22404
|
+
this.#stderr = sanitizeDiagnosticTail(this.#stderr + data.toString());
|
|
22405
|
+
});
|
|
22406
|
+
child.stdin.on("error", (error51) => this.#fault(error51));
|
|
22407
|
+
child.once("error", (error51) => this.#fault(error51));
|
|
22408
|
+
child.once("exit", () => {
|
|
22409
|
+
if (!this.#closed)
|
|
22410
|
+
this.#fault(new Error(`Hermes gateway exited: ${this.#stderr}`));
|
|
22411
|
+
});
|
|
22412
|
+
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
22413
|
+
try {
|
|
22414
|
+
this.#frame(gatewayRecord(JSON.parse(line)));
|
|
22415
|
+
} catch (error51) {
|
|
22416
|
+
this.#fault(error51 instanceof Error ? error51 : new Error(String(error51)));
|
|
22417
|
+
}
|
|
22418
|
+
});
|
|
22419
|
+
const capabilities = await this.request("gateway.capabilities", {});
|
|
22420
|
+
if (capabilities.per_session_exclusive_submit !== true)
|
|
22421
|
+
throw new Error("Hermes gateway does not enforce exclusive turns");
|
|
22422
|
+
}
|
|
22423
|
+
async waitForSession(sessionId) {
|
|
22424
|
+
const error51 = this.#sessionErrors.get(sessionId);
|
|
22425
|
+
if (error51)
|
|
22426
|
+
throw error51;
|
|
22427
|
+
const ready = this.#sessionReady.get(sessionId);
|
|
22428
|
+
if (ready)
|
|
22429
|
+
return ready;
|
|
22430
|
+
const result = new Promise((resolve, reject) => this.#sessionWaiters.set(sessionId, { resolve, reject }));
|
|
22431
|
+
try {
|
|
22432
|
+
return await withTimeout(result, this.timeoutMs, "Hermes gateway agent initialization");
|
|
22433
|
+
} finally {
|
|
22434
|
+
this.#sessionWaiters.delete(sessionId);
|
|
22435
|
+
}
|
|
22436
|
+
}
|
|
22437
|
+
async request(method, params, timeoutMs = this.timeoutMs) {
|
|
22438
|
+
if (this.#closed || !this.#child)
|
|
22439
|
+
throw new Error("Hermes gateway is closed");
|
|
22440
|
+
const id = `codexhost-${++this.#nextId}`;
|
|
22441
|
+
const response = new Promise((resolve, reject) => {
|
|
22442
|
+
this.#pending.set(id, { resolve, reject });
|
|
22443
|
+
this.#send({ jsonrpc: "2.0", id, method, params });
|
|
22444
|
+
});
|
|
22445
|
+
try {
|
|
22446
|
+
return await withTimeout(response, timeoutMs, `Hermes ${method}`);
|
|
22447
|
+
} catch (error51) {
|
|
22448
|
+
if (error51 instanceof HermesTransportError)
|
|
22449
|
+
this.#fault(error51);
|
|
22450
|
+
throw error51;
|
|
22451
|
+
} finally {
|
|
22452
|
+
this.#pending.delete(id);
|
|
22453
|
+
}
|
|
22454
|
+
}
|
|
22455
|
+
respond(id, result) {
|
|
22456
|
+
this.#send({ jsonrpc: "2.0", id, result });
|
|
22457
|
+
}
|
|
22458
|
+
rejectRequest(id) {
|
|
22459
|
+
this.#send({
|
|
22460
|
+
jsonrpc: "2.0",
|
|
22461
|
+
id,
|
|
22462
|
+
error: { code: -32601, message: "Unsupported Host interaction" }
|
|
22463
|
+
});
|
|
22464
|
+
}
|
|
22465
|
+
#send(frame) {
|
|
22466
|
+
if (!this.#child?.stdin.writable)
|
|
22467
|
+
throw new Error("Hermes gateway input is closed");
|
|
22468
|
+
this.#child.stdin.write(JSON.stringify(frame) + "\n");
|
|
22469
|
+
}
|
|
22470
|
+
#frame(frame) {
|
|
22471
|
+
if (frame.method === "event") {
|
|
22472
|
+
const event = gatewayRecord(frame.params);
|
|
22473
|
+
const sessionId = gatewayString(event.session_id);
|
|
22474
|
+
const payload = gatewayRecord(event.payload);
|
|
22475
|
+
if (event.type === "session.info" && payload.lazy !== true) {
|
|
22476
|
+
this.#sessionReady.set(sessionId, payload);
|
|
22477
|
+
this.#sessionWaiters.get(sessionId)?.resolve(payload);
|
|
22478
|
+
} else if (event.type === "error") {
|
|
22479
|
+
const error51 = new Error(gatewayString(payload.message));
|
|
22480
|
+
this.#sessionErrors.set(sessionId, error51);
|
|
22481
|
+
this.#sessionWaiters.get(sessionId)?.reject(error51);
|
|
22482
|
+
}
|
|
22483
|
+
this.onEvent(event);
|
|
22484
|
+
return;
|
|
22485
|
+
}
|
|
22486
|
+
if (typeof frame.method === "string" && typeof frame.id === "string") {
|
|
22487
|
+
this.onRequest(frame.id, frame.method, gatewayRecord(frame.params));
|
|
22488
|
+
return;
|
|
22489
|
+
}
|
|
22490
|
+
const id = gatewayString(frame.id);
|
|
22491
|
+
const pending = this.#pending.get(id);
|
|
22492
|
+
if (!pending)
|
|
22493
|
+
return;
|
|
22494
|
+
this.#pending.delete(id);
|
|
22495
|
+
if (frame.error)
|
|
22496
|
+
pending.reject(new Error(gatewayString(gatewayRecord(frame.error).message) || "Hermes gateway request failed"));
|
|
22497
|
+
else
|
|
22498
|
+
pending.resolve(gatewayRecord(frame.result));
|
|
22499
|
+
}
|
|
22500
|
+
#fault(error51) {
|
|
22501
|
+
for (const pending of this.#pending.values())
|
|
22502
|
+
pending.reject(error51);
|
|
22503
|
+
for (const waiter of this.#sessionWaiters.values())
|
|
22504
|
+
waiter.reject(error51);
|
|
22505
|
+
this.#sessionWaiters.clear();
|
|
22506
|
+
this.#pending.clear();
|
|
22507
|
+
if (!this.#closed) {
|
|
22508
|
+
this.onFault(error51);
|
|
22509
|
+
void this.close();
|
|
22510
|
+
}
|
|
22511
|
+
}
|
|
22512
|
+
#signal(signal) {
|
|
22513
|
+
const pid = this.#child?.pid;
|
|
22514
|
+
if (!pid)
|
|
22515
|
+
return;
|
|
22516
|
+
if (process.platform === "win32") {
|
|
22517
|
+
spawnSync2("taskkill.exe", ["/pid", String(pid), "/t", "/f"], {
|
|
22518
|
+
stdio: "ignore",
|
|
22519
|
+
windowsHide: true
|
|
22520
|
+
});
|
|
22521
|
+
return;
|
|
22522
|
+
}
|
|
22523
|
+
try {
|
|
22524
|
+
process.kill(-pid, signal);
|
|
22525
|
+
} catch (error51) {
|
|
22526
|
+
if (gatewayRecord(error51).code !== "ESRCH")
|
|
22527
|
+
throw error51;
|
|
22528
|
+
}
|
|
22529
|
+
}
|
|
22530
|
+
close() {
|
|
22531
|
+
return this.#closePromise ??= this.#close().finally(() => this.#delegation?.dispose());
|
|
22532
|
+
}
|
|
22533
|
+
async #close() {
|
|
22534
|
+
if (this.#closed)
|
|
22535
|
+
return;
|
|
22536
|
+
this.#closed = true;
|
|
22537
|
+
this.#fault(new Error("Hermes gateway closed"));
|
|
22538
|
+
const child = this.#child;
|
|
22539
|
+
if (!child)
|
|
22540
|
+
return;
|
|
22541
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
22542
|
+
this.#signal("SIGKILL");
|
|
22543
|
+
return;
|
|
22544
|
+
}
|
|
22545
|
+
const exit = this.#processClosed;
|
|
22546
|
+
child.stdin.end();
|
|
22547
|
+
try {
|
|
22548
|
+
await withTimeout(exit, 2e3, "Hermes gateway close");
|
|
22549
|
+
} catch {
|
|
22550
|
+
this.#signal("SIGTERM");
|
|
22551
|
+
try {
|
|
22552
|
+
await withTimeout(exit, 2e3, "Hermes gateway exit");
|
|
22553
|
+
} catch {
|
|
22554
|
+
this.#signal("SIGKILL");
|
|
22555
|
+
await withTimeout(exit, 2e3, "Hermes gateway killed").catch(() => void 0);
|
|
22556
|
+
}
|
|
22557
|
+
}
|
|
22558
|
+
}
|
|
22559
|
+
};
|
|
22560
|
+
|
|
22561
|
+
// dist/gateway-history.js
|
|
22562
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
22563
|
+
|
|
22564
|
+
// dist/gateway-history-script.js
|
|
22565
|
+
var GATEWAY_HISTORY_SCRIPT = String.raw`
|
|
22566
|
+
import sys
|
|
22567
|
+
output = sys.stdout
|
|
22568
|
+
sys.stdout = sys.stderr
|
|
22569
|
+
import hashlib, json, sqlite3
|
|
22570
|
+
from pathlib import Path
|
|
22571
|
+
from urllib.parse import quote
|
|
22572
|
+
from tui_gateway.server import _history_to_messages
|
|
22573
|
+
from agent.context_compressor import user_originated_turn_view
|
|
22574
|
+
from hermes_state import SessionDB
|
|
22575
|
+
from hermes_state_ids import new_session_id
|
|
22576
|
+
p = json.load(sys.stdin)
|
|
22577
|
+
sid = p['sessionId']
|
|
22578
|
+
public_sid = sid
|
|
22579
|
+
|
|
22580
|
+
class HistoryFailure(Exception):
|
|
22581
|
+
def __init__(self, code, message):
|
|
22582
|
+
super().__init__(message)
|
|
22583
|
+
self.code = code
|
|
22584
|
+
|
|
22585
|
+
def digest(rows):
|
|
22586
|
+
return hashlib.sha256(json.dumps(rows, sort_keys=True, ensure_ascii=True, separators=(',', ':')).encode()).hexdigest()
|
|
22587
|
+
|
|
22588
|
+
def config(value):
|
|
22589
|
+
return json.loads(value) if isinstance(value, str) else dict(value or {})
|
|
22590
|
+
|
|
22591
|
+
def user_text(row):
|
|
22592
|
+
view = user_originated_turn_view(row)
|
|
22593
|
+
if view is None: return None
|
|
22594
|
+
# Use the original display kind for native /steer and skill rendering; the
|
|
22595
|
+
# origin predicate above separately excludes synthetic continuation turns.
|
|
22596
|
+
projected = _history_to_messages([row])
|
|
22597
|
+
if not projected: return None
|
|
22598
|
+
return projected[0].get('text')
|
|
22599
|
+
|
|
22600
|
+
def capture(db):
|
|
22601
|
+
exported = db.export_session(sid)
|
|
22602
|
+
if exported is None:
|
|
22603
|
+
raise RuntimeError('Hermes session is not persisted')
|
|
22604
|
+
active = exported['messages']
|
|
22605
|
+
lineage = db.get_compression_lineage(sid)
|
|
22606
|
+
if not lineage: raise RuntimeError('Hermes session lineage is missing')
|
|
22607
|
+
_, display = db.get_resume_conversations(sid)
|
|
22608
|
+
# get_resume_conversations preserves tool relations but sanitizes display text.
|
|
22609
|
+
# Read the same native rows verbatim and native display identities through a
|
|
22610
|
+
# separate mode=ro connection; MIN(id) preserves identity across tail cloning.
|
|
22611
|
+
uri = 'file:' + quote(str(Path(db.db_path).resolve()), safe='/') + '?mode=ro'
|
|
22612
|
+
with sqlite3.connect(uri, uri=True) as conn:
|
|
22613
|
+
conn.row_factory = sqlite3.Row
|
|
22614
|
+
rows = []
|
|
22615
|
+
native_rows = {}
|
|
22616
|
+
for msg in display:
|
|
22617
|
+
row = conn.execute('SELECT * FROM messages WHERE id = ?', (msg['_row_id'],)).fetchone()
|
|
22618
|
+
if row is None:
|
|
22619
|
+
raise RuntimeError('Hermes history changed while reading')
|
|
22620
|
+
owner = row['session_id']
|
|
22621
|
+
if owner not in native_rows:
|
|
22622
|
+
native_rows[owner] = {r['id']: r for r in db.get_messages(owner, include_inactive=True)}
|
|
22623
|
+
raw = dict(native_rows[owner][row['id']])
|
|
22624
|
+
original = row['id']
|
|
22625
|
+
if row['display_identity'] is not None:
|
|
22626
|
+
original = conn.execute('SELECT MIN(id) FROM messages WHERE session_id IN (' + ','.join('?' for _ in lineage) + ') AND display_identity = ?',
|
|
22627
|
+
(*lineage, row['display_identity'])).fetchone()[0] or row['id']
|
|
22628
|
+
raw['original_id'] = original
|
|
22629
|
+
if raw['role'] == 'user': raw['user_text'] = user_text(raw)
|
|
22630
|
+
elif raw['role'] == 'assistant':
|
|
22631
|
+
visible = _history_to_messages([raw])
|
|
22632
|
+
raw['display_text'] = visible[0].get('text', '') if visible else ''
|
|
22633
|
+
raw['display_visible'] = bool(visible)
|
|
22634
|
+
rows.append(raw)
|
|
22635
|
+
compressed = conn.execute('SELECT 1 FROM messages WHERE session_id = ? AND (compacted = 1 OR _compressed_summary = 1) LIMIT 1', (sid,)).fetchone() is not None
|
|
22636
|
+
current = db.export_session(sid)
|
|
22637
|
+
if current is None or digest(current['messages']) != digest(active):
|
|
22638
|
+
raise RuntimeError('Hermes history changed while reading')
|
|
22639
|
+
derivable = sid == public_sid and len(lineage) == 1 and not compressed and [r['id'] for r in rows] == [r['id'] for r in active]
|
|
22640
|
+
boundaries = {}
|
|
22641
|
+
if derivable:
|
|
22642
|
+
for i, row in enumerate(active):
|
|
22643
|
+
if user_text(row) is None: continue
|
|
22644
|
+
end = next((j for j in range(i + 1, len(active)) if user_text(active[j]) is not None), len(active))
|
|
22645
|
+
boundaries[str(row['id'])] = {'count': end, 'digest': digest(active[:end])}
|
|
22646
|
+
return exported, {'rows': rows, 'derivable': derivable, 'boundaries': boundaries, 'physicalSessionId': sid}
|
|
22647
|
+
|
|
22648
|
+
try:
|
|
22649
|
+
if p['operation'] == 'ensure':
|
|
22650
|
+
db = SessionDB()
|
|
22651
|
+
try:
|
|
22652
|
+
if db.get_session(sid) is None:
|
|
22653
|
+
from hermes_constants import parse_reasoning_effort
|
|
22654
|
+
initial = {}
|
|
22655
|
+
if isinstance(p.get('provider'), str) and p['provider']: initial['provider'] = p['provider']
|
|
22656
|
+
if isinstance(p.get('model'), str) and p['model']: initial['model'] = p['model']
|
|
22657
|
+
if isinstance(p.get('reasoningEffort'), str):
|
|
22658
|
+
reasoning = parse_reasoning_effort(p['reasoningEffort'])
|
|
22659
|
+
if reasoning is not None: initial['reasoning_config'] = reasoning
|
|
22660
|
+
if isinstance(p.get('yolo'), bool): initial['yolo_mode'] = p['yolo']
|
|
22661
|
+
db.create_session(session_id=sid, source='cli', cwd=p['cwd'], model=p.get('model'), model_config=initial)
|
|
22662
|
+
result = {'created': True}
|
|
22663
|
+
finally: db.close()
|
|
22664
|
+
elif p['operation'] == 'discard':
|
|
22665
|
+
child = p['derivedSessionId']
|
|
22666
|
+
result = {'deleted': False}
|
|
22667
|
+
if child == sid: raise HistoryFailure('invalidState', 'Cannot delete the source Hermes session')
|
|
22668
|
+
db = SessionDB()
|
|
22669
|
+
try:
|
|
22670
|
+
row = db.get_session(child)
|
|
22671
|
+
if (row is not None and row.get('parent_session_id') == sid
|
|
22672
|
+
and config(row.get('model_config')).get('_branched_from') == sid
|
|
22673
|
+
and digest(db.get_messages(child)) == p['expectedDigest']):
|
|
22674
|
+
result['deleted'] = db.delete_session(child, expected_delete_ids=[child])
|
|
22675
|
+
finally: db.close()
|
|
22676
|
+
else:
|
|
22677
|
+
db = SessionDB(read_only=True)
|
|
22678
|
+
try:
|
|
22679
|
+
sid = db.resolve_resume_session_id(public_sid)
|
|
22680
|
+
exported, snapshot = capture(db)
|
|
22681
|
+
finally: db.close()
|
|
22682
|
+
if p['operation'] in ('read', 'resolve'):
|
|
22683
|
+
result = snapshot
|
|
22684
|
+
elif p['operation'] == 'derive':
|
|
22685
|
+
if not snapshot['derivable']:
|
|
22686
|
+
raise HistoryFailure('unsupported', 'Hermes cannot losslessly derive compacted or inherited history')
|
|
22687
|
+
messages = exported['messages']
|
|
22688
|
+
if p.get('rollbackLastTurn'):
|
|
22689
|
+
users = [i for i, row in enumerate(messages) if user_text(row) is not None]
|
|
22690
|
+
if not users: raise HistoryFailure('invalidState', 'Hermes session has no user turn to roll back')
|
|
22691
|
+
messages = messages[:users[-1]]
|
|
22692
|
+
elif p.get('checkpoint'):
|
|
22693
|
+
checkpoint = p['checkpoint']
|
|
22694
|
+
boundary = snapshot['boundaries'].get(checkpoint['checkpointId'])
|
|
22695
|
+
if boundary is None or boundary != checkpoint.get('locator'):
|
|
22696
|
+
raise HistoryFailure('checkpointNotFound', 'Hermes checkpoint no longer matches native history')
|
|
22697
|
+
messages = messages[:boundary['count']]
|
|
22698
|
+
child = new_session_id()
|
|
22699
|
+
model_config = config(exported.get('model_config'))
|
|
22700
|
+
model_config['_branched_from'] = sid
|
|
22701
|
+
payload = {**exported, 'id': child, 'parent_session_id': sid, 'model_config': model_config,
|
|
22702
|
+
'messages': messages, 'title': None, 'ended_at': None, 'end_reason': None, 'archived': False}
|
|
22703
|
+
db = SessionDB()
|
|
22704
|
+
imported = False
|
|
22705
|
+
try:
|
|
22706
|
+
result = db.import_sessions([payload])
|
|
22707
|
+
if result.get('imported_ids') != [child]:
|
|
22708
|
+
raise RuntimeError('Hermes native import did not create the derived session')
|
|
22709
|
+
imported = True
|
|
22710
|
+
# Native import resets ownership. Fill this NEW row only through the
|
|
22711
|
+
# native COALESCE upsert, preserving source profile and working dir.
|
|
22712
|
+
db.create_session(session_id=child, source=exported.get('source') or 'cli',
|
|
22713
|
+
cwd=exported.get('cwd'), profile_name=exported.get('profile_name'), parent_session_id=sid)
|
|
22714
|
+
tools = exported.get('tool_names')
|
|
22715
|
+
if isinstance(tools, str): tools = json.loads(tools)
|
|
22716
|
+
if tools is not None: db.update_session_tool_names(child, tools)
|
|
22717
|
+
copied = db.get_messages(child)
|
|
22718
|
+
def payload_rows(rows):
|
|
22719
|
+
ignored = {'id', 'session_id', 'active', 'compacted', '_row_id'}
|
|
22720
|
+
result = []
|
|
22721
|
+
for row in rows:
|
|
22722
|
+
row = {k: v for k, v in row.items() if k not in ignored}
|
|
22723
|
+
for key in ('reasoning_details', 'codex_reasoning_items', 'codex_message_items'):
|
|
22724
|
+
if isinstance(row.get(key), str): row[key] = json.loads(row[key])
|
|
22725
|
+
result.append(row)
|
|
22726
|
+
return result
|
|
22727
|
+
if payload_rows(copied) != payload_rows(messages):
|
|
22728
|
+
raise RuntimeError('Hermes native import did not preserve the transcript')
|
|
22729
|
+
result = {'sessionId': child, 'digest': digest(copied)}
|
|
22730
|
+
except Exception:
|
|
22731
|
+
if imported: db.delete_session(child, expected_delete_ids=[child])
|
|
22732
|
+
raise
|
|
22733
|
+
finally: db.close()
|
|
22734
|
+
else: raise RuntimeError('Unknown Hermes history operation')
|
|
22735
|
+
except HistoryFailure as exc:
|
|
22736
|
+
result = {'error': {'code': exc.code, 'message': str(exc)}}
|
|
22737
|
+
print(json.dumps(result, ensure_ascii=True), file=output)
|
|
22738
|
+
`;
|
|
22739
|
+
|
|
22740
|
+
// dist/gateway-history.js
|
|
22741
|
+
function record2(value) {
|
|
22742
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
22743
|
+
}
|
|
22744
|
+
function text(value) {
|
|
22745
|
+
if (typeof value === "string")
|
|
22746
|
+
return value;
|
|
22747
|
+
if (Array.isArray(value))
|
|
22748
|
+
return value.map((part) => text(record2(part).text)).join("\n");
|
|
22749
|
+
return "";
|
|
22750
|
+
}
|
|
22751
|
+
function parsed(value) {
|
|
22752
|
+
if (typeof value === "string") {
|
|
22753
|
+
try {
|
|
22754
|
+
return JSON.parse(value);
|
|
22755
|
+
} catch {
|
|
22756
|
+
return value;
|
|
22757
|
+
}
|
|
22758
|
+
}
|
|
22759
|
+
return value ?? null;
|
|
22760
|
+
}
|
|
22761
|
+
function projectGatewayHistory(sessionId, data) {
|
|
22762
|
+
const turns = [];
|
|
22763
|
+
let turn;
|
|
22764
|
+
const tools = /* @__PURE__ */ new Map();
|
|
22765
|
+
for (const row of data.rows) {
|
|
22766
|
+
if (!Number.isSafeInteger(row.id) || !Number.isSafeInteger(row.original_id))
|
|
22767
|
+
throw new Error("Hermes history has no durable message identity");
|
|
22768
|
+
const id = String(row.original_id);
|
|
22769
|
+
if (row.role === "user") {
|
|
22770
|
+
if (typeof row.user_text !== "string")
|
|
22771
|
+
continue;
|
|
22772
|
+
tools.clear();
|
|
22773
|
+
const boundary = data.derivable ? data.boundaries[String(row.id)] : void 0;
|
|
22774
|
+
turn = {
|
|
22775
|
+
nativeTurnRef: nativeTurnRefSchema.parse({
|
|
22776
|
+
harnessId: "hermes",
|
|
22777
|
+
nativeSessionId: sessionId,
|
|
22778
|
+
nativeTurnKey: id,
|
|
22779
|
+
formatVersion: 1
|
|
22780
|
+
}),
|
|
22781
|
+
...boundary ? {
|
|
22782
|
+
checkpoint: nativeCheckpointRefSchema.parse({
|
|
22783
|
+
harnessId: "hermes",
|
|
22784
|
+
nativeSessionId: sessionId,
|
|
22785
|
+
checkpointId: String(row.id),
|
|
22786
|
+
formatVersion: 1,
|
|
22787
|
+
locator: boundary
|
|
22788
|
+
})
|
|
22789
|
+
} : {},
|
|
22790
|
+
input: [{ type: "text", text: row.user_text }],
|
|
22791
|
+
items: [],
|
|
22792
|
+
outcome: {
|
|
22793
|
+
status: "unknown",
|
|
22794
|
+
reason: "Hermes persisted history does not record a turn outcome"
|
|
22795
|
+
},
|
|
22796
|
+
...typeof row.timestamp === "number" ? { startedAtMs: Math.trunc(row.timestamp * 1e3) } : {}
|
|
22797
|
+
};
|
|
22798
|
+
turns.push(turn);
|
|
22799
|
+
continue;
|
|
22800
|
+
}
|
|
22801
|
+
if (!turn)
|
|
22802
|
+
continue;
|
|
22803
|
+
const itemId = (suffix) => hostItemIdSchema.parse(`hermes:${id}:${suffix}`);
|
|
22804
|
+
if (row.role === "assistant") {
|
|
22805
|
+
const reasoning = row.display_visible === false ? "" : text(row.reasoning_content) || text(row.reasoning);
|
|
22806
|
+
if (reasoning)
|
|
22807
|
+
turn.items.push({
|
|
22808
|
+
item: { type: "reasoning", itemId: itemId("reasoning"), text: reasoning },
|
|
22809
|
+
outcome: { status: "succeeded" }
|
|
22810
|
+
});
|
|
22811
|
+
const content = typeof row.display_text === "string" ? row.display_text : text(row.content);
|
|
22812
|
+
if (content)
|
|
22813
|
+
turn.items.push({
|
|
22814
|
+
item: { type: "agentMessage", itemId: itemId("message"), text: content },
|
|
22815
|
+
outcome: { status: "succeeded" }
|
|
22816
|
+
});
|
|
22817
|
+
if (Array.isArray(row.tool_calls))
|
|
22818
|
+
for (const value of row.tool_calls) {
|
|
22819
|
+
const call = record2(value);
|
|
22820
|
+
const fn = record2(call.function);
|
|
22821
|
+
if (typeof call.id !== "string" || typeof fn.name !== "string")
|
|
22822
|
+
continue;
|
|
22823
|
+
tools.set(call.id, {
|
|
22824
|
+
item: {
|
|
22825
|
+
type: "toolExecution",
|
|
22826
|
+
itemId: itemId(`tool:${call.id}`),
|
|
22827
|
+
toolName: fn.name,
|
|
22828
|
+
arguments: parsed(fn.arguments)
|
|
22829
|
+
},
|
|
22830
|
+
outcome: { status: "succeeded" }
|
|
22831
|
+
});
|
|
22832
|
+
}
|
|
22833
|
+
} else if (row.role === "tool" && typeof row.tool_call_id === "string") {
|
|
22834
|
+
const tool = tools.get(row.tool_call_id);
|
|
22835
|
+
if (!tool || tool.item.type !== "toolExecution")
|
|
22836
|
+
continue;
|
|
22837
|
+
const output = typeof row.content === "string" ? row.content : JSON.stringify(row.content ?? "");
|
|
22838
|
+
tool.item.output = { content: [{ type: "text", text: output }] };
|
|
22839
|
+
const result = record2(parsed(row.content));
|
|
22840
|
+
if (result.is_error === true || result.isError === true || result.error)
|
|
22841
|
+
tool.outcome = {
|
|
22842
|
+
status: "failed",
|
|
22843
|
+
error: {
|
|
22844
|
+
code: "nativeFailure",
|
|
22845
|
+
message: typeof result.error === "string" ? result.error : "Hermes tool reported an error",
|
|
22846
|
+
retryable: false
|
|
22847
|
+
}
|
|
22848
|
+
};
|
|
22849
|
+
turn.items.push(tool);
|
|
22850
|
+
tools.delete(row.tool_call_id);
|
|
22851
|
+
}
|
|
22852
|
+
}
|
|
22853
|
+
return { turns };
|
|
22854
|
+
}
|
|
22855
|
+
var HermesGatewayHistoryError = class extends Error {
|
|
22856
|
+
code;
|
|
22857
|
+
constructor(code, message) {
|
|
22858
|
+
super(message);
|
|
22859
|
+
this.code = code;
|
|
22860
|
+
}
|
|
22861
|
+
};
|
|
22862
|
+
var HermesGatewayHistory = class {
|
|
22863
|
+
options;
|
|
22864
|
+
#derived = /* @__PURE__ */ new Map();
|
|
22865
|
+
constructor(options) {
|
|
22866
|
+
this.options = options;
|
|
22867
|
+
}
|
|
22868
|
+
async readSnapshot() {
|
|
22869
|
+
const data = await this.#run({ operation: "read" });
|
|
22870
|
+
if (!Array.isArray(data.rows) || typeof data.derivable !== "boolean" || !data.boundaries)
|
|
22871
|
+
throw new Error("Malformed Hermes native history response");
|
|
22872
|
+
return projectGatewayHistory(this.options.nativeSessionId, data);
|
|
22873
|
+
}
|
|
22874
|
+
async resolvePhysicalSessionId() {
|
|
22875
|
+
const data = await this.#run({ operation: "resolve" });
|
|
22876
|
+
if (typeof data.physicalSessionId !== "string")
|
|
22877
|
+
throw new Error("Missing Hermes storage identity");
|
|
22878
|
+
return data.physicalSessionId;
|
|
22879
|
+
}
|
|
22880
|
+
async ensureCreated(input) {
|
|
22881
|
+
await this.#run({ operation: "ensure", ...input });
|
|
22882
|
+
}
|
|
22883
|
+
async derive(input = {}) {
|
|
22884
|
+
if (input.checkpoint && input.rollbackLastTurn)
|
|
22885
|
+
throw new Error("Conflicting Hermes derivation boundaries");
|
|
22886
|
+
if (input.checkpoint && (input.checkpoint.harnessId !== "hermes" || input.checkpoint.nativeSessionId !== this.options.nativeSessionId))
|
|
22887
|
+
throw new Error("Hermes checkpoint belongs to another session");
|
|
22888
|
+
const data = await this.#run({ operation: "derive", ...input });
|
|
22889
|
+
const ref = nativeSessionRefSchema.parse({
|
|
22890
|
+
harnessId: "hermes",
|
|
22891
|
+
nativeSessionId: data.sessionId,
|
|
22892
|
+
formatVersion: 1,
|
|
22893
|
+
locator: { transport: "gateway" }
|
|
22894
|
+
});
|
|
22895
|
+
if (typeof data.digest !== "string")
|
|
22896
|
+
throw new Error("Missing Hermes derived-history proof");
|
|
22897
|
+
this.#derived.set(ref.nativeSessionId, data.digest);
|
|
22898
|
+
return ref;
|
|
22899
|
+
}
|
|
22900
|
+
async discardDerived(ref) {
|
|
22901
|
+
const expectedDigest = this.#derived.get(ref.nativeSessionId);
|
|
22902
|
+
if (ref.harnessId !== "hermes" || ref.nativeSessionId === this.options.nativeSessionId || !expectedDigest)
|
|
22903
|
+
throw new HermesGatewayHistoryError("invalidRequest", "This history reader did not create the derived Hermes session");
|
|
22904
|
+
const result = await this.#run({
|
|
22905
|
+
operation: "discard",
|
|
22906
|
+
derivedSessionId: ref.nativeSessionId,
|
|
22907
|
+
expectedDigest
|
|
22908
|
+
});
|
|
22909
|
+
if (result.deleted === true)
|
|
22910
|
+
this.#derived.delete(ref.nativeSessionId);
|
|
22911
|
+
return result.deleted === true;
|
|
22912
|
+
}
|
|
22913
|
+
#run(input) {
|
|
22914
|
+
return new Promise((resolve, reject) => {
|
|
22915
|
+
const child = spawn4(this.options.python, ["-I", "-u", "-c", GATEWAY_HISTORY_SCRIPT], {
|
|
22916
|
+
cwd: this.options.cwd,
|
|
22917
|
+
env: { ...process.env, ...this.options.environment },
|
|
22918
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
22919
|
+
windowsHide: true
|
|
22920
|
+
});
|
|
22921
|
+
let stdout = "";
|
|
22922
|
+
const timer = setTimeout(() => {
|
|
22923
|
+
child.kill();
|
|
22924
|
+
reject(new Error("Hermes history operation timed out"));
|
|
22925
|
+
}, 3e4);
|
|
22926
|
+
child.on("error", () => {
|
|
22927
|
+
clearTimeout(timer);
|
|
22928
|
+
reject(new Error("Cannot start Hermes native history reader"));
|
|
22929
|
+
});
|
|
22930
|
+
child.stdout.on("data", (chunk) => {
|
|
22931
|
+
stdout += chunk.toString();
|
|
22932
|
+
if (stdout.length > 32 * 1024 * 1024) {
|
|
22933
|
+
child.kill();
|
|
22934
|
+
reject(new Error("Hermes native history exceeds the supported size"));
|
|
22935
|
+
}
|
|
22936
|
+
});
|
|
22937
|
+
child.stderr.resume();
|
|
22938
|
+
child.stdin.on("error", () => void 0);
|
|
22939
|
+
child.on("close", (code) => {
|
|
22940
|
+
clearTimeout(timer);
|
|
22941
|
+
if (code !== 0)
|
|
22942
|
+
return reject(new Error("Hermes native history operation failed; source history was not modified"));
|
|
22943
|
+
try {
|
|
22944
|
+
const value = record2(JSON.parse(stdout.trim()));
|
|
22945
|
+
const error51 = record2(value.error);
|
|
22946
|
+
if (["unsupported", "checkpointNotFound", "invalidState"].includes(String(error51.code))) {
|
|
22947
|
+
reject(new HermesGatewayHistoryError(error51.code, String(error51.message)));
|
|
22948
|
+
} else
|
|
22949
|
+
resolve(value);
|
|
22950
|
+
} catch {
|
|
22951
|
+
reject(new Error("Malformed Hermes native history response"));
|
|
22952
|
+
}
|
|
22953
|
+
});
|
|
22954
|
+
child.stdin.end(JSON.stringify({ ...input, sessionId: this.options.nativeSessionId }));
|
|
22955
|
+
});
|
|
22956
|
+
}
|
|
22957
|
+
};
|
|
22958
|
+
|
|
22959
|
+
// dist/gateway-session-transport.js
|
|
22960
|
+
var hermesGatewayThinkingOptions = [
|
|
22961
|
+
"none",
|
|
22962
|
+
"minimal",
|
|
22963
|
+
"low",
|
|
22964
|
+
"medium",
|
|
22965
|
+
"high",
|
|
22966
|
+
"xhigh",
|
|
22967
|
+
"max",
|
|
22968
|
+
"ultra"
|
|
22969
|
+
].map((id) => ({ id: harnessThinkingOptionIdSchema.parse(id), label: id }));
|
|
22970
|
+
function question(entry, fallbackId) {
|
|
22971
|
+
const id = gatewayString(entry.qid) || fallbackId;
|
|
22972
|
+
const prompt = gatewayString(entry.question);
|
|
22973
|
+
if (!prompt)
|
|
22974
|
+
throw new Error("Hermes clarify request has no question");
|
|
22975
|
+
const choices = Array.isArray(entry.choices) ? entry.choices.filter((choice) => typeof choice === "string") : [];
|
|
22976
|
+
return choices.length ? {
|
|
22977
|
+
id,
|
|
22978
|
+
type: "choice",
|
|
22979
|
+
prompt,
|
|
22980
|
+
options: choices.map((value) => ({ value, label: value })),
|
|
22981
|
+
multiple: entry.multi_select === true,
|
|
22982
|
+
allowOther: true,
|
|
22983
|
+
optional: false
|
|
22984
|
+
} : { id, type: "text", prompt, multiline: true, secret: false, optional: false };
|
|
22985
|
+
}
|
|
22986
|
+
function gatewayDiff(text2) {
|
|
22987
|
+
if (!text2 || text2.length > 1024 * 1024)
|
|
22988
|
+
return [];
|
|
22989
|
+
const result = [];
|
|
22990
|
+
let path7 = "";
|
|
22991
|
+
let inHunk = false;
|
|
22992
|
+
let oldLines = [], newLines = [];
|
|
22993
|
+
const flush = () => {
|
|
22994
|
+
if (path7)
|
|
22995
|
+
result.push({
|
|
22996
|
+
type: "diff",
|
|
22997
|
+
path: path7,
|
|
22998
|
+
oldText: oldLines.join("\n"),
|
|
22999
|
+
newText: newLines.join("\n")
|
|
23000
|
+
});
|
|
23001
|
+
oldLines = [];
|
|
23002
|
+
newLines = [];
|
|
23003
|
+
};
|
|
23004
|
+
for (const raw of text2.split("\n")) {
|
|
23005
|
+
const line = raw.replace(/\u001b\[[0-9;]*m/gu, "");
|
|
23006
|
+
const header = /^(a\/.+|\/dev\/null) → (b\/.+|\/dev\/null)$/u.exec(line);
|
|
23007
|
+
if (header) {
|
|
23008
|
+
flush();
|
|
23009
|
+
inHunk = false;
|
|
23010
|
+
path7 = (header[2] === "/dev/null" ? header[1] ?? "" : header[2] ?? "").replace(/^[ab]\//u, "");
|
|
23011
|
+
continue;
|
|
23012
|
+
}
|
|
23013
|
+
if (line.startsWith("--- ") && !inHunk) {
|
|
23014
|
+
flush();
|
|
23015
|
+
path7 = line.slice(4).replace(/^a\//u, "");
|
|
23016
|
+
} else if (line.startsWith("+++ ") && !inHunk) {
|
|
23017
|
+
const next = line.slice(4);
|
|
23018
|
+
if (next !== "/dev/null")
|
|
23019
|
+
path7 = next.replace(/^b\//u, "");
|
|
23020
|
+
} else if (line.startsWith("@@")) {
|
|
23021
|
+
inHunk = true;
|
|
23022
|
+
continue;
|
|
23023
|
+
} else if (path7 && line.startsWith("-"))
|
|
23024
|
+
oldLines.push(line.slice(1));
|
|
23025
|
+
else if (path7 && line.startsWith("+"))
|
|
23026
|
+
newLines.push(line.slice(1));
|
|
23027
|
+
else if (path7 && line.startsWith(" ")) {
|
|
23028
|
+
oldLines.push(line.slice(1));
|
|
23029
|
+
newLines.push(line.slice(1));
|
|
23030
|
+
}
|
|
23031
|
+
}
|
|
23032
|
+
flush();
|
|
23033
|
+
return result;
|
|
23034
|
+
}
|
|
23035
|
+
var HermesGatewaySessionTransport = class {
|
|
23036
|
+
transport;
|
|
23037
|
+
sessionId;
|
|
23038
|
+
nativeSessionId;
|
|
23039
|
+
onFault = () => void 0;
|
|
23040
|
+
availableCommands = HERMES_GATEWAY_COMMANDS;
|
|
23041
|
+
history;
|
|
23042
|
+
#active = null;
|
|
23043
|
+
#requests = /* @__PURE__ */ new Map();
|
|
23044
|
+
#closed = false;
|
|
23045
|
+
#info;
|
|
23046
|
+
constructor(transport, sessionId, nativeSessionId, info) {
|
|
23047
|
+
this.transport = transport;
|
|
23048
|
+
this.sessionId = sessionId;
|
|
23049
|
+
this.nativeSessionId = nativeSessionId;
|
|
23050
|
+
this.#info = info;
|
|
23051
|
+
this.history = new HermesGatewayHistory({
|
|
23052
|
+
python: transport.python,
|
|
23053
|
+
cwd: transport.cwd,
|
|
23054
|
+
environment: transport.environment,
|
|
23055
|
+
nativeSessionId
|
|
23056
|
+
});
|
|
23057
|
+
transport.onEvent = (event) => this.#event(event);
|
|
23058
|
+
transport.onRequest = (id, method, params) => {
|
|
23059
|
+
void this.#request(id, method, params).catch((error51) => this.#fault(error51));
|
|
23060
|
+
};
|
|
23061
|
+
transport.onFault = (error51) => this.#fault(error51);
|
|
23062
|
+
}
|
|
23063
|
+
async openResult() {
|
|
23064
|
+
const reasoning = await this.transport.request("config.get", {
|
|
23065
|
+
key: "reasoning",
|
|
23066
|
+
session_id: this.sessionId
|
|
23067
|
+
});
|
|
23068
|
+
const currentThinkingOptionId = gatewayString(reasoning.value);
|
|
23069
|
+
const model = gatewayString(this.#info.model);
|
|
23070
|
+
const provider = gatewayString(this.#info.provider);
|
|
23071
|
+
const currentModelId = provider ? `${provider}:${model}` : model;
|
|
23072
|
+
return {
|
|
23073
|
+
initialize: { protocolVersion: 1 },
|
|
23074
|
+
sessionId: this.nativeSessionId,
|
|
23075
|
+
replay: [],
|
|
23076
|
+
session: {
|
|
23077
|
+
sessionId: this.nativeSessionId,
|
|
23078
|
+
models: currentModelId ? {
|
|
23079
|
+
currentModelId,
|
|
23080
|
+
availableModels: [
|
|
23081
|
+
{ modelId: currentModelId, name: provider ? `${provider} / ${model}` : model }
|
|
23082
|
+
]
|
|
23083
|
+
} : null,
|
|
23084
|
+
modes: {
|
|
23085
|
+
currentModeId: this.#info.yolo === true ? "dont_ask" : "default",
|
|
23086
|
+
availableModes: [
|
|
23087
|
+
{ id: "default", name: "Native approval policy" },
|
|
23088
|
+
{ id: "dont_ask", name: "Session YOLO" }
|
|
23089
|
+
]
|
|
23090
|
+
},
|
|
23091
|
+
thinkingOptions: hermesGatewayThinkingOptions,
|
|
23092
|
+
...hermesGatewayThinkingOptions.some(({ id }) => id === currentThinkingOptionId) ? { currentThinkingOptionId } : {}
|
|
23093
|
+
}
|
|
23094
|
+
};
|
|
23095
|
+
}
|
|
23096
|
+
async readNativeSnapshot() {
|
|
23097
|
+
return this.history.readSnapshot();
|
|
23098
|
+
}
|
|
23099
|
+
async setThinking(optionId) {
|
|
23100
|
+
if (!hermesGatewayThinkingOptions.some(({ id }) => id === optionId))
|
|
23101
|
+
throw new Error("Unsupported Hermes reasoning effort");
|
|
23102
|
+
const result = await this.transport.request("config.set", {
|
|
23103
|
+
key: "reasoning",
|
|
23104
|
+
value: optionId,
|
|
23105
|
+
scope: "session",
|
|
23106
|
+
session_id: this.sessionId
|
|
23107
|
+
});
|
|
23108
|
+
if (result.value !== optionId || (await this.transport.request("config.get", { key: "reasoning", session_id: this.sessionId })).value !== optionId)
|
|
23109
|
+
throw new Error("Hermes did not confirm reasoning selection");
|
|
23110
|
+
return optionId;
|
|
23111
|
+
}
|
|
23112
|
+
async setModel(modelId) {
|
|
23113
|
+
if (/\s/u.test(modelId) || modelId.startsWith("-"))
|
|
23114
|
+
throw new Error("Invalid Hermes Model identifier");
|
|
23115
|
+
const result = await this.transport.request("config.set", {
|
|
23116
|
+
key: "model",
|
|
23117
|
+
value: modelId,
|
|
23118
|
+
scope: "session",
|
|
23119
|
+
session_id: this.sessionId
|
|
23120
|
+
});
|
|
23121
|
+
if (result.confirm_required === true)
|
|
23122
|
+
throw new Error(gatewayString(result.confirm_message) || "Hermes requires confirmation for this Model");
|
|
23123
|
+
const actualModel = gatewayString(this.#info.model);
|
|
23124
|
+
const actualProvider = gatewayString(this.#info.provider);
|
|
23125
|
+
if (modelId !== actualModel && modelId !== `${actualProvider}:${actualModel}`)
|
|
23126
|
+
throw new Error("Hermes did not confirm the requested Model");
|
|
23127
|
+
}
|
|
23128
|
+
async setPermissionMode(modeId) {
|
|
23129
|
+
if (modeId !== "default" && modeId !== "dont_ask")
|
|
23130
|
+
throw new Error("Hermes gateway has no accept_edits mode");
|
|
23131
|
+
const result = await this.transport.request("config.set", {
|
|
23132
|
+
key: "yolo",
|
|
23133
|
+
value: modeId === "dont_ask" ? "on" : "off",
|
|
23134
|
+
scope: "session",
|
|
23135
|
+
session_id: this.sessionId
|
|
23136
|
+
});
|
|
23137
|
+
if (result.value !== (modeId === "dont_ask" ? "1" : "0") || this.#info.yolo !== (modeId === "dont_ask"))
|
|
23138
|
+
throw new Error("Hermes effective approval policy differs from the requested mode; check native global approvals policy");
|
|
23139
|
+
}
|
|
23140
|
+
nativeCommandName(text2) {
|
|
23141
|
+
const commandText = text2.trim();
|
|
23142
|
+
if (/^\/compress(?:\s|$)/iu.test(commandText))
|
|
23143
|
+
return "compress";
|
|
23144
|
+
return /^\/(help|tools|context|version)$/iu.exec(commandText)?.[1]?.toLowerCase() ?? null;
|
|
23145
|
+
}
|
|
23146
|
+
async runTurn(text2, emit, permission, question2) {
|
|
23147
|
+
if (this.#active || this.#closed)
|
|
23148
|
+
throw new Error("Hermes gateway Session is unavailable");
|
|
23149
|
+
let resolveResult = () => void 0;
|
|
23150
|
+
let rejectResult = () => void 0;
|
|
23151
|
+
const result = new Promise((resolve, reject) => {
|
|
23152
|
+
resolveResult = resolve;
|
|
23153
|
+
rejectResult = reject;
|
|
23154
|
+
});
|
|
23155
|
+
void result.catch(() => void 0);
|
|
23156
|
+
const active = {
|
|
23157
|
+
emit,
|
|
23158
|
+
permission,
|
|
23159
|
+
...question2 ? { question: question2 } : {},
|
|
23160
|
+
resolve: resolveResult,
|
|
23161
|
+
reject: rejectResult,
|
|
23162
|
+
streamed: "",
|
|
23163
|
+
reasoning: "",
|
|
23164
|
+
toolIds: /* @__PURE__ */ new Set()
|
|
23165
|
+
};
|
|
23166
|
+
this.#active = active;
|
|
23167
|
+
const commandText = text2.trim();
|
|
23168
|
+
const nativeCommand = this.nativeCommandName(text2);
|
|
23169
|
+
try {
|
|
23170
|
+
if (nativeCommand === "compress") {
|
|
23171
|
+
const compact = await this.transport.request("session.compress", { session_id: this.sessionId, focus_topic: commandText.slice(9).trim() }, 3e5);
|
|
23172
|
+
const summary = gatewayRecord(compact.summary);
|
|
23173
|
+
const explanation = [summary.headline, summary.token_line, summary.note, compact.message].filter((value) => typeof value === "string" && !!value).join("\n");
|
|
23174
|
+
if (explanation)
|
|
23175
|
+
emit({ type: "agent.text", text: explanation });
|
|
23176
|
+
if (compact.status === "pending") {
|
|
23177
|
+
this.#fault(new Error("Hermes compression remains pending; Session closed to prevent overlapping native work"));
|
|
23178
|
+
return await result;
|
|
23179
|
+
}
|
|
23180
|
+
if (!["compressed", "aborted"].includes(String(compact.status)) && compact.lock_held !== true)
|
|
23181
|
+
throw new Error("Hermes returned an unrecognized compression outcome");
|
|
23182
|
+
this.#usage(gatewayRecord(compact.usage));
|
|
23183
|
+
const succeeded = compact.status === "compressed" && summary.noop !== true;
|
|
23184
|
+
active.resolve({
|
|
23185
|
+
stopReason: "end_turn",
|
|
23186
|
+
compactionOutcome: compact.status === "aborted" || summary.aborted === true ? {
|
|
23187
|
+
status: "failed",
|
|
23188
|
+
error: {
|
|
23189
|
+
code: "nativeFailure",
|
|
23190
|
+
message: explanation || "Hermes summary generation failed",
|
|
23191
|
+
retryable: true
|
|
23192
|
+
}
|
|
23193
|
+
} : succeeded ? { status: "succeeded" } : { status: "cancelled", reason: explanation || "Hermes did not compact context" }
|
|
23194
|
+
});
|
|
23195
|
+
} else if (nativeCommand) {
|
|
23196
|
+
const response = await this.transport.request("slash.exec", {
|
|
23197
|
+
session_id: this.sessionId,
|
|
23198
|
+
command: `/${nativeCommand}`
|
|
23199
|
+
});
|
|
23200
|
+
emit({ type: "agent.text", text: gatewayString(response.output) });
|
|
23201
|
+
active.resolve({ stopReason: "end_turn" });
|
|
23202
|
+
} else {
|
|
23203
|
+
const submitted = await this.transport.request("prompt.submit", {
|
|
23204
|
+
session_id: this.sessionId,
|
|
23205
|
+
text: text2
|
|
23206
|
+
});
|
|
23207
|
+
if (submitted.status !== "streaming")
|
|
23208
|
+
this.#fault(new Error(`Hermes did not start an exclusive turn (${String(submitted.status)})`));
|
|
23209
|
+
}
|
|
23210
|
+
} catch (error51) {
|
|
23211
|
+
active.reject(error51 instanceof Error ? error51 : new Error(String(error51)));
|
|
23212
|
+
}
|
|
23213
|
+
try {
|
|
23214
|
+
return await result;
|
|
23215
|
+
} finally {
|
|
23216
|
+
if (this.#active === active)
|
|
23217
|
+
this.#active = null;
|
|
23218
|
+
for (const controller of this.#requests.values())
|
|
23219
|
+
controller.abort("cancelled");
|
|
23220
|
+
this.#requests.clear();
|
|
23221
|
+
}
|
|
23222
|
+
}
|
|
23223
|
+
async cancel() {
|
|
23224
|
+
await this.transport.request("session.interrupt", { session_id: this.sessionId });
|
|
23225
|
+
}
|
|
23226
|
+
async close() {
|
|
23227
|
+
if (this.#closed)
|
|
23228
|
+
return;
|
|
23229
|
+
this.#closed = true;
|
|
23230
|
+
for (const controller of this.#requests.values())
|
|
23231
|
+
controller.abort("cancelled");
|
|
23232
|
+
this.#requests.clear();
|
|
23233
|
+
this.#active?.reject(new Error("Hermes gateway Session closed"));
|
|
23234
|
+
try {
|
|
23235
|
+
await this.transport.request("session.close", { session_id: this.sessionId });
|
|
23236
|
+
} catch {
|
|
23237
|
+
}
|
|
23238
|
+
await this.transport.close();
|
|
23239
|
+
}
|
|
23240
|
+
#fault(error51) {
|
|
23241
|
+
if (this.#closed)
|
|
23242
|
+
return;
|
|
23243
|
+
this.#closed = true;
|
|
23244
|
+
for (const controller of this.#requests.values())
|
|
23245
|
+
controller.abort("cancelled");
|
|
23246
|
+
this.#requests.clear();
|
|
23247
|
+
const fault = new HermesTransportError("protocolError", error51 instanceof Error ? error51.message : String(error51));
|
|
23248
|
+
this.#active?.reject(fault);
|
|
23249
|
+
this.onFault(fault);
|
|
23250
|
+
void this.transport.close();
|
|
23251
|
+
}
|
|
23252
|
+
#event(event) {
|
|
23253
|
+
if (event.session_id !== this.sessionId || this.#closed)
|
|
23254
|
+
return;
|
|
23255
|
+
const payload = gatewayRecord(event.payload);
|
|
23256
|
+
if (event.type === "session.info") {
|
|
23257
|
+
this.#info = payload;
|
|
23258
|
+
return;
|
|
23259
|
+
}
|
|
23260
|
+
if (event.type === "request.cancel") {
|
|
23261
|
+
const controller = this.#requests.get(gatewayString(payload.id));
|
|
23262
|
+
controller?.abort(payload.reason === "timeout" ? "expired" : "cancelled");
|
|
23263
|
+
return;
|
|
23264
|
+
}
|
|
23265
|
+
const active = this.#active;
|
|
23266
|
+
if (!active) {
|
|
23267
|
+
if (event.type === "error")
|
|
23268
|
+
this.#fault(new Error(gatewayString(payload.message)));
|
|
23269
|
+
return;
|
|
23270
|
+
}
|
|
23271
|
+
const text2 = gatewayString(payload.text);
|
|
23272
|
+
if (event.type === "message.delta") {
|
|
23273
|
+
active.streamed += text2;
|
|
23274
|
+
active.emit({ type: "agent.text", text: text2 });
|
|
23275
|
+
} else if (event.type === "reasoning.delta" || event.type === "reasoning.available") {
|
|
23276
|
+
if (event.type === "reasoning.delta" || !active.reasoning) {
|
|
23277
|
+
active.reasoning += text2;
|
|
23278
|
+
active.emit({ type: "agent.thought", text: text2 });
|
|
23279
|
+
}
|
|
23280
|
+
} else if (event.type === "message.interim") {
|
|
23281
|
+
if (payload.already_streamed !== true)
|
|
23282
|
+
active.emit({ type: "agent.text", text: text2 });
|
|
23283
|
+
active.streamed = "";
|
|
23284
|
+
active.reasoning = "";
|
|
23285
|
+
} else if (event.type === "session.usage")
|
|
23286
|
+
this.#usage(gatewayRecord(payload.usage));
|
|
23287
|
+
else if (event.type === "tool.start" || event.type === "tool.complete") {
|
|
23288
|
+
const toolCallId = gatewayString(payload.tool_id);
|
|
23289
|
+
if (!toolCallId)
|
|
23290
|
+
return;
|
|
23291
|
+
const result = gatewayRecord(payload.result);
|
|
23292
|
+
const output = payload.result !== void 0 ? typeof payload.result === "string" ? payload.result : JSON.stringify(payload.result) : gatewayString(payload.result_text) || gatewayString(payload.summary);
|
|
23293
|
+
const content = [
|
|
23294
|
+
...output ? [{ type: "content", content: { type: "text", text: output } }] : [],
|
|
23295
|
+
...gatewayDiff(gatewayString(payload.inline_diff))
|
|
23296
|
+
];
|
|
23297
|
+
if (event.type === "tool.complete" && !active.toolIds.has(toolCallId))
|
|
23298
|
+
active.emit({
|
|
23299
|
+
type: "tool.call",
|
|
23300
|
+
toolCallId,
|
|
23301
|
+
update: {
|
|
23302
|
+
sessionUpdate: "tool_call",
|
|
23303
|
+
toolCallId,
|
|
23304
|
+
title: gatewayString(payload.name),
|
|
23305
|
+
rawInput: payload.args,
|
|
23306
|
+
status: "in_progress"
|
|
23307
|
+
}
|
|
23308
|
+
});
|
|
23309
|
+
active.toolIds.add(toolCallId);
|
|
23310
|
+
active.emit(event.type === "tool.start" ? {
|
|
23311
|
+
type: "tool.call",
|
|
23312
|
+
toolCallId,
|
|
23313
|
+
update: {
|
|
23314
|
+
sessionUpdate: "tool_call",
|
|
23315
|
+
toolCallId,
|
|
23316
|
+
title: gatewayString(payload.name),
|
|
23317
|
+
rawInput: payload.args,
|
|
23318
|
+
status: "in_progress"
|
|
23319
|
+
}
|
|
23320
|
+
} : {
|
|
23321
|
+
type: "tool.update",
|
|
23322
|
+
toolCallId,
|
|
23323
|
+
update: {
|
|
23324
|
+
sessionUpdate: "tool_call_update",
|
|
23325
|
+
toolCallId,
|
|
23326
|
+
status: result.error || result.is_error === true || result.success === false ? "failed" : "completed",
|
|
23327
|
+
content
|
|
23328
|
+
}
|
|
23329
|
+
});
|
|
23330
|
+
} else if (event.type === "message.complete") {
|
|
23331
|
+
if (!active.streamed)
|
|
23332
|
+
active.emit({ type: "agent.text", text: text2 });
|
|
23333
|
+
else if (text2.startsWith(active.streamed) && text2.length > active.streamed.length)
|
|
23334
|
+
active.emit({ type: "agent.text", text: text2.slice(active.streamed.length) });
|
|
23335
|
+
const reasoning = gatewayString(payload.reasoning);
|
|
23336
|
+
if (reasoning && !active.reasoning)
|
|
23337
|
+
active.emit({ type: "agent.thought", text: reasoning });
|
|
23338
|
+
else if (reasoning.startsWith(active.reasoning) && reasoning.length > active.reasoning.length)
|
|
23339
|
+
active.emit({ type: "agent.thought", text: reasoning.slice(active.reasoning.length) });
|
|
23340
|
+
const usage = gatewayRecord(payload.usage);
|
|
23341
|
+
this.#usage(usage);
|
|
23342
|
+
if (payload.status === "error")
|
|
23343
|
+
active.reject(new Error(gatewayString(payload.error) || gatewayString(payload.failure_reason) || "Hermes turn failed"));
|
|
23344
|
+
else
|
|
23345
|
+
active.resolve({
|
|
23346
|
+
stopReason: payload.status === "interrupted" ? "cancelled" : "end_turn",
|
|
23347
|
+
usage: {
|
|
23348
|
+
inputTokens: Number(usage.input) || 0,
|
|
23349
|
+
outputTokens: Number(usage.output) || 0,
|
|
23350
|
+
totalTokens: Number(usage.total) || 0,
|
|
23351
|
+
...typeof usage.reasoning === "number" ? { thoughtTokens: usage.reasoning } : {}
|
|
23352
|
+
}
|
|
23353
|
+
});
|
|
23354
|
+
} else if (event.type === "error")
|
|
23355
|
+
active.reject(new Error(gatewayString(payload.message) || "Hermes gateway failed"));
|
|
23356
|
+
}
|
|
23357
|
+
#usage(usage) {
|
|
23358
|
+
this.#active?.emit({
|
|
23359
|
+
type: "usage",
|
|
23360
|
+
...typeof usage.context_used === "number" ? { used: usage.context_used } : {},
|
|
23361
|
+
...typeof usage.context_max === "number" ? { size: usage.context_max } : {}
|
|
23362
|
+
});
|
|
23363
|
+
}
|
|
23364
|
+
async #request(id, method, params) {
|
|
23365
|
+
const active = this.#active;
|
|
23366
|
+
if (!active || params.session_id !== this.sessionId || !["clarify", "approval"].includes(method)) {
|
|
23367
|
+
this.transport.rejectRequest(id);
|
|
23368
|
+
return;
|
|
23369
|
+
}
|
|
23370
|
+
const controller = new AbortController();
|
|
23371
|
+
this.#requests.set(id, controller);
|
|
23372
|
+
try {
|
|
23373
|
+
if (method === "clarify" && active.question) {
|
|
23374
|
+
const batch = Array.isArray(params.questions);
|
|
23375
|
+
const questions = batch ? params.questions.map((value, index) => question(gatewayRecord(value), String(index))) : [question(params, "answer")];
|
|
23376
|
+
const response = await active.question({
|
|
23377
|
+
title: "Hermes",
|
|
23378
|
+
questions,
|
|
23379
|
+
signal: controller.signal
|
|
23380
|
+
});
|
|
23381
|
+
if (!controller.signal.aborted) {
|
|
23382
|
+
const answers = Object.fromEntries(Object.entries(response.answers).map(([key, values]) => {
|
|
23383
|
+
const q = questions.find((entry) => entry.id === key);
|
|
23384
|
+
return [
|
|
23385
|
+
key,
|
|
23386
|
+
q?.type === "choice" && q.multiple ? JSON.stringify(values) : values[0] ?? ""
|
|
23387
|
+
];
|
|
23388
|
+
}));
|
|
23389
|
+
this.transport.respond(id, response.cancelled ? {} : batch ? { answers } : { answer: answers.answer ?? "" });
|
|
23390
|
+
}
|
|
23391
|
+
} else if (method === "approval") {
|
|
23392
|
+
const choices = Array.isArray(params.choices) ? params.choices : ["once", "deny"];
|
|
23393
|
+
const options = choices.flatMap((choice) => choice === "once" ? [{ optionId: "once", kind: "allow_once", name: "Allow once" }] : choice === "session" || choice === "always" ? [
|
|
23394
|
+
{
|
|
23395
|
+
optionId: choice,
|
|
23396
|
+
kind: "allow_always",
|
|
23397
|
+
name: choice === "session" ? "Allow for this session" : "Always allow"
|
|
23398
|
+
}
|
|
23399
|
+
] : choice === "deny" ? [{ optionId: "deny", kind: "reject_once", name: "Deny" }] : []);
|
|
23400
|
+
const response = await active.permission({
|
|
23401
|
+
signal: controller.signal,
|
|
23402
|
+
effects: { session: "allowForSession", always: "allowAlways" },
|
|
23403
|
+
description: gatewayString(params.command) || gatewayString(params.description),
|
|
23404
|
+
request: {
|
|
23405
|
+
sessionId: this.nativeSessionId,
|
|
23406
|
+
toolCall: {
|
|
23407
|
+
toolCallId: gatewayString(params.request_id),
|
|
23408
|
+
title: gatewayString(params.description) || gatewayString(params.command)
|
|
23409
|
+
},
|
|
23410
|
+
options
|
|
23411
|
+
},
|
|
23412
|
+
options
|
|
23413
|
+
});
|
|
23414
|
+
if (!controller.signal.aborted)
|
|
23415
|
+
this.transport.respond(id, {
|
|
23416
|
+
choice: response.outcome.outcome === "selected" ? response.outcome.optionId : "deny"
|
|
23417
|
+
});
|
|
23418
|
+
} else
|
|
23419
|
+
this.transport.rejectRequest(id);
|
|
23420
|
+
} finally {
|
|
23421
|
+
this.#requests.delete(id);
|
|
23422
|
+
}
|
|
23423
|
+
}
|
|
23424
|
+
};
|
|
23425
|
+
|
|
23426
|
+
// dist/gateway-open.js
|
|
23427
|
+
import path6 from "node:path";
|
|
23428
|
+
import { realpath } from "node:fs/promises";
|
|
23429
|
+
|
|
23430
|
+
// dist/gateway-configuration.js
|
|
23431
|
+
import { execFile } from "node:child_process";
|
|
23432
|
+
import { promisify } from "node:util";
|
|
23433
|
+
async function resolveGatewayModel(transport, modelId) {
|
|
23434
|
+
if (/\s/u.test(modelId) || modelId.startsWith("-"))
|
|
23435
|
+
throw new Error("Invalid Hermes Model identifier");
|
|
23436
|
+
const result = await promisify(execFile)(transport.python, [
|
|
23437
|
+
"-I",
|
|
23438
|
+
"-c",
|
|
23439
|
+
"import json,sys\nfrom hermes_cli.models import parse_model_input\np,m=parse_model_input(sys.argv[1], '')\nprint(json.dumps({'provider':p,'model':m}))",
|
|
23440
|
+
modelId
|
|
23441
|
+
], {
|
|
23442
|
+
cwd: transport.cwd,
|
|
23443
|
+
env: { ...process.env, ...transport.environment },
|
|
23444
|
+
timeout: 2e4,
|
|
23445
|
+
maxBuffer: 1024 * 1024
|
|
23446
|
+
});
|
|
23447
|
+
const value = JSON.parse(result.stdout.trim());
|
|
23448
|
+
if (!value || typeof value !== "object" || !("provider" in value) || !("model" in value) || typeof value.provider !== "string" || typeof value.model !== "string")
|
|
23449
|
+
throw new Error("Hermes returned an invalid Model choice");
|
|
23450
|
+
return { provider: value.provider, model: value.model };
|
|
23451
|
+
}
|
|
23452
|
+
|
|
23453
|
+
// dist/gateway-open.js
|
|
23454
|
+
async function sameDirectory(left, right) {
|
|
23455
|
+
return await realpath(left).catch(() => path6.resolve(left)) === await realpath(right).catch(() => path6.resolve(right));
|
|
23456
|
+
}
|
|
23457
|
+
var gatewayCapabilities = {
|
|
23458
|
+
configuration: {
|
|
23459
|
+
selectModel: true,
|
|
23460
|
+
selectThinkingOption: true,
|
|
23461
|
+
selectPermissionMode: true,
|
|
23462
|
+
permissionModeScope: "live"
|
|
23463
|
+
},
|
|
23464
|
+
history: { fork: true, forkAcrossCwd: false, rollbackLastTurn: true }
|
|
23465
|
+
};
|
|
23466
|
+
function gatewayPermissionModes() {
|
|
23467
|
+
return harnessPermissionModeCatalogSchema.parse({
|
|
23468
|
+
modes: [
|
|
23469
|
+
{
|
|
23470
|
+
id: "default",
|
|
23471
|
+
label: "原生审批策略",
|
|
23472
|
+
description: "遵循 Hermes 全局审批策略,关闭本会话 YOLO。"
|
|
23473
|
+
},
|
|
23474
|
+
{
|
|
23475
|
+
id: "dont_ask",
|
|
23476
|
+
label: "会话 YOLO",
|
|
23477
|
+
description: "本会话自动批准 Hermes 工具操作。",
|
|
23478
|
+
dangerous: true
|
|
23479
|
+
}
|
|
23480
|
+
],
|
|
23481
|
+
defaultModeId: "default"
|
|
23482
|
+
});
|
|
23483
|
+
}
|
|
23484
|
+
function isGatewayRef(ref) {
|
|
23485
|
+
return ref.harnessId === "hermes" && gatewayRecord(ref.locator).transport === "gateway";
|
|
23486
|
+
}
|
|
23487
|
+
async function openGatewaySession(input, transport, onSettle, inheritedPermissionMode) {
|
|
23488
|
+
const source = input.kind === "create" ? null : input.kind === "resume" ? input.nativeRef : input.sourceRef;
|
|
23489
|
+
if (source && !isGatewayRef(source))
|
|
23490
|
+
throw new HermesGatewayHistoryError("unsupported", "This Hermes native reference is not a supported gateway Session");
|
|
23491
|
+
const savedMode = source ? gatewayRecord(source.locator).permissionModeId : void 0;
|
|
23492
|
+
const mode = (input.kind === "fork" ? inheritedPermissionMode : input.permissionModeId) ?? (typeof savedMode === "string" ? savedMode : void 0);
|
|
23493
|
+
if (mode && mode !== "default" && mode !== "dont_ask")
|
|
23494
|
+
throw new HermesGatewayHistoryError("unsupported", "Hermes gateway supports native policy and session YOLO; accept_edits remains ACP-only");
|
|
23495
|
+
if (input.kind === "create" && input.executionPolicy === "unattended-full-access" && mode && mode !== "dont_ask")
|
|
23496
|
+
throw new HermesGatewayHistoryError("invalidRequest", "unattended-full-access requires dont_ask");
|
|
23497
|
+
const model = input.kind !== "fork" && input.model ? decodeHermesModelRefId(input.model.id) : null;
|
|
23498
|
+
if (input.kind !== "fork" && input.model && !model)
|
|
23499
|
+
throw new HermesGatewayHistoryError("invalidRequest", "Model Ref does not belong to Hermes");
|
|
23500
|
+
if (source && gatewayRecord(source.locator).cwd && !await sameDirectory(String(gatewayRecord(source?.locator).cwd), input.cwd))
|
|
23501
|
+
throw new HermesGatewayHistoryError("unsupported", "Hermes gateway preserves the native Session working directory");
|
|
23502
|
+
let nativeRef = source;
|
|
23503
|
+
let sourceHistory;
|
|
23504
|
+
try {
|
|
23505
|
+
await transport.prepareSession();
|
|
23506
|
+
await transport.start();
|
|
23507
|
+
if (source && (input.kind === "fork" || input.kind === "rollbackLastTurn")) {
|
|
23508
|
+
sourceHistory = new HermesGatewayHistory({
|
|
23509
|
+
python: transport.python,
|
|
23510
|
+
cwd: transport.cwd,
|
|
23511
|
+
environment: transport.environment,
|
|
23512
|
+
nativeSessionId: source.nativeSessionId
|
|
23513
|
+
});
|
|
23514
|
+
nativeRef = await sourceHistory.derive(input.kind === "fork" ? { checkpoint: input.checkpoint } : { rollbackLastTurn: true });
|
|
23515
|
+
}
|
|
23516
|
+
const choice = model ? await resolveGatewayModel(transport, model) : null;
|
|
23517
|
+
const response = await transport.request(nativeRef ? "session.resume" : "session.create", nativeRef ? { session_id: nativeRef.nativeSessionId, eager_build: true, omit_messages: true } : {
|
|
23518
|
+
cwd: input.cwd,
|
|
23519
|
+
close_on_disconnect: true,
|
|
23520
|
+
...choice ? choice : {},
|
|
23521
|
+
...input.kind === "create" && input.thinkingOptionId ? { reasoning_effort: input.thinkingOptionId } : {}
|
|
23522
|
+
});
|
|
23523
|
+
const runtimeId = gatewayString(response.session_id);
|
|
23524
|
+
const storedId = nativeRef?.nativeSessionId || gatewayString(response.stored_session_id);
|
|
23525
|
+
if (!runtimeId || !storedId)
|
|
23526
|
+
throw new Error("Hermes gateway did not return Session identity");
|
|
23527
|
+
let info = gatewayRecord(response.info);
|
|
23528
|
+
if (info.lazy === true)
|
|
23529
|
+
info = await transport.waitForSession(runtimeId);
|
|
23530
|
+
const nativeCwd = gatewayString(info.cwd);
|
|
23531
|
+
if (nativeCwd && !await sameDirectory(nativeCwd, input.cwd))
|
|
23532
|
+
throw new HermesGatewayHistoryError("unsupported", "Hermes resumed a different native working directory");
|
|
23533
|
+
const bridge = new HermesGatewaySessionTransport(transport, runtimeId, storedId, info);
|
|
23534
|
+
if (!nativeRef)
|
|
23535
|
+
await bridge.history.ensureCreated({
|
|
23536
|
+
cwd: input.cwd,
|
|
23537
|
+
model: gatewayString(info.model),
|
|
23538
|
+
provider: gatewayString(info.provider),
|
|
23539
|
+
reasoningEffort: gatewayString(info.reasoning_effort)
|
|
23540
|
+
});
|
|
23541
|
+
const physicalId = await bridge.history.resolvePhysicalSessionId();
|
|
23542
|
+
if (gatewayString(info.stored_session_id) !== physicalId)
|
|
23543
|
+
throw new Error("Hermes live Session and persisted history identities differ");
|
|
23544
|
+
if (model)
|
|
23545
|
+
await bridge.setModel(model);
|
|
23546
|
+
if (input.kind !== "fork" && input.thinkingOptionId)
|
|
23547
|
+
await bridge.setThinking(input.thinkingOptionId);
|
|
23548
|
+
const desiredMode = input.kind === "create" && input.executionPolicy === "unattended-full-access" ? "dont_ask" : mode;
|
|
23549
|
+
if (desiredMode)
|
|
23550
|
+
await bridge.setPermissionMode(desiredMode);
|
|
23551
|
+
const open = await bridge.openResult();
|
|
23552
|
+
return new HermesSession({
|
|
23553
|
+
nativeRef: nativeSessionRefSchema.parse({
|
|
23554
|
+
harnessId: "hermes",
|
|
23555
|
+
nativeSessionId: storedId,
|
|
23556
|
+
formatVersion: 1,
|
|
23557
|
+
locator: {
|
|
23558
|
+
transport: "gateway",
|
|
23559
|
+
cwd: input.cwd,
|
|
23560
|
+
permissionModeId: open.session.modes?.currentModeId
|
|
23561
|
+
}
|
|
23562
|
+
}),
|
|
23563
|
+
transport: bridge,
|
|
23564
|
+
open,
|
|
23565
|
+
supportsDerivation: true,
|
|
23566
|
+
onSettle
|
|
23567
|
+
});
|
|
23568
|
+
} catch (error51) {
|
|
23569
|
+
await transport.close().catch(() => void 0);
|
|
23570
|
+
if (sourceHistory && nativeRef)
|
|
23571
|
+
await sourceHistory.discardDerived(nativeRef).catch(() => false);
|
|
23572
|
+
throw error51;
|
|
23573
|
+
}
|
|
23574
|
+
}
|
|
23575
|
+
|
|
21348
23576
|
// dist/hermes-adapter.js
|
|
21349
23577
|
var hermesHarnessId = harnessIdSchema.parse("hermes");
|
|
21350
23578
|
var IMPORT_TIMEOUT_MS = 2e4;
|
|
21351
23579
|
var HERMES_THREAD_ID_ENV = "CODEXHOST_THREAD_ID";
|
|
21352
23580
|
var HermesAdapter = class {
|
|
23581
|
+
commandCatalog = HERMES_COMMAND_CATALOG;
|
|
21353
23582
|
harnessId = hermesHarnessId;
|
|
21354
23583
|
sessionImport = {
|
|
21355
23584
|
listCandidates: () => this.#listImportCandidates(),
|
|
@@ -21357,11 +23586,16 @@ var HermesAdapter = class {
|
|
|
21357
23586
|
};
|
|
21358
23587
|
#options;
|
|
21359
23588
|
#inspectionCache = null;
|
|
23589
|
+
#lastInventory = null;
|
|
23590
|
+
#inventoryRead = null;
|
|
21360
23591
|
#inspectionCacheScope = null;
|
|
21361
23592
|
#sessions = /* @__PURE__ */ new Set();
|
|
21362
23593
|
#warmTransports = /* @__PURE__ */ new Map();
|
|
21363
23594
|
#transports = /* @__PURE__ */ new Set();
|
|
21364
23595
|
#closed = false;
|
|
23596
|
+
#gatewayTransports = /* @__PURE__ */ new Set();
|
|
23597
|
+
#gatewayProbes = /* @__PURE__ */ new Map();
|
|
23598
|
+
#openingNativeIds = /* @__PURE__ */ new Set();
|
|
21365
23599
|
constructor(options = {}) {
|
|
21366
23600
|
this.#options = options;
|
|
21367
23601
|
}
|
|
@@ -21371,6 +23605,29 @@ var HermesAdapter = class {
|
|
|
21371
23605
|
return this.#inspectionCache;
|
|
21372
23606
|
}
|
|
21373
23607
|
const environment = this.#effectiveEnvironment();
|
|
23608
|
+
if (input.refresh)
|
|
23609
|
+
this.#gatewayProbes.clear();
|
|
23610
|
+
const gatewayPython = await this.#gatewayPython(cwd, environment);
|
|
23611
|
+
if (gatewayPython) {
|
|
23612
|
+
try {
|
|
23613
|
+
const catalog = catalogModelsFromInventory(await this.#readInventory());
|
|
23614
|
+
const inspection = {
|
|
23615
|
+
status: "ready",
|
|
23616
|
+
catalog: {
|
|
23617
|
+
models: catalog.models.map(({ ref, label }) => ({ ref, label })),
|
|
23618
|
+
thinkingOptions: hermesGatewayThinkingOptions,
|
|
23619
|
+
...catalog.defaultModel ? { defaultModel: catalog.defaultModel } : {}
|
|
23620
|
+
},
|
|
23621
|
+
permissionModes: gatewayPermissionModes(),
|
|
23622
|
+
capabilities: gatewayCapabilities
|
|
23623
|
+
};
|
|
23624
|
+
this.#inspectionCache = inspection;
|
|
23625
|
+
this.#inspectionCacheScope = cwd;
|
|
23626
|
+
return inspection;
|
|
23627
|
+
} catch (error51) {
|
|
23628
|
+
return inspectionFromTransportError(error51);
|
|
23629
|
+
}
|
|
23630
|
+
}
|
|
21374
23631
|
const transport = await this.#takeTransport(cwd, environment);
|
|
21375
23632
|
let retainedForOpen = false;
|
|
21376
23633
|
try {
|
|
@@ -21415,13 +23672,26 @@ var HermesAdapter = class {
|
|
|
21415
23672
|
}
|
|
21416
23673
|
}
|
|
21417
23674
|
async #readInventory() {
|
|
23675
|
+
if (this.#inventoryRead)
|
|
23676
|
+
return this.#inventoryRead;
|
|
21418
23677
|
const executable = resolveHermesExecutable({
|
|
21419
23678
|
...this.#options.command ? { command: this.#options.command } : {},
|
|
21420
23679
|
...this.#options.environment ? { environment: this.#options.environment } : {}
|
|
21421
23680
|
});
|
|
21422
|
-
|
|
23681
|
+
this.#inventoryRead = readHermesModelInventory(executable, 2e4, {
|
|
21423
23682
|
...this.#options.environment ? { environment: this.#options.environment } : {}
|
|
23683
|
+
}).then((inventory) => {
|
|
23684
|
+
if (!this.#closed)
|
|
23685
|
+
this.#lastInventory = inventory;
|
|
23686
|
+
return inventory;
|
|
23687
|
+
}).catch((error51) => {
|
|
23688
|
+
if (error51 instanceof HermesInventoryTimeoutError && this.#lastInventory)
|
|
23689
|
+
return this.#lastInventory;
|
|
23690
|
+
throw error51;
|
|
23691
|
+
}).finally(() => {
|
|
23692
|
+
this.#inventoryRead = null;
|
|
21424
23693
|
});
|
|
23694
|
+
return this.#inventoryRead;
|
|
21425
23695
|
}
|
|
21426
23696
|
async open(input) {
|
|
21427
23697
|
if (this.#closed) {
|
|
@@ -21431,6 +23701,23 @@ var HermesAdapter = class {
|
|
|
21431
23701
|
if (typeof cwd !== "string" || cwd.trim().length === 0) {
|
|
21432
23702
|
return failure("invalidRequest", "open requires a cwd");
|
|
21433
23703
|
}
|
|
23704
|
+
const nativeRef = input.kind === "create" ? null : input.kind === "resume" ? input.nativeRef : input.sourceRef;
|
|
23705
|
+
const gatewayEnvironment = {
|
|
23706
|
+
...this.#options.environment ?? process.env,
|
|
23707
|
+
...input.environment ?? {}
|
|
23708
|
+
};
|
|
23709
|
+
const environment = this.#effectiveEnvironment(input.environment);
|
|
23710
|
+
if (input.kind === "resume" && (this.#openingNativeIds.has(input.nativeRef.nativeSessionId) || [...this.#sessions].some((s) => s.initialState.nativeRef?.nativeSessionId === input.nativeRef.nativeSessionId)))
|
|
23711
|
+
return failure("sessionBusy", "This Hermes Session already has an owner", true);
|
|
23712
|
+
if (!nativeRef || isGatewayRef(nativeRef)) {
|
|
23713
|
+
const python = await this.#gatewayPython(cwd, gatewayEnvironment);
|
|
23714
|
+
if (this.#closed)
|
|
23715
|
+
return failure("invalidState", "Hermes Adapter is closed");
|
|
23716
|
+
if (python)
|
|
23717
|
+
return this.#openGateway(input, python, gatewayEnvironment);
|
|
23718
|
+
if (nativeRef)
|
|
23719
|
+
return failure("unavailable", "Hermes gateway Session requires an available gateway with exclusive turn support");
|
|
23720
|
+
}
|
|
21434
23721
|
let transportOpen;
|
|
21435
23722
|
let permissionModeId;
|
|
21436
23723
|
if (input.kind === "create") {
|
|
@@ -21454,7 +23741,6 @@ var HermesAdapter = class {
|
|
|
21454
23741
|
if (permissionModeId && !isHermesModeId(permissionModeId)) {
|
|
21455
23742
|
return failure("invalidRequest", "Permission Mode does not belong to Hermes");
|
|
21456
23743
|
}
|
|
21457
|
-
const environment = this.#effectiveEnvironment(input.environment);
|
|
21458
23744
|
const transport = await this.#takeTransport(cwd, environment);
|
|
21459
23745
|
if (this.#closed) {
|
|
21460
23746
|
await this.#releaseTransport(transport);
|
|
@@ -21530,16 +23816,80 @@ var HermesAdapter = class {
|
|
|
21530
23816
|
return failure("nativeFailure", error51 instanceof Error ? error51.message : "Hermes Session open failed");
|
|
21531
23817
|
}
|
|
21532
23818
|
}
|
|
23819
|
+
async #gatewayPython(cwd, environment) {
|
|
23820
|
+
const key = `${cwd}:${this.#transportScope(cwd, environment)}`;
|
|
23821
|
+
let pending = this.#gatewayProbes.get(key);
|
|
23822
|
+
if (!pending) {
|
|
23823
|
+
pending = (async () => {
|
|
23824
|
+
try {
|
|
23825
|
+
return await HermesGatewayTransport.probe(resolveHermesExecutable({
|
|
23826
|
+
...this.#options.command ? { command: this.#options.command } : {},
|
|
23827
|
+
environment
|
|
23828
|
+
}), cwd, environment);
|
|
23829
|
+
} catch {
|
|
23830
|
+
return null;
|
|
23831
|
+
}
|
|
23832
|
+
})();
|
|
23833
|
+
this.#gatewayProbes.set(key, pending);
|
|
23834
|
+
}
|
|
23835
|
+
return pending;
|
|
23836
|
+
}
|
|
23837
|
+
async #openGateway(input, python, environment) {
|
|
23838
|
+
if (this.#closed)
|
|
23839
|
+
return failure("invalidState", "Hermes Adapter is closed");
|
|
23840
|
+
const ref = input.kind === "resume" ? input.nativeRef : null;
|
|
23841
|
+
if (input.kind === "fork" || input.kind === "rollbackLastTurn") {
|
|
23842
|
+
const source = [...this.#sessions].find((s) => s.initialState.nativeRef?.nativeSessionId === input.sourceRef.nativeSessionId);
|
|
23843
|
+
if (source?.busy)
|
|
23844
|
+
return failure("sessionBusy", "Cannot derive a Hermes Session while its source Turn is active", true);
|
|
23845
|
+
}
|
|
23846
|
+
const owned = (id) => this.#openingNativeIds.has(id) || [...this.#sessions].some((session) => session.initialState.nativeRef?.nativeSessionId === id);
|
|
23847
|
+
if (ref && owned(ref.nativeSessionId))
|
|
23848
|
+
return failure("sessionBusy", "This Hermes Session already has an owner", true);
|
|
23849
|
+
if (ref)
|
|
23850
|
+
this.#openingNativeIds.add(ref.nativeSessionId);
|
|
23851
|
+
const transport = new HermesGatewayTransport(python, input.cwd, environment, this.#options.commandTimeoutMs);
|
|
23852
|
+
this.#gatewayTransports.add(transport);
|
|
23853
|
+
try {
|
|
23854
|
+
let inheritedMode;
|
|
23855
|
+
if (input.kind === "fork") {
|
|
23856
|
+
const source = [...this.#sessions].find((s) => s.initialState.nativeRef?.nativeSessionId === input.sourceRef.nativeSessionId);
|
|
23857
|
+
const snapshot = await source?.readSnapshot();
|
|
23858
|
+
if (snapshot?.ok)
|
|
23859
|
+
inheritedMode = snapshot.value.state?.effectivePermissionModeId;
|
|
23860
|
+
}
|
|
23861
|
+
const session = await openGatewaySession(input, transport, (settled) => {
|
|
23862
|
+
this.#sessions.delete(settled);
|
|
23863
|
+
this.#gatewayTransports.delete(transport);
|
|
23864
|
+
}, inheritedMode);
|
|
23865
|
+
if (this.#closed) {
|
|
23866
|
+
await session.close();
|
|
23867
|
+
return failure("invalidState", "Hermes Adapter is closed");
|
|
23868
|
+
}
|
|
23869
|
+
this.#sessions.add(session);
|
|
23870
|
+
return { ok: true, value: session };
|
|
23871
|
+
} catch (error51) {
|
|
23872
|
+
await transport.close().catch(() => void 0);
|
|
23873
|
+
this.#gatewayTransports.delete(transport);
|
|
23874
|
+
return failure(error51 instanceof HermesGatewayHistoryError ? error51.code : "nativeFailure", error51 instanceof Error ? error51.message : "Hermes gateway open failed");
|
|
23875
|
+
} finally {
|
|
23876
|
+
if (ref)
|
|
23877
|
+
this.#openingNativeIds.delete(ref.nativeSessionId);
|
|
23878
|
+
}
|
|
23879
|
+
}
|
|
21533
23880
|
async close() {
|
|
21534
23881
|
if (this.#closed)
|
|
21535
23882
|
return;
|
|
21536
23883
|
this.#closed = true;
|
|
21537
23884
|
this.#inspectionCache = null;
|
|
23885
|
+
this.#lastInventory = null;
|
|
21538
23886
|
const sessions = [...this.#sessions];
|
|
21539
23887
|
this.#sessions.clear();
|
|
21540
23888
|
this.#warmTransports.clear();
|
|
21541
23889
|
await Promise.all(sessions.map((session) => session.close().catch(() => void 0)));
|
|
21542
23890
|
await Promise.all([...this.#transports].map((transport) => this.#releaseTransport(transport)));
|
|
23891
|
+
await Promise.all([...this.#gatewayTransports].map((transport) => transport.close()));
|
|
23892
|
+
this.#gatewayTransports.clear();
|
|
21543
23893
|
}
|
|
21544
23894
|
#effectiveEnvironment(environment) {
|
|
21545
23895
|
const merged = { ...this.#options.environment ?? process.env, ...environment ?? {} };
|