@gethmy/agent 1.46.0 → 1.47.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/dist/cli.js +150 -25
- package/dist/index.js +150 -25
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ npx @gethmy/mcp connect
|
|
|
50
50
|
"agent": {
|
|
51
51
|
"poolSize": 3,
|
|
52
52
|
"pickupColumns": ["To Do"],
|
|
53
|
-
"claude": { "model": "claude-opus-5", "escalateModel": "claude-fable-5-1", "reviewModel": "sonnet", "deepReviewModel": "sonnet" },
|
|
53
|
+
"claude": { "model": "claude-opus-5-5", "escalateModel": "claude-fable-5-1", "reviewModel": "sonnet", "deepReviewModel": "sonnet" },
|
|
54
54
|
"review": {
|
|
55
55
|
"enabled": true,
|
|
56
56
|
"poolSize": 2,
|
package/dist/cli.js
CHANGED
|
@@ -2572,6 +2572,9 @@ function untrustedDataBlock(text, options) {
|
|
|
2572
2572
|
`);
|
|
2573
2573
|
}
|
|
2574
2574
|
|
|
2575
|
+
// ../harmony-shared/src/xPostLink.ts
|
|
2576
|
+
var init_xPostLink = () => {};
|
|
2577
|
+
|
|
2575
2578
|
// ../harmony-shared/src/index.ts
|
|
2576
2579
|
var init_src = __esm(() => {
|
|
2577
2580
|
init_agentPauseAccounting();
|
|
@@ -2602,6 +2605,7 @@ var init_src = __esm(() => {
|
|
|
2602
2605
|
init_runRedaction();
|
|
2603
2606
|
init_stageHandoff();
|
|
2604
2607
|
init_sweepPresence();
|
|
2608
|
+
init_xPostLink();
|
|
2605
2609
|
});
|
|
2606
2610
|
|
|
2607
2611
|
// src/config-merge.ts
|
|
@@ -3566,12 +3570,12 @@ var init_types = __esm(() => {
|
|
|
3566
3570
|
postSummary: true
|
|
3567
3571
|
},
|
|
3568
3572
|
claude: {
|
|
3569
|
-
model: "claude-opus-5",
|
|
3573
|
+
model: "claude-opus-5-5",
|
|
3570
3574
|
escalateModel: "claude-fable-5-1",
|
|
3571
3575
|
escalateAfterAttempts: 2,
|
|
3572
3576
|
tiers: {
|
|
3573
3577
|
simple: "claude-sonnet-5",
|
|
3574
|
-
advanced: "claude-opus-5",
|
|
3578
|
+
advanced: "claude-opus-5-5",
|
|
3575
3579
|
research: "claude-fable-5-1"
|
|
3576
3580
|
},
|
|
3577
3581
|
scoreBands: DEFAULT_SCORE_BANDS,
|
|
@@ -7296,7 +7300,7 @@ class ProgressTracker {
|
|
|
7296
7300
|
return PHASES[this.phase].label;
|
|
7297
7301
|
}
|
|
7298
7302
|
describeToolAction(name, input) {
|
|
7299
|
-
const fileTool = FILE_TOOL_VERBS
|
|
7303
|
+
const fileTool = FILE_TOOL_VERBS.get(name);
|
|
7300
7304
|
if (fileTool) {
|
|
7301
7305
|
const [verb, key] = fileTool;
|
|
7302
7306
|
const fp = this.extractString(input, key);
|
|
@@ -7434,13 +7438,13 @@ var init_progress_tracker = __esm(() => {
|
|
|
7434
7438
|
finishing: 4
|
|
7435
7439
|
};
|
|
7436
7440
|
EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
7437
|
-
FILE_TOOL_VERBS =
|
|
7438
|
-
Read
|
|
7439
|
-
Edit
|
|
7440
|
-
MultiEdit
|
|
7441
|
-
Write
|
|
7442
|
-
NotebookEdit
|
|
7443
|
-
|
|
7441
|
+
FILE_TOOL_VERBS = new Map([
|
|
7442
|
+
["Read", ["Reading", "file_path"]],
|
|
7443
|
+
["Edit", ["Editing", "file_path"]],
|
|
7444
|
+
["MultiEdit", ["Editing", "file_path"]],
|
|
7445
|
+
["Write", ["Writing", "file_path"]],
|
|
7446
|
+
["NotebookEdit", ["Editing notebook", "notebook_path"]]
|
|
7447
|
+
]);
|
|
7444
7448
|
});
|
|
7445
7449
|
|
|
7446
7450
|
// src/prompt.ts
|
|
@@ -11595,6 +11599,15 @@ function resolveEffectiveAgentConfig(cfg, ws) {
|
|
|
11595
11599
|
const withWorkspace = ws ? mergeAgentConfig(DEFAULT_AGENT_CONFIG, workspaceConfigToPartial(ws)) : DEFAULT_AGENT_CONFIG;
|
|
11596
11600
|
return mergeAgentConfig(mergeAgentConfig(withWorkspace, cfg.agentOverrides), cfg.repoAgentOverrides);
|
|
11597
11601
|
}
|
|
11602
|
+
function withdrawnMapFrom(models) {
|
|
11603
|
+
const withdrawn = {};
|
|
11604
|
+
for (const m of models) {
|
|
11605
|
+
if (m.status === "withdrawn" && m.replaced_by) {
|
|
11606
|
+
withdrawn[m.id] = m.replaced_by;
|
|
11607
|
+
}
|
|
11608
|
+
}
|
|
11609
|
+
return withdrawn;
|
|
11610
|
+
}
|
|
11598
11611
|
var init_workspace_model_config = __esm(() => {
|
|
11599
11612
|
init_config_merge();
|
|
11600
11613
|
init_types();
|
|
@@ -14085,16 +14098,7 @@ class Pool {
|
|
|
14085
14098
|
const { config: wsConfig, platformDefaults } = await client.getWorkspaceModelConfig(workspaceId);
|
|
14086
14099
|
return layerPlatformDefaults(platformDefaults, wsConfig);
|
|
14087
14100
|
}) : undefined;
|
|
14088
|
-
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () =>
|
|
14089
|
-
const { models } = await client.getModelCatalog();
|
|
14090
|
-
const withdrawn = {};
|
|
14091
|
-
for (const m of models) {
|
|
14092
|
-
if (m.status === "withdrawn" && m.replaced_by) {
|
|
14093
|
-
withdrawn[m.id] = m.replaced_by;
|
|
14094
|
-
}
|
|
14095
|
-
}
|
|
14096
|
-
return withdrawn;
|
|
14097
|
-
}) : undefined;
|
|
14101
|
+
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () => withdrawnMapFrom((await client.getModelCatalog()).models)) : undefined;
|
|
14098
14102
|
const reportedConfig = daemonConfig ? new ReportedConfigCache(client, effectiveModelReport(config)) : undefined;
|
|
14099
14103
|
for (let i = 0;i < config.poolSize; i++) {
|
|
14100
14104
|
this.implWorkers.push(new Worker(i, config, client, this.identity, () => {
|
|
@@ -16230,6 +16234,105 @@ var init_reconcile = __esm(() => {
|
|
|
16230
16234
|
init_types();
|
|
16231
16235
|
});
|
|
16232
16236
|
|
|
16237
|
+
// src/startup-model.ts
|
|
16238
|
+
function describeStartupModel(config, layers, withdrawn) {
|
|
16239
|
+
const workspace = layers?.workspace ?? null;
|
|
16240
|
+
const platform = layers?.platform ?? null;
|
|
16241
|
+
const database = layerPlatformDefaults(platform, workspace);
|
|
16242
|
+
const claude = resolveEffectiveAgentConfig(config, database).claude;
|
|
16243
|
+
const pinned = ownObject(config.agentOverrides, "claude");
|
|
16244
|
+
const pinnedTiers = ownObject(pinned, "tiers");
|
|
16245
|
+
const pinnedModel = ownString(pinned, "model");
|
|
16246
|
+
let source = "built-in default";
|
|
16247
|
+
if (pinnedModel)
|
|
16248
|
+
source = "config.json";
|
|
16249
|
+
else if (workspace?.implement_model)
|
|
16250
|
+
source = "workspace";
|
|
16251
|
+
else if (platform?.implement_model)
|
|
16252
|
+
source = "platform";
|
|
16253
|
+
const warnings = [];
|
|
16254
|
+
const pins = [
|
|
16255
|
+
["claude.model", pinnedModel, database?.implement_model],
|
|
16256
|
+
[
|
|
16257
|
+
"claude.escalateModel",
|
|
16258
|
+
ownString(pinned, "escalateModel"),
|
|
16259
|
+
database?.escalate_model
|
|
16260
|
+
],
|
|
16261
|
+
...TIERS.map((tier) => [
|
|
16262
|
+
`claude.tiers.${tier}`,
|
|
16263
|
+
ownString(pinnedTiers, tier),
|
|
16264
|
+
database?.tiers?.[tier]
|
|
16265
|
+
])
|
|
16266
|
+
];
|
|
16267
|
+
for (const [key, local, db] of pins) {
|
|
16268
|
+
if (local && db && local !== db) {
|
|
16269
|
+
warnings.push(`config.json pins ${key} to "${local}", which overrides the database default "${db}" — remove it from config.json to follow the app's model settings`);
|
|
16270
|
+
}
|
|
16271
|
+
}
|
|
16272
|
+
const effective = [
|
|
16273
|
+
["claude.model", claude.model],
|
|
16274
|
+
["claude.escalateModel", claude.escalateModel],
|
|
16275
|
+
...TIERS.map((tier) => [`claude.tiers.${tier}`, claude.tiers[tier]])
|
|
16276
|
+
];
|
|
16277
|
+
for (const [key, id] of effective) {
|
|
16278
|
+
const replacement = withdrawn?.[id];
|
|
16279
|
+
if (replacement) {
|
|
16280
|
+
warnings.push(`${key} resolves to "${id}", which is withdrawn in the model catalog — runs use its replacement "${replacement}"; update the setting to match`);
|
|
16281
|
+
}
|
|
16282
|
+
}
|
|
16283
|
+
return {
|
|
16284
|
+
model: claude.model,
|
|
16285
|
+
escalateModel: claude.escalateModel,
|
|
16286
|
+
reviewModel: config.agent.claude.reviewModel,
|
|
16287
|
+
sizingModel: claude.sizingModel,
|
|
16288
|
+
tiers: {
|
|
16289
|
+
simple: claude.tiers.simple,
|
|
16290
|
+
advanced: claude.tiers.advanced,
|
|
16291
|
+
research: claude.tiers.research
|
|
16292
|
+
},
|
|
16293
|
+
source,
|
|
16294
|
+
resolved: layers !== null && withdrawn !== null,
|
|
16295
|
+
warnings
|
|
16296
|
+
};
|
|
16297
|
+
}
|
|
16298
|
+
async function resolveStartupModel(config, client) {
|
|
16299
|
+
const [layers, withdrawn] = await Promise.all([
|
|
16300
|
+
client.getWorkspaceModelConfig(config.workspaceId).then(({ config: workspace, platformDefaults }) => ({
|
|
16301
|
+
workspace,
|
|
16302
|
+
platform: platformDefaults ?? null
|
|
16303
|
+
})).catch(() => null),
|
|
16304
|
+
client.getModelCatalog().then(({ models }) => withdrawnMapFrom(models)).catch(() => null)
|
|
16305
|
+
]);
|
|
16306
|
+
return describeStartupModel(config, layers, withdrawn);
|
|
16307
|
+
}
|
|
16308
|
+
function ownObject(source, key) {
|
|
16309
|
+
if (typeof source !== "object" || source === null)
|
|
16310
|
+
return {};
|
|
16311
|
+
const value = own(source, key);
|
|
16312
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
16313
|
+
}
|
|
16314
|
+
function ownString(source, key) {
|
|
16315
|
+
const value = own(source, key);
|
|
16316
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
16317
|
+
}
|
|
16318
|
+
function startupModelLine(m) {
|
|
16319
|
+
const origin = m.resolved ? `from ${m.source}` : `from ${m.source}; database model settings unreachable, a pickup may resolve differently`;
|
|
16320
|
+
return `${implementModelsLine(m)} (${origin})`;
|
|
16321
|
+
}
|
|
16322
|
+
function implementModelsLine(m) {
|
|
16323
|
+
if (m.sizingModel) {
|
|
16324
|
+
const ladder = TIERS.map((tier) => `${tier} → ${m.tiers[tier]}`).join(" · ");
|
|
16325
|
+
return `sized per pickup by ${m.sizingModel}: ${ladder} (${m.model} only when sizing fails) · review ${m.reviewModel}`;
|
|
16326
|
+
}
|
|
16327
|
+
return m.model === m.escalateModel ? m.model : `${m.model} → ${m.escalateModel} on retry/high · review ${m.reviewModel}`;
|
|
16328
|
+
}
|
|
16329
|
+
var TIERS;
|
|
16330
|
+
var init_startup_model = __esm(() => {
|
|
16331
|
+
init_src();
|
|
16332
|
+
init_workspace_model_config();
|
|
16333
|
+
TIERS = ["simple", "advanced", "research"];
|
|
16334
|
+
});
|
|
16335
|
+
|
|
16233
16336
|
// src/startup-banner.ts
|
|
16234
16337
|
var exports_startup_banner = {};
|
|
16235
16338
|
__export(exports_startup_banner, {
|
|
@@ -16245,6 +16348,7 @@ function prettyBanner(config, version) {
|
|
|
16245
16348
|
let projectName;
|
|
16246
16349
|
let gitProvider;
|
|
16247
16350
|
let httpPort;
|
|
16351
|
+
let model;
|
|
16248
16352
|
let failed = false;
|
|
16249
16353
|
let rendered = false;
|
|
16250
16354
|
return {
|
|
@@ -16257,6 +16361,9 @@ function prettyBanner(config, version) {
|
|
|
16257
16361
|
setHttpPort(port) {
|
|
16258
16362
|
httpPort = port;
|
|
16259
16363
|
},
|
|
16364
|
+
setModel(resolved) {
|
|
16365
|
+
model = resolved;
|
|
16366
|
+
},
|
|
16260
16367
|
check(message) {
|
|
16261
16368
|
checks.push({ kind: "ok", message });
|
|
16262
16369
|
},
|
|
@@ -16278,6 +16385,7 @@ function prettyBanner(config, version) {
|
|
|
16278
16385
|
projectName,
|
|
16279
16386
|
gitProvider,
|
|
16280
16387
|
httpPort,
|
|
16388
|
+
model,
|
|
16281
16389
|
checks,
|
|
16282
16390
|
readyMessage: message
|
|
16283
16391
|
});
|
|
@@ -16287,12 +16395,13 @@ function prettyBanner(config, version) {
|
|
|
16287
16395
|
}
|
|
16288
16396
|
function jsonBanner(config, version) {
|
|
16289
16397
|
log45.info(TAG41, `Harmony Agent Daemon v${version} starting...`);
|
|
16290
|
-
log45.info(TAG41, `Project: ${config.projectId} | Pool: ${config.agent.poolSize} |
|
|
16398
|
+
log45.info(TAG41, `Project: ${config.projectId} | Pool: ${config.agent.poolSize} | Runner: ${config.agent.runner} | Pickup: ${config.agent.pickupColumns.join(", ")}`);
|
|
16291
16399
|
log45.info(TAG41, `Config: ${contextSourceLine(config)}`);
|
|
16292
16400
|
if (config.agent.review.enabled) {
|
|
16293
16401
|
log45.info(TAG41, `Review: enabled | Columns: ${config.agent.review.pickupColumns.join(", ")} | → ${config.agent.review.moveToColumn} / ${config.agent.review.failColumn}`);
|
|
16294
16402
|
}
|
|
16295
16403
|
let failed = false;
|
|
16404
|
+
let modelLogged = false;
|
|
16296
16405
|
return {
|
|
16297
16406
|
setProjectName(_name) {},
|
|
16298
16407
|
setGitProvider(provider) {
|
|
@@ -16301,6 +16410,10 @@ function jsonBanner(config, version) {
|
|
|
16301
16410
|
setHttpPort(port) {
|
|
16302
16411
|
log45.info(TAG41, `HTTP server on port ${port}`);
|
|
16303
16412
|
},
|
|
16413
|
+
setModel(resolved) {
|
|
16414
|
+
modelLogged = true;
|
|
16415
|
+
log45.info(TAG41, `Model: ${startupModelLine(resolved)}`);
|
|
16416
|
+
},
|
|
16304
16417
|
check(message) {
|
|
16305
16418
|
log45.info(TAG41, message);
|
|
16306
16419
|
},
|
|
@@ -16313,6 +16426,8 @@ function jsonBanner(config, version) {
|
|
|
16313
16426
|
async ready(message) {
|
|
16314
16427
|
if (failed)
|
|
16315
16428
|
return;
|
|
16429
|
+
if (!modelLogged)
|
|
16430
|
+
log45.info(TAG41, `Model: ${localModelLine(config)}`);
|
|
16316
16431
|
log45.info(TAG41, message);
|
|
16317
16432
|
}
|
|
16318
16433
|
};
|
|
@@ -16324,6 +16439,7 @@ function renderPretty(input) {
|
|
|
16324
16439
|
projectName,
|
|
16325
16440
|
gitProvider,
|
|
16326
16441
|
httpPort,
|
|
16442
|
+
model,
|
|
16327
16443
|
checks,
|
|
16328
16444
|
readyMessage
|
|
16329
16445
|
} = input;
|
|
@@ -16331,7 +16447,7 @@ function renderPretty(input) {
|
|
|
16331
16447
|
lines.push("");
|
|
16332
16448
|
lines.push(titleRule(`Harmony Agent Daemon v${version}`));
|
|
16333
16449
|
lines.push("");
|
|
16334
|
-
for (const row of configRows(config, projectName, gitProvider, httpPort)) {
|
|
16450
|
+
for (const row of configRows(config, projectName, gitProvider, httpPort, model)) {
|
|
16335
16451
|
lines.push(` ${dim(row.label.padEnd(9))} ${row.value}`);
|
|
16336
16452
|
}
|
|
16337
16453
|
lines.push("");
|
|
@@ -16345,7 +16461,7 @@ function renderPretty(input) {
|
|
|
16345
16461
|
return lines.join(`
|
|
16346
16462
|
`);
|
|
16347
16463
|
}
|
|
16348
|
-
function configRows(config, projectName, gitProvider, httpPort) {
|
|
16464
|
+
function configRows(config, projectName, gitProvider, httpPort, model) {
|
|
16349
16465
|
const rows = [];
|
|
16350
16466
|
const projectLabel = projectName ? `${projectName} (${shortenId(config.projectId)})` : shortenId(config.projectId);
|
|
16351
16467
|
rows.push({ label: "Project", value: projectLabel });
|
|
@@ -16354,8 +16470,7 @@ function configRows(config, projectName, gitProvider, httpPort) {
|
|
|
16354
16470
|
const reviewEnabled = config.agent.review.enabled;
|
|
16355
16471
|
const poolDesc = reviewEnabled ? `Pool ${config.agent.poolSize} impl + ${config.agent.review.poolSize} review` : `Pool ${config.agent.poolSize} impl`;
|
|
16356
16472
|
const flowDesc = reviewEnabled ? `Pickup ${config.agent.pickupColumns[0]} → ${config.agent.completion.moveToColumn} → ${config.agent.review.moveToColumn}` : `Pickup ${config.agent.pickupColumns.join(", ")}`;
|
|
16357
|
-
const
|
|
16358
|
-
const modelDesc = model === escalateModel ? model : `${model} → ${escalateModel} on retry/high · review ${reviewModel}`;
|
|
16473
|
+
const modelDesc = model ? startupModelLine(model) : localModelLine(config);
|
|
16359
16474
|
rows.push({
|
|
16360
16475
|
label: "Model",
|
|
16361
16476
|
value: `${modelDesc} · ${poolDesc} · ${flowDesc}`
|
|
@@ -16389,6 +16504,9 @@ function titleRule(title) {
|
|
|
16389
16504
|
const suffix = "─".repeat(Math.max(3, RULE_WIDTH - prefix.length - title.length - surround.length));
|
|
16390
16505
|
return dim(`${prefix}${title}${surround}${suffix}`);
|
|
16391
16506
|
}
|
|
16507
|
+
function localModelLine(config) {
|
|
16508
|
+
return `${implementModelsLine(config.agent.claude)} (local config only; database model settings not read)`;
|
|
16509
|
+
}
|
|
16392
16510
|
function runnerDesc(runner) {
|
|
16393
16511
|
return runner === "sdk" ? "sdk (Agent SDK)" : "cli (Claude CLI)";
|
|
16394
16512
|
}
|
|
@@ -16409,6 +16527,7 @@ function yellow(s) {
|
|
|
16409
16527
|
var TAG41 = "daemon", RULE_WIDTH = 70, ANSI;
|
|
16410
16528
|
var init_startup_banner = __esm(() => {
|
|
16411
16529
|
init_port_registry();
|
|
16530
|
+
init_startup_model();
|
|
16412
16531
|
ANSI = {
|
|
16413
16532
|
reset: "\x1B[0m",
|
|
16414
16533
|
dim: "\x1B[2m",
|
|
@@ -17766,6 +17885,11 @@ async function main() {
|
|
|
17766
17885
|
} catch (err) {
|
|
17767
17886
|
log50.warn(TAG46, `Could not report model config: ${err instanceof Error ? err.message : String(err)}`);
|
|
17768
17887
|
}
|
|
17888
|
+
const startupModel = await resolveStartupModel(config, client);
|
|
17889
|
+
banner.setModel(startupModel);
|
|
17890
|
+
for (const warning of startupModel.warnings) {
|
|
17891
|
+
banner.warn(warning);
|
|
17892
|
+
}
|
|
17769
17893
|
migrateConfigDir();
|
|
17770
17894
|
try {
|
|
17771
17895
|
migrateLegacyStateFile({
|
|
@@ -18088,6 +18212,7 @@ var init_src2 = __esm(() => {
|
|
|
18088
18212
|
init_recovery();
|
|
18089
18213
|
init_review_worktree();
|
|
18090
18214
|
init_startup_banner();
|
|
18215
|
+
init_startup_model();
|
|
18091
18216
|
init_state_migration();
|
|
18092
18217
|
init_state_store();
|
|
18093
18218
|
init_stream_parser_selftest();
|
package/dist/index.js
CHANGED
|
@@ -2571,6 +2571,9 @@ function untrustedDataBlock(text, options) {
|
|
|
2571
2571
|
`);
|
|
2572
2572
|
}
|
|
2573
2573
|
|
|
2574
|
+
// ../harmony-shared/src/xPostLink.ts
|
|
2575
|
+
var init_xPostLink = () => {};
|
|
2576
|
+
|
|
2574
2577
|
// ../harmony-shared/src/index.ts
|
|
2575
2578
|
var init_src = __esm(() => {
|
|
2576
2579
|
init_agentPauseAccounting();
|
|
@@ -2601,6 +2604,7 @@ var init_src = __esm(() => {
|
|
|
2601
2604
|
init_runRedaction();
|
|
2602
2605
|
init_stageHandoff();
|
|
2603
2606
|
init_sweepPresence();
|
|
2607
|
+
init_xPostLink();
|
|
2604
2608
|
});
|
|
2605
2609
|
|
|
2606
2610
|
// src/config-merge.ts
|
|
@@ -3565,12 +3569,12 @@ var init_types = __esm(() => {
|
|
|
3565
3569
|
postSummary: true
|
|
3566
3570
|
},
|
|
3567
3571
|
claude: {
|
|
3568
|
-
model: "claude-opus-5",
|
|
3572
|
+
model: "claude-opus-5-5",
|
|
3569
3573
|
escalateModel: "claude-fable-5-1",
|
|
3570
3574
|
escalateAfterAttempts: 2,
|
|
3571
3575
|
tiers: {
|
|
3572
3576
|
simple: "claude-sonnet-5",
|
|
3573
|
-
advanced: "claude-opus-5",
|
|
3577
|
+
advanced: "claude-opus-5-5",
|
|
3574
3578
|
research: "claude-fable-5-1"
|
|
3575
3579
|
},
|
|
3576
3580
|
scoreBands: DEFAULT_SCORE_BANDS,
|
|
@@ -7295,7 +7299,7 @@ class ProgressTracker {
|
|
|
7295
7299
|
return PHASES[this.phase].label;
|
|
7296
7300
|
}
|
|
7297
7301
|
describeToolAction(name, input) {
|
|
7298
|
-
const fileTool = FILE_TOOL_VERBS
|
|
7302
|
+
const fileTool = FILE_TOOL_VERBS.get(name);
|
|
7299
7303
|
if (fileTool) {
|
|
7300
7304
|
const [verb, key] = fileTool;
|
|
7301
7305
|
const fp = this.extractString(input, key);
|
|
@@ -7433,13 +7437,13 @@ var init_progress_tracker = __esm(() => {
|
|
|
7433
7437
|
finishing: 4
|
|
7434
7438
|
};
|
|
7435
7439
|
EDIT_TOOLS = new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
7436
|
-
FILE_TOOL_VERBS =
|
|
7437
|
-
Read
|
|
7438
|
-
Edit
|
|
7439
|
-
MultiEdit
|
|
7440
|
-
Write
|
|
7441
|
-
NotebookEdit
|
|
7442
|
-
|
|
7440
|
+
FILE_TOOL_VERBS = new Map([
|
|
7441
|
+
["Read", ["Reading", "file_path"]],
|
|
7442
|
+
["Edit", ["Editing", "file_path"]],
|
|
7443
|
+
["MultiEdit", ["Editing", "file_path"]],
|
|
7444
|
+
["Write", ["Writing", "file_path"]],
|
|
7445
|
+
["NotebookEdit", ["Editing notebook", "notebook_path"]]
|
|
7446
|
+
]);
|
|
7443
7447
|
});
|
|
7444
7448
|
|
|
7445
7449
|
// src/prompt.ts
|
|
@@ -11594,6 +11598,15 @@ function resolveEffectiveAgentConfig(cfg, ws) {
|
|
|
11594
11598
|
const withWorkspace = ws ? mergeAgentConfig(DEFAULT_AGENT_CONFIG, workspaceConfigToPartial(ws)) : DEFAULT_AGENT_CONFIG;
|
|
11595
11599
|
return mergeAgentConfig(mergeAgentConfig(withWorkspace, cfg.agentOverrides), cfg.repoAgentOverrides);
|
|
11596
11600
|
}
|
|
11601
|
+
function withdrawnMapFrom(models) {
|
|
11602
|
+
const withdrawn = {};
|
|
11603
|
+
for (const m of models) {
|
|
11604
|
+
if (m.status === "withdrawn" && m.replaced_by) {
|
|
11605
|
+
withdrawn[m.id] = m.replaced_by;
|
|
11606
|
+
}
|
|
11607
|
+
}
|
|
11608
|
+
return withdrawn;
|
|
11609
|
+
}
|
|
11597
11610
|
var init_workspace_model_config = __esm(() => {
|
|
11598
11611
|
init_config_merge();
|
|
11599
11612
|
init_types();
|
|
@@ -14084,16 +14097,7 @@ class Pool {
|
|
|
14084
14097
|
const { config: wsConfig, platformDefaults } = await client.getWorkspaceModelConfig(workspaceId);
|
|
14085
14098
|
return layerPlatformDefaults(platformDefaults, wsConfig);
|
|
14086
14099
|
}) : undefined;
|
|
14087
|
-
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () =>
|
|
14088
|
-
const { models } = await client.getModelCatalog();
|
|
14089
|
-
const withdrawn = {};
|
|
14090
|
-
for (const m of models) {
|
|
14091
|
-
if (m.status === "withdrawn" && m.replaced_by) {
|
|
14092
|
-
withdrawn[m.id] = m.replaced_by;
|
|
14093
|
-
}
|
|
14094
|
-
}
|
|
14095
|
-
return withdrawn;
|
|
14096
|
-
}) : undefined;
|
|
14100
|
+
const modelCatalog = daemonConfig ? new WorkspaceModelCache(async () => withdrawnMapFrom((await client.getModelCatalog()).models)) : undefined;
|
|
14097
14101
|
const reportedConfig = daemonConfig ? new ReportedConfigCache(client, effectiveModelReport(config)) : undefined;
|
|
14098
14102
|
for (let i = 0;i < config.poolSize; i++) {
|
|
14099
14103
|
this.implWorkers.push(new Worker(i, config, client, this.identity, () => {
|
|
@@ -16229,6 +16233,105 @@ var init_reconcile = __esm(() => {
|
|
|
16229
16233
|
init_types();
|
|
16230
16234
|
});
|
|
16231
16235
|
|
|
16236
|
+
// src/startup-model.ts
|
|
16237
|
+
function describeStartupModel(config, layers, withdrawn) {
|
|
16238
|
+
const workspace = layers?.workspace ?? null;
|
|
16239
|
+
const platform = layers?.platform ?? null;
|
|
16240
|
+
const database = layerPlatformDefaults(platform, workspace);
|
|
16241
|
+
const claude = resolveEffectiveAgentConfig(config, database).claude;
|
|
16242
|
+
const pinned = ownObject(config.agentOverrides, "claude");
|
|
16243
|
+
const pinnedTiers = ownObject(pinned, "tiers");
|
|
16244
|
+
const pinnedModel = ownString(pinned, "model");
|
|
16245
|
+
let source = "built-in default";
|
|
16246
|
+
if (pinnedModel)
|
|
16247
|
+
source = "config.json";
|
|
16248
|
+
else if (workspace?.implement_model)
|
|
16249
|
+
source = "workspace";
|
|
16250
|
+
else if (platform?.implement_model)
|
|
16251
|
+
source = "platform";
|
|
16252
|
+
const warnings = [];
|
|
16253
|
+
const pins = [
|
|
16254
|
+
["claude.model", pinnedModel, database?.implement_model],
|
|
16255
|
+
[
|
|
16256
|
+
"claude.escalateModel",
|
|
16257
|
+
ownString(pinned, "escalateModel"),
|
|
16258
|
+
database?.escalate_model
|
|
16259
|
+
],
|
|
16260
|
+
...TIERS.map((tier) => [
|
|
16261
|
+
`claude.tiers.${tier}`,
|
|
16262
|
+
ownString(pinnedTiers, tier),
|
|
16263
|
+
database?.tiers?.[tier]
|
|
16264
|
+
])
|
|
16265
|
+
];
|
|
16266
|
+
for (const [key, local, db] of pins) {
|
|
16267
|
+
if (local && db && local !== db) {
|
|
16268
|
+
warnings.push(`config.json pins ${key} to "${local}", which overrides the database default "${db}" — remove it from config.json to follow the app's model settings`);
|
|
16269
|
+
}
|
|
16270
|
+
}
|
|
16271
|
+
const effective = [
|
|
16272
|
+
["claude.model", claude.model],
|
|
16273
|
+
["claude.escalateModel", claude.escalateModel],
|
|
16274
|
+
...TIERS.map((tier) => [`claude.tiers.${tier}`, claude.tiers[tier]])
|
|
16275
|
+
];
|
|
16276
|
+
for (const [key, id] of effective) {
|
|
16277
|
+
const replacement = withdrawn?.[id];
|
|
16278
|
+
if (replacement) {
|
|
16279
|
+
warnings.push(`${key} resolves to "${id}", which is withdrawn in the model catalog — runs use its replacement "${replacement}"; update the setting to match`);
|
|
16280
|
+
}
|
|
16281
|
+
}
|
|
16282
|
+
return {
|
|
16283
|
+
model: claude.model,
|
|
16284
|
+
escalateModel: claude.escalateModel,
|
|
16285
|
+
reviewModel: config.agent.claude.reviewModel,
|
|
16286
|
+
sizingModel: claude.sizingModel,
|
|
16287
|
+
tiers: {
|
|
16288
|
+
simple: claude.tiers.simple,
|
|
16289
|
+
advanced: claude.tiers.advanced,
|
|
16290
|
+
research: claude.tiers.research
|
|
16291
|
+
},
|
|
16292
|
+
source,
|
|
16293
|
+
resolved: layers !== null && withdrawn !== null,
|
|
16294
|
+
warnings
|
|
16295
|
+
};
|
|
16296
|
+
}
|
|
16297
|
+
async function resolveStartupModel(config, client) {
|
|
16298
|
+
const [layers, withdrawn] = await Promise.all([
|
|
16299
|
+
client.getWorkspaceModelConfig(config.workspaceId).then(({ config: workspace, platformDefaults }) => ({
|
|
16300
|
+
workspace,
|
|
16301
|
+
platform: platformDefaults ?? null
|
|
16302
|
+
})).catch(() => null),
|
|
16303
|
+
client.getModelCatalog().then(({ models }) => withdrawnMapFrom(models)).catch(() => null)
|
|
16304
|
+
]);
|
|
16305
|
+
return describeStartupModel(config, layers, withdrawn);
|
|
16306
|
+
}
|
|
16307
|
+
function ownObject(source, key) {
|
|
16308
|
+
if (typeof source !== "object" || source === null)
|
|
16309
|
+
return {};
|
|
16310
|
+
const value = own(source, key);
|
|
16311
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
16312
|
+
}
|
|
16313
|
+
function ownString(source, key) {
|
|
16314
|
+
const value = own(source, key);
|
|
16315
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
16316
|
+
}
|
|
16317
|
+
function startupModelLine(m) {
|
|
16318
|
+
const origin = m.resolved ? `from ${m.source}` : `from ${m.source}; database model settings unreachable, a pickup may resolve differently`;
|
|
16319
|
+
return `${implementModelsLine(m)} (${origin})`;
|
|
16320
|
+
}
|
|
16321
|
+
function implementModelsLine(m) {
|
|
16322
|
+
if (m.sizingModel) {
|
|
16323
|
+
const ladder = TIERS.map((tier) => `${tier} → ${m.tiers[tier]}`).join(" · ");
|
|
16324
|
+
return `sized per pickup by ${m.sizingModel}: ${ladder} (${m.model} only when sizing fails) · review ${m.reviewModel}`;
|
|
16325
|
+
}
|
|
16326
|
+
return m.model === m.escalateModel ? m.model : `${m.model} → ${m.escalateModel} on retry/high · review ${m.reviewModel}`;
|
|
16327
|
+
}
|
|
16328
|
+
var TIERS;
|
|
16329
|
+
var init_startup_model = __esm(() => {
|
|
16330
|
+
init_src();
|
|
16331
|
+
init_workspace_model_config();
|
|
16332
|
+
TIERS = ["simple", "advanced", "research"];
|
|
16333
|
+
});
|
|
16334
|
+
|
|
16232
16335
|
// src/startup-banner.ts
|
|
16233
16336
|
var exports_startup_banner = {};
|
|
16234
16337
|
__export(exports_startup_banner, {
|
|
@@ -16244,6 +16347,7 @@ function prettyBanner(config, version) {
|
|
|
16244
16347
|
let projectName;
|
|
16245
16348
|
let gitProvider;
|
|
16246
16349
|
let httpPort;
|
|
16350
|
+
let model;
|
|
16247
16351
|
let failed = false;
|
|
16248
16352
|
let rendered = false;
|
|
16249
16353
|
return {
|
|
@@ -16256,6 +16360,9 @@ function prettyBanner(config, version) {
|
|
|
16256
16360
|
setHttpPort(port) {
|
|
16257
16361
|
httpPort = port;
|
|
16258
16362
|
},
|
|
16363
|
+
setModel(resolved) {
|
|
16364
|
+
model = resolved;
|
|
16365
|
+
},
|
|
16259
16366
|
check(message) {
|
|
16260
16367
|
checks.push({ kind: "ok", message });
|
|
16261
16368
|
},
|
|
@@ -16277,6 +16384,7 @@ function prettyBanner(config, version) {
|
|
|
16277
16384
|
projectName,
|
|
16278
16385
|
gitProvider,
|
|
16279
16386
|
httpPort,
|
|
16387
|
+
model,
|
|
16280
16388
|
checks,
|
|
16281
16389
|
readyMessage: message
|
|
16282
16390
|
});
|
|
@@ -16286,12 +16394,13 @@ function prettyBanner(config, version) {
|
|
|
16286
16394
|
}
|
|
16287
16395
|
function jsonBanner(config, version) {
|
|
16288
16396
|
log45.info(TAG41, `Harmony Agent Daemon v${version} starting...`);
|
|
16289
|
-
log45.info(TAG41, `Project: ${config.projectId} | Pool: ${config.agent.poolSize} |
|
|
16397
|
+
log45.info(TAG41, `Project: ${config.projectId} | Pool: ${config.agent.poolSize} | Runner: ${config.agent.runner} | Pickup: ${config.agent.pickupColumns.join(", ")}`);
|
|
16290
16398
|
log45.info(TAG41, `Config: ${contextSourceLine(config)}`);
|
|
16291
16399
|
if (config.agent.review.enabled) {
|
|
16292
16400
|
log45.info(TAG41, `Review: enabled | Columns: ${config.agent.review.pickupColumns.join(", ")} | → ${config.agent.review.moveToColumn} / ${config.agent.review.failColumn}`);
|
|
16293
16401
|
}
|
|
16294
16402
|
let failed = false;
|
|
16403
|
+
let modelLogged = false;
|
|
16295
16404
|
return {
|
|
16296
16405
|
setProjectName(_name) {},
|
|
16297
16406
|
setGitProvider(provider) {
|
|
@@ -16300,6 +16409,10 @@ function jsonBanner(config, version) {
|
|
|
16300
16409
|
setHttpPort(port) {
|
|
16301
16410
|
log45.info(TAG41, `HTTP server on port ${port}`);
|
|
16302
16411
|
},
|
|
16412
|
+
setModel(resolved) {
|
|
16413
|
+
modelLogged = true;
|
|
16414
|
+
log45.info(TAG41, `Model: ${startupModelLine(resolved)}`);
|
|
16415
|
+
},
|
|
16303
16416
|
check(message) {
|
|
16304
16417
|
log45.info(TAG41, message);
|
|
16305
16418
|
},
|
|
@@ -16312,6 +16425,8 @@ function jsonBanner(config, version) {
|
|
|
16312
16425
|
async ready(message) {
|
|
16313
16426
|
if (failed)
|
|
16314
16427
|
return;
|
|
16428
|
+
if (!modelLogged)
|
|
16429
|
+
log45.info(TAG41, `Model: ${localModelLine(config)}`);
|
|
16315
16430
|
log45.info(TAG41, message);
|
|
16316
16431
|
}
|
|
16317
16432
|
};
|
|
@@ -16323,6 +16438,7 @@ function renderPretty(input) {
|
|
|
16323
16438
|
projectName,
|
|
16324
16439
|
gitProvider,
|
|
16325
16440
|
httpPort,
|
|
16441
|
+
model,
|
|
16326
16442
|
checks,
|
|
16327
16443
|
readyMessage
|
|
16328
16444
|
} = input;
|
|
@@ -16330,7 +16446,7 @@ function renderPretty(input) {
|
|
|
16330
16446
|
lines.push("");
|
|
16331
16447
|
lines.push(titleRule(`Harmony Agent Daemon v${version}`));
|
|
16332
16448
|
lines.push("");
|
|
16333
|
-
for (const row of configRows(config, projectName, gitProvider, httpPort)) {
|
|
16449
|
+
for (const row of configRows(config, projectName, gitProvider, httpPort, model)) {
|
|
16334
16450
|
lines.push(` ${dim(row.label.padEnd(9))} ${row.value}`);
|
|
16335
16451
|
}
|
|
16336
16452
|
lines.push("");
|
|
@@ -16344,7 +16460,7 @@ function renderPretty(input) {
|
|
|
16344
16460
|
return lines.join(`
|
|
16345
16461
|
`);
|
|
16346
16462
|
}
|
|
16347
|
-
function configRows(config, projectName, gitProvider, httpPort) {
|
|
16463
|
+
function configRows(config, projectName, gitProvider, httpPort, model) {
|
|
16348
16464
|
const rows = [];
|
|
16349
16465
|
const projectLabel = projectName ? `${projectName} (${shortenId(config.projectId)})` : shortenId(config.projectId);
|
|
16350
16466
|
rows.push({ label: "Project", value: projectLabel });
|
|
@@ -16353,8 +16469,7 @@ function configRows(config, projectName, gitProvider, httpPort) {
|
|
|
16353
16469
|
const reviewEnabled = config.agent.review.enabled;
|
|
16354
16470
|
const poolDesc = reviewEnabled ? `Pool ${config.agent.poolSize} impl + ${config.agent.review.poolSize} review` : `Pool ${config.agent.poolSize} impl`;
|
|
16355
16471
|
const flowDesc = reviewEnabled ? `Pickup ${config.agent.pickupColumns[0]} → ${config.agent.completion.moveToColumn} → ${config.agent.review.moveToColumn}` : `Pickup ${config.agent.pickupColumns.join(", ")}`;
|
|
16356
|
-
const
|
|
16357
|
-
const modelDesc = model === escalateModel ? model : `${model} → ${escalateModel} on retry/high · review ${reviewModel}`;
|
|
16472
|
+
const modelDesc = model ? startupModelLine(model) : localModelLine(config);
|
|
16358
16473
|
rows.push({
|
|
16359
16474
|
label: "Model",
|
|
16360
16475
|
value: `${modelDesc} · ${poolDesc} · ${flowDesc}`
|
|
@@ -16388,6 +16503,9 @@ function titleRule(title) {
|
|
|
16388
16503
|
const suffix = "─".repeat(Math.max(3, RULE_WIDTH - prefix.length - title.length - surround.length));
|
|
16389
16504
|
return dim(`${prefix}${title}${surround}${suffix}`);
|
|
16390
16505
|
}
|
|
16506
|
+
function localModelLine(config) {
|
|
16507
|
+
return `${implementModelsLine(config.agent.claude)} (local config only; database model settings not read)`;
|
|
16508
|
+
}
|
|
16391
16509
|
function runnerDesc(runner) {
|
|
16392
16510
|
return runner === "sdk" ? "sdk (Agent SDK)" : "cli (Claude CLI)";
|
|
16393
16511
|
}
|
|
@@ -16408,6 +16526,7 @@ function yellow(s) {
|
|
|
16408
16526
|
var TAG41 = "daemon", RULE_WIDTH = 70, ANSI;
|
|
16409
16527
|
var init_startup_banner = __esm(() => {
|
|
16410
16528
|
init_port_registry();
|
|
16529
|
+
init_startup_model();
|
|
16411
16530
|
ANSI = {
|
|
16412
16531
|
reset: "\x1B[0m",
|
|
16413
16532
|
dim: "\x1B[2m",
|
|
@@ -17765,6 +17884,11 @@ async function main() {
|
|
|
17765
17884
|
} catch (err) {
|
|
17766
17885
|
log50.warn(TAG46, `Could not report model config: ${err instanceof Error ? err.message : String(err)}`);
|
|
17767
17886
|
}
|
|
17887
|
+
const startupModel = await resolveStartupModel(config, client);
|
|
17888
|
+
banner.setModel(startupModel);
|
|
17889
|
+
for (const warning of startupModel.warnings) {
|
|
17890
|
+
banner.warn(warning);
|
|
17891
|
+
}
|
|
17768
17892
|
migrateConfigDir();
|
|
17769
17893
|
try {
|
|
17770
17894
|
migrateLegacyStateFile({
|
|
@@ -18087,6 +18211,7 @@ var init_src2 = __esm(() => {
|
|
|
18087
18211
|
init_recovery();
|
|
18088
18212
|
init_review_worktree();
|
|
18089
18213
|
init_startup_banner();
|
|
18214
|
+
init_startup_model();
|
|
18090
18215
|
init_state_migration();
|
|
18091
18216
|
init_state_store();
|
|
18092
18217
|
init_stream_parser_selftest();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gethmy/agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.47.1",
|
|
4
4
|
"description": "Push-based agent daemon for Harmony — picks up assigned cards, builds them in isolated git worktrees, and opens PRs. It runs where you put it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@anthropic-ai/claude-agent-sdk": "^0.3.178",
|
|
48
|
-
"@gethmy/harness": "1.19.
|
|
49
|
-
"@gethmy/mcp": "3.
|
|
48
|
+
"@gethmy/harness": "1.19.2",
|
|
49
|
+
"@gethmy/mcp": "3.17.0",
|
|
50
50
|
"@supabase/supabase-js": "2.95.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|