@ouro.bot/cli 0.1.0-alpha.157 → 0.1.0-alpha.159
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/AdoptionSpecialist.ouro/agent.json +3 -2
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +1 -1
- package/README.md +5 -4
- package/changelog.json +24 -0
- package/dist/heart/config.js +0 -7
- package/dist/heart/core.js +51 -36
- package/dist/heart/daemon/auth-flow.js +45 -25
- package/dist/heart/daemon/daemon-cli.js +117 -11
- package/dist/heart/daemon/daemon.js +2 -0
- package/dist/heart/daemon/hatch-flow.js +2 -0
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/specialist-prompt.js +3 -1
- package/dist/heart/identity.js +78 -40
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/provider-ping.js +19 -6
- package/dist/heart/providers/anthropic.js +9 -10
- package/dist/heart/providers/azure.js +5 -5
- package/dist/heart/providers/github-copilot.js +6 -6
- package/dist/heart/providers/minimax.js +4 -4
- package/dist/heart/providers/openai-codex.js +6 -6
- package/dist/mind/friends/channel.js +12 -0
- package/dist/mind/prompt.js +3 -3
- package/dist/repertoire/guardrails.js +1 -0
- package/dist/repertoire/tasks/board.js +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +5 -1
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -0
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +10 -8
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/senses/bluebubbles-client.js +1 -1
- package/dist/senses/bluebubbles.js +1 -1
- package/dist/senses/cli.js +4 -2
- package/dist/senses/pipeline.js +5 -2
- package/dist/senses/teams.js +1 -1
- package/package.json +1 -1
|
@@ -134,6 +134,8 @@ function writeDiaryScaffold(bundleRoot) {
|
|
|
134
134
|
function writeHatchlingAgentConfig(bundleRoot, input) {
|
|
135
135
|
const template = (0, identity_1.buildDefaultAgentTemplate)(input.agentName);
|
|
136
136
|
template.provider = input.provider;
|
|
137
|
+
template.humanFacing = { provider: input.provider, model: template.humanFacing.model };
|
|
138
|
+
template.agentFacing = { provider: input.provider, model: template.agentFacing.model };
|
|
137
139
|
template.enabled = true;
|
|
138
140
|
fs.writeFileSync(path.join(bundleRoot, "agent.json"), `${JSON.stringify(template, null, 2)}\n`, "utf-8");
|
|
139
141
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentConfigV2Hook = agentConfigV2Hook;
|
|
4
|
+
const runtime_1 = require("../../../nerves/runtime");
|
|
5
|
+
const migrate_config_1 = require("../../migrate-config");
|
|
6
|
+
async function agentConfigV2Hook(ctx) {
|
|
7
|
+
(0, runtime_1.emitNervesEvent)({
|
|
8
|
+
component: "daemon",
|
|
9
|
+
event: "daemon.agent_config_v2_hook_start",
|
|
10
|
+
message: "running agent-config-v2 update hook",
|
|
11
|
+
meta: { agentRoot: ctx.agentRoot, currentVersion: ctx.currentVersion },
|
|
12
|
+
});
|
|
13
|
+
try {
|
|
14
|
+
(0, migrate_config_1.migrateAgentConfigV1ToV2)(ctx.agentRoot);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
|
|
18
|
+
(0, runtime_1.emitNervesEvent)({
|
|
19
|
+
component: "daemon",
|
|
20
|
+
event: "daemon.agent_config_v2_hook_error",
|
|
21
|
+
message: "agent-config-v2 hook migration failed",
|
|
22
|
+
meta: { agentRoot: ctx.agentRoot, error: errorMessage },
|
|
23
|
+
});
|
|
24
|
+
return { ok: false, error: errorMessage };
|
|
25
|
+
}
|
|
26
|
+
(0, runtime_1.emitNervesEvent)({
|
|
27
|
+
component: "daemon",
|
|
28
|
+
event: "daemon.agent_config_v2_hook_end",
|
|
29
|
+
message: "agent-config-v2 hook completed",
|
|
30
|
+
meta: { agentRoot: ctx.agentRoot },
|
|
31
|
+
});
|
|
32
|
+
return { ok: true };
|
|
33
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runHooks = runHooks;
|
|
4
4
|
const runtime_1 = require("../../nerves/runtime");
|
|
5
5
|
const bundle_meta_1 = require("./hooks/bundle-meta");
|
|
6
|
+
const agent_config_v2_1 = require("./hooks/agent-config-v2");
|
|
6
7
|
async function runHooks(deps) {
|
|
7
8
|
(0, runtime_1.emitNervesEvent)({
|
|
8
9
|
component: "daemon",
|
|
@@ -12,6 +13,7 @@ async function runHooks(deps) {
|
|
|
12
13
|
});
|
|
13
14
|
try {
|
|
14
15
|
deps.registerUpdateHook(bundle_meta_1.bundleMetaHook);
|
|
16
|
+
deps.registerUpdateHook(agent_config_v2_1.agentConfigV2Hook);
|
|
15
17
|
const currentVersion = deps.getPackageVersion();
|
|
16
18
|
await deps.applyPendingUpdates(deps.bundlesRoot, currentVersion);
|
|
17
19
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -59,8 +59,10 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles, co
|
|
|
59
59
|
"It also needs an **agent.json** with at minimum:",
|
|
60
60
|
'```json',
|
|
61
61
|
'{',
|
|
62
|
+
' "version": 2,',
|
|
62
63
|
' "name": "AgentName",',
|
|
63
|
-
` "provider": "${context.provider}",`,
|
|
64
|
+
` "humanFacing": { "provider": "${context.provider}", "model": "${context.model}" },`,
|
|
65
|
+
` "agentFacing": { "provider": "${context.provider}", "model": "${context.model}" },`,
|
|
64
66
|
' "enabled": true',
|
|
65
67
|
'}',
|
|
66
68
|
'```',
|
package/dist/heart/identity.js
CHANGED
|
@@ -56,6 +56,7 @@ const fs = __importStar(require("fs"));
|
|
|
56
56
|
const os = __importStar(require("os"));
|
|
57
57
|
const path = __importStar(require("path"));
|
|
58
58
|
const runtime_1 = require("../nerves/runtime");
|
|
59
|
+
const migrate_config_1 = require("./migrate-config");
|
|
59
60
|
exports.DEFAULT_AGENT_CONTEXT = {
|
|
60
61
|
maxTokens: 80000,
|
|
61
62
|
contextMargin: 20,
|
|
@@ -123,9 +124,10 @@ function normalizeSenses(value, configFile) {
|
|
|
123
124
|
}
|
|
124
125
|
function buildDefaultAgentTemplate(_agentName) {
|
|
125
126
|
return {
|
|
126
|
-
version:
|
|
127
|
+
version: 2,
|
|
127
128
|
enabled: true,
|
|
128
|
-
provider: "anthropic",
|
|
129
|
+
humanFacing: { provider: "anthropic", model: "claude-opus-4-6" },
|
|
130
|
+
agentFacing: { provider: "anthropic", model: "claude-opus-4-6" },
|
|
129
131
|
context: { ...exports.DEFAULT_AGENT_CONTEXT },
|
|
130
132
|
senses: {
|
|
131
133
|
cli: { ...exports.DEFAULT_AGENT_SENSES.cli },
|
|
@@ -231,17 +233,11 @@ function getAgentToolsRoot(agentName) {
|
|
|
231
233
|
function getAgentSecretsPath(agentName = getAgentName()) {
|
|
232
234
|
return path.join(os.homedir(), ".agentsecrets", agentName, "secrets.json");
|
|
233
235
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
function loadAgentConfig() {
|
|
240
|
-
if (_agentConfigOverride) {
|
|
241
|
-
return _agentConfigOverride;
|
|
242
|
-
}
|
|
243
|
-
const agentRoot = getAgentRoot();
|
|
244
|
-
const configFile = path.join(agentRoot, "agent.json");
|
|
236
|
+
const VALID_PROVIDERS = ["azure", "minimax", "anthropic", "openai-codex", "github-copilot"];
|
|
237
|
+
function isValidProvider(value) {
|
|
238
|
+
return typeof value === "string" && VALID_PROVIDERS.includes(value);
|
|
239
|
+
}
|
|
240
|
+
function readAndParseAgentJson(configFile) {
|
|
245
241
|
let raw;
|
|
246
242
|
try {
|
|
247
243
|
raw = fs.readFileSync(configFile, "utf-8");
|
|
@@ -259,9 +255,8 @@ function loadAgentConfig() {
|
|
|
259
255
|
});
|
|
260
256
|
throw new Error(`Cannot read agent.json at ${configFile}. Does the agent directory exist?`);
|
|
261
257
|
}
|
|
262
|
-
let parsed;
|
|
263
258
|
try {
|
|
264
|
-
|
|
259
|
+
return JSON.parse(raw);
|
|
265
260
|
}
|
|
266
261
|
catch (error) {
|
|
267
262
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -276,6 +271,62 @@ function loadAgentConfig() {
|
|
|
276
271
|
});
|
|
277
272
|
throw new Error(`Invalid JSON in agent.json at ${configFile}. Check syntax.`);
|
|
278
273
|
}
|
|
274
|
+
}
|
|
275
|
+
function validateFacingConfig(parsed, facingName, configFile) {
|
|
276
|
+
const raw = parsed[facingName];
|
|
277
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
278
|
+
(0, runtime_1.emitNervesEvent)({
|
|
279
|
+
level: "error",
|
|
280
|
+
event: "config_identity.error",
|
|
281
|
+
component: "config/identity",
|
|
282
|
+
message: `agent config missing or invalid ${facingName}`,
|
|
283
|
+
meta: { path: configFile, [facingName]: raw ?? null },
|
|
284
|
+
});
|
|
285
|
+
throw new Error(`agent.json at ${configFile} must include ${facingName} as { provider, model }.`);
|
|
286
|
+
}
|
|
287
|
+
const facing = raw;
|
|
288
|
+
if (!isValidProvider(facing.provider)) {
|
|
289
|
+
(0, runtime_1.emitNervesEvent)({
|
|
290
|
+
level: "error",
|
|
291
|
+
event: "config_identity.error",
|
|
292
|
+
component: "config/identity",
|
|
293
|
+
message: `agent config has invalid provider in ${facingName}`,
|
|
294
|
+
meta: { path: configFile, provider: facing.provider ?? null },
|
|
295
|
+
});
|
|
296
|
+
throw new Error(`agent.json at ${configFile} ${facingName}.provider must be one of: ${VALID_PROVIDERS.join(", ")}.`);
|
|
297
|
+
}
|
|
298
|
+
if (typeof facing.model !== "string") {
|
|
299
|
+
(0, runtime_1.emitNervesEvent)({
|
|
300
|
+
level: "error",
|
|
301
|
+
event: "config_identity.error",
|
|
302
|
+
component: "config/identity",
|
|
303
|
+
message: `agent config has invalid model in ${facingName}`,
|
|
304
|
+
meta: { path: configFile, model: facing.model ?? null },
|
|
305
|
+
});
|
|
306
|
+
throw new Error(`agent.json at ${configFile} ${facingName}.model must be a string.`);
|
|
307
|
+
}
|
|
308
|
+
return { provider: facing.provider, model: facing.model };
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Load and parse `<agentRoot>/agent.json`.
|
|
312
|
+
* Reads the file fresh on each call unless an override is set.
|
|
313
|
+
* If the config is v1, auto-migrates to v2 via migrateAgentConfigV1ToV2 and re-reads.
|
|
314
|
+
* Throws descriptive error if file is missing or contains invalid JSON.
|
|
315
|
+
*/
|
|
316
|
+
function loadAgentConfig() {
|
|
317
|
+
if (_agentConfigOverride) {
|
|
318
|
+
return _agentConfigOverride;
|
|
319
|
+
}
|
|
320
|
+
const agentRoot = getAgentRoot();
|
|
321
|
+
const configFile = path.join(agentRoot, "agent.json");
|
|
322
|
+
let parsed = readAndParseAgentJson(configFile);
|
|
323
|
+
// Inline migration: v1 -> v2
|
|
324
|
+
const rawVersion = parsed.version;
|
|
325
|
+
const initialVersion = typeof rawVersion === "number" ? rawVersion : 1;
|
|
326
|
+
if (initialVersion < 2) {
|
|
327
|
+
(0, migrate_config_1.migrateAgentConfigV1ToV2)(agentRoot);
|
|
328
|
+
parsed = readAndParseAgentJson(configFile);
|
|
329
|
+
}
|
|
279
330
|
const existingPhrases = parsed.phrases;
|
|
280
331
|
const needsFill = !existingPhrases ||
|
|
281
332
|
!existingPhrases.thinking ||
|
|
@@ -297,29 +348,11 @@ function loadAgentConfig() {
|
|
|
297
348
|
});
|
|
298
349
|
fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
|
|
299
350
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
rawProvider !== "github-copilot") {
|
|
306
|
-
(0, runtime_1.emitNervesEvent)({
|
|
307
|
-
level: "error",
|
|
308
|
-
event: "config_identity.error",
|
|
309
|
-
component: "config/identity",
|
|
310
|
-
message: "agent config missing or invalid provider",
|
|
311
|
-
meta: {
|
|
312
|
-
path: configFile,
|
|
313
|
-
provider: rawProvider,
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
throw new Error(`agent.json at ${configFile} must include provider: "azure", "minimax", "anthropic", "openai-codex", or "github-copilot".`);
|
|
317
|
-
}
|
|
318
|
-
const provider = rawProvider;
|
|
319
|
-
const rawVersion = parsed.version;
|
|
320
|
-
const version = rawVersion === undefined ? 1 : rawVersion;
|
|
321
|
-
if (typeof version !== "number" ||
|
|
322
|
-
!Number.isInteger(version) ||
|
|
351
|
+
// Validate v2 facing configs
|
|
352
|
+
const humanFacing = validateFacingConfig(parsed, "humanFacing", configFile);
|
|
353
|
+
const agentFacing = validateFacingConfig(parsed, "agentFacing", configFile);
|
|
354
|
+
const version = typeof parsed.version === "number" ? parsed.version : 1;
|
|
355
|
+
if (!Number.isInteger(version) ||
|
|
323
356
|
version < 1) {
|
|
324
357
|
(0, runtime_1.emitNervesEvent)({
|
|
325
358
|
level: "error",
|
|
@@ -328,7 +361,7 @@ function loadAgentConfig() {
|
|
|
328
361
|
message: "agent config missing or invalid version",
|
|
329
362
|
meta: {
|
|
330
363
|
path: configFile,
|
|
331
|
-
version:
|
|
364
|
+
version: parsed.version,
|
|
332
365
|
},
|
|
333
366
|
});
|
|
334
367
|
throw new Error(`agent.json at ${configFile} must include version as integer >= 1.`);
|
|
@@ -348,10 +381,15 @@ function loadAgentConfig() {
|
|
|
348
381
|
});
|
|
349
382
|
throw new Error(`agent.json at ${configFile} must include enabled as boolean.`);
|
|
350
383
|
}
|
|
384
|
+
// Tolerate deprecated provider field for backward compatibility
|
|
385
|
+
const rawProvider = parsed.provider;
|
|
386
|
+
const provider = isValidProvider(rawProvider) ? rawProvider : undefined;
|
|
351
387
|
const config = {
|
|
352
388
|
version,
|
|
353
389
|
enabled,
|
|
354
|
-
provider,
|
|
390
|
+
...(provider !== undefined ? { provider } : {}),
|
|
391
|
+
humanFacing,
|
|
392
|
+
agentFacing,
|
|
355
393
|
context: parsed.context,
|
|
356
394
|
logging: parsed.logging,
|
|
357
395
|
senses: normalizeSenses(parsed.senses, configFile),
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// v1 → v2 agent.json migration.
|
|
3
|
+
// Moves model from secrets.json into agent.json under humanFacing/agentFacing.
|
|
4
|
+
// Uses raw fs — NO import from config.ts (avoids circular dependency).
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.migrateAgentConfigV1ToV2 = migrateAgentConfigV1ToV2;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const runtime_1 = require("../nerves/runtime");
|
|
43
|
+
const MODEL_FIELD = {
|
|
44
|
+
azure: "modelName",
|
|
45
|
+
minimax: "model",
|
|
46
|
+
anthropic: "model",
|
|
47
|
+
"openai-codex": "model",
|
|
48
|
+
"github-copilot": "model",
|
|
49
|
+
};
|
|
50
|
+
function resolveSecretsPath(agentRoot, deps) {
|
|
51
|
+
const agentName = path.basename(agentRoot).replace(/\.ouro$/, "");
|
|
52
|
+
const secretsBase = deps?.secretsRoot ?? path.join(require("os").homedir(), ".agentsecrets");
|
|
53
|
+
return path.join(secretsBase, agentName, "secrets.json");
|
|
54
|
+
}
|
|
55
|
+
function migrateAgentConfigV1ToV2(agentRoot, deps) {
|
|
56
|
+
const configPath = path.join(agentRoot, "agent.json");
|
|
57
|
+
let raw;
|
|
58
|
+
try {
|
|
59
|
+
raw = fs.readFileSync(configPath, "utf-8");
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return; // No agent.json — nothing to migrate
|
|
63
|
+
}
|
|
64
|
+
let config;
|
|
65
|
+
try {
|
|
66
|
+
config = JSON.parse(raw);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new Error(`Cannot parse agent.json at ${configPath} — invalid JSON`);
|
|
70
|
+
}
|
|
71
|
+
const version = typeof config.version === "number" ? config.version : 1;
|
|
72
|
+
if (version >= 2) {
|
|
73
|
+
(0, runtime_1.emitNervesEvent)({
|
|
74
|
+
component: "config/identity",
|
|
75
|
+
event: "config_identity.migrate_skip",
|
|
76
|
+
message: "agent config already v2, skipping migration",
|
|
77
|
+
meta: { agentRoot },
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
(0, runtime_1.emitNervesEvent)({
|
|
82
|
+
component: "config/identity",
|
|
83
|
+
event: "config_identity.migrate_start",
|
|
84
|
+
message: "migrating agent config v1 → v2",
|
|
85
|
+
meta: { agentRoot },
|
|
86
|
+
});
|
|
87
|
+
const provider = config.provider;
|
|
88
|
+
let model = "";
|
|
89
|
+
if (provider) {
|
|
90
|
+
const secretsPath = resolveSecretsPath(agentRoot, deps);
|
|
91
|
+
try {
|
|
92
|
+
const secretsRaw = fs.readFileSync(secretsPath, "utf-8");
|
|
93
|
+
const secrets = JSON.parse(secretsRaw);
|
|
94
|
+
const providers = secrets.providers;
|
|
95
|
+
if (providers) {
|
|
96
|
+
const providerSecrets = providers[provider];
|
|
97
|
+
if (providerSecrets) {
|
|
98
|
+
/* v8 ignore next -- fallback: all known providers are in MODEL_FIELD @preserve */
|
|
99
|
+
const fieldName = MODEL_FIELD[provider] ?? "model";
|
|
100
|
+
const rawModel = providerSecrets[fieldName];
|
|
101
|
+
model = typeof rawModel === "string" ? rawModel : "";
|
|
102
|
+
// Strip model from secrets
|
|
103
|
+
delete providerSecrets[fieldName];
|
|
104
|
+
fs.writeFileSync(secretsPath, JSON.stringify(secrets, null, 2) + "\n", "utf-8");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Missing or malformed secrets.json — leave model as empty string
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Write v2 config
|
|
113
|
+
const { provider: _removed, ...rest } = config;
|
|
114
|
+
const v2Config = {
|
|
115
|
+
...rest,
|
|
116
|
+
version: 2,
|
|
117
|
+
humanFacing: { provider: provider ?? "anthropic", model },
|
|
118
|
+
agentFacing: { provider: provider ?? "anthropic", model },
|
|
119
|
+
};
|
|
120
|
+
fs.writeFileSync(configPath, JSON.stringify(v2Config, null, 2) + "\n", "utf-8");
|
|
121
|
+
(0, runtime_1.emitNervesEvent)({
|
|
122
|
+
component: "config/identity",
|
|
123
|
+
event: "config_identity.migrate_end",
|
|
124
|
+
message: "agent config migration complete",
|
|
125
|
+
meta: { agentRoot, provider: provider ?? "unknown", model },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
@@ -62,18 +62,31 @@ function hasEmptyCredentials(provider, config) {
|
|
|
62
62
|
return true;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
function createRuntimeForPing(provider,
|
|
65
|
+
function createRuntimeForPing(provider, _config) {
|
|
66
|
+
// The provider constructors read credentials from the active config via getXxxConfig().
|
|
67
|
+
// For ping, this is acceptable because verifyProviderCredentials patches the runtime
|
|
68
|
+
// config before calling ping. The model string is a default — for anthropic the ping
|
|
69
|
+
// overrides it with haiku anyway, and for others it's used in a minimal API call.
|
|
70
|
+
const DEFAULT_MODELS = {
|
|
71
|
+
anthropic: "claude-haiku-4-5-20251001",
|
|
72
|
+
azure: "gpt-4o",
|
|
73
|
+
minimax: "minimax-text-01",
|
|
74
|
+
"openai-codex": "codex-mini-latest",
|
|
75
|
+
"github-copilot": "gpt-4o",
|
|
76
|
+
};
|
|
77
|
+
/* v8 ignore next -- fallback: all known providers are in DEFAULT_MODELS @preserve */
|
|
78
|
+
const model = DEFAULT_MODELS[provider] ?? "unknown";
|
|
66
79
|
switch (provider) {
|
|
67
80
|
case "anthropic":
|
|
68
|
-
return (0, anthropic_1.createAnthropicProviderRuntime)(
|
|
81
|
+
return (0, anthropic_1.createAnthropicProviderRuntime)(model);
|
|
69
82
|
case "azure":
|
|
70
|
-
return (0, azure_1.createAzureProviderRuntime)(
|
|
83
|
+
return (0, azure_1.createAzureProviderRuntime)(model);
|
|
71
84
|
case "minimax":
|
|
72
|
-
return (0, minimax_1.createMinimaxProviderRuntime)(
|
|
85
|
+
return (0, minimax_1.createMinimaxProviderRuntime)(model);
|
|
73
86
|
case "openai-codex":
|
|
74
|
-
return (0, openai_codex_1.createOpenAICodexProviderRuntime)(
|
|
87
|
+
return (0, openai_codex_1.createOpenAICodexProviderRuntime)(model);
|
|
75
88
|
case "github-copilot":
|
|
76
|
-
return (0, github_copilot_1.createGithubCopilotProviderRuntime)(
|
|
89
|
+
return (0, github_copilot_1.createGithubCopilotProviderRuntime)(model);
|
|
77
90
|
/* v8 ignore next 2 -- exhaustive: all providers handled above @preserve */
|
|
78
91
|
default:
|
|
79
92
|
throw new Error(`unsupported provider for ping: ${provider}`);
|
|
@@ -417,25 +417,24 @@ async function streamAnthropicMessages(client, model, request) {
|
|
|
417
417
|
settleStreamed: answerStreamer.streamed,
|
|
418
418
|
};
|
|
419
419
|
}
|
|
420
|
-
function createAnthropicProviderRuntime(
|
|
420
|
+
function createAnthropicProviderRuntime(model) {
|
|
421
421
|
(0, runtime_1.emitNervesEvent)({
|
|
422
422
|
component: "engine",
|
|
423
423
|
event: "engine.provider_init",
|
|
424
424
|
message: "anthropic provider init",
|
|
425
425
|
meta: { provider: "anthropic" },
|
|
426
426
|
});
|
|
427
|
-
const anthropicConfig =
|
|
428
|
-
if (!
|
|
429
|
-
throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.
|
|
427
|
+
const anthropicConfig = (0, config_1.getAnthropicConfig)();
|
|
428
|
+
if (!anthropicConfig.setupToken) {
|
|
429
|
+
throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.setupToken is missing in secrets.json."));
|
|
430
430
|
}
|
|
431
|
-
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(
|
|
431
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
432
432
|
const capabilities = new Set();
|
|
433
433
|
if (modelCaps.reasoningEffort)
|
|
434
434
|
capabilities.add("reasoning-effort");
|
|
435
435
|
const credential = resolveAnthropicSetupTokenCredential();
|
|
436
|
-
const
|
|
437
|
-
const
|
|
438
|
-
const expiresAt = fullConfig.expiresAt;
|
|
436
|
+
const refreshToken = anthropicConfig.refreshToken;
|
|
437
|
+
const expiresAt = anthropicConfig.expiresAt;
|
|
439
438
|
function createClient(token) {
|
|
440
439
|
return new sdk_1.default({
|
|
441
440
|
authToken: token,
|
|
@@ -470,7 +469,7 @@ function createAnthropicProviderRuntime(config) {
|
|
|
470
469
|
/* v8 ignore stop */
|
|
471
470
|
return {
|
|
472
471
|
id: "anthropic",
|
|
473
|
-
model
|
|
472
|
+
model,
|
|
474
473
|
/* v8 ignore next -- getter: returns mutable client ref @preserve */
|
|
475
474
|
get client() { return client; },
|
|
476
475
|
capabilities,
|
|
@@ -483,7 +482,7 @@ function createAnthropicProviderRuntime(config) {
|
|
|
483
482
|
},
|
|
484
483
|
async streamTurn(request) {
|
|
485
484
|
const freshClient = await ensureClient();
|
|
486
|
-
return streamAnthropicMessages(freshClient,
|
|
485
|
+
return streamAnthropicMessages(freshClient, model, request);
|
|
487
486
|
},
|
|
488
487
|
/* v8 ignore next 3 -- delegation: classification logic tested via classifyAnthropicError @preserve */
|
|
489
488
|
classifyError(error) {
|
|
@@ -92,8 +92,8 @@ function createAzureTokenProvider(managedIdentityClientId) {
|
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
|
-
function createAzureProviderRuntime(
|
|
96
|
-
const azureConfig =
|
|
95
|
+
function createAzureProviderRuntime(model) {
|
|
96
|
+
const azureConfig = (0, config_1.getAzureConfig)();
|
|
97
97
|
const useApiKey = !!azureConfig.apiKey;
|
|
98
98
|
const authMethod = useApiKey ? "key" : "managed-identity";
|
|
99
99
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -102,10 +102,10 @@ function createAzureProviderRuntime(config) {
|
|
|
102
102
|
message: "azure provider init",
|
|
103
103
|
meta: { provider: "azure", authMethod },
|
|
104
104
|
});
|
|
105
|
-
if (!(azureConfig.endpoint && azureConfig.deployment
|
|
105
|
+
if (!(azureConfig.endpoint && azureConfig.deployment)) {
|
|
106
106
|
throw new Error("provider 'azure' is selected in agent.json but providers.azure is incomplete in secrets.json.");
|
|
107
107
|
}
|
|
108
|
-
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(
|
|
108
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
109
109
|
const capabilities = new Set();
|
|
110
110
|
if (modelCaps.reasoningEffort)
|
|
111
111
|
capabilities.add("reasoning-effort");
|
|
@@ -128,7 +128,7 @@ function createAzureProviderRuntime(config) {
|
|
|
128
128
|
let nativeInstructions = "";
|
|
129
129
|
return {
|
|
130
130
|
id: "azure",
|
|
131
|
-
model
|
|
131
|
+
model,
|
|
132
132
|
client,
|
|
133
133
|
capabilities,
|
|
134
134
|
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
@@ -34,22 +34,22 @@ function classifyGithubCopilotError(error) {
|
|
|
34
34
|
return "unknown";
|
|
35
35
|
}
|
|
36
36
|
/* v8 ignore stop */
|
|
37
|
-
function createGithubCopilotProviderRuntime(
|
|
37
|
+
function createGithubCopilotProviderRuntime(model) {
|
|
38
38
|
(0, runtime_1.emitNervesEvent)({
|
|
39
39
|
component: "engine",
|
|
40
40
|
event: "engine.provider_init",
|
|
41
41
|
message: "github-copilot provider init",
|
|
42
42
|
meta: { provider: "github-copilot" },
|
|
43
43
|
});
|
|
44
|
-
const config =
|
|
44
|
+
const config = (0, config_1.getGithubCopilotConfig)();
|
|
45
45
|
if (!config.githubToken) {
|
|
46
46
|
throw new Error("provider 'github-copilot' is selected in agent.json but providers.github-copilot.githubToken is missing in secrets.json.");
|
|
47
47
|
}
|
|
48
48
|
if (!config.baseUrl) {
|
|
49
49
|
throw new Error("provider 'github-copilot' is selected in agent.json but providers.github-copilot.baseUrl is missing in secrets.json.");
|
|
50
50
|
}
|
|
51
|
-
const isCompletionsModel =
|
|
52
|
-
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(
|
|
51
|
+
const isCompletionsModel = model.startsWith("claude");
|
|
52
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
53
53
|
const capabilities = new Set();
|
|
54
54
|
/* v8 ignore next -- branch: capability detection tested via unit test @preserve */
|
|
55
55
|
if (modelCaps.reasoningEffort)
|
|
@@ -64,7 +64,7 @@ function createGithubCopilotProviderRuntime(injectedConfig) {
|
|
|
64
64
|
// Chat completions path (Claude models via Copilot)
|
|
65
65
|
return {
|
|
66
66
|
id: "github-copilot",
|
|
67
|
-
model
|
|
67
|
+
model,
|
|
68
68
|
client,
|
|
69
69
|
capabilities,
|
|
70
70
|
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
@@ -106,7 +106,7 @@ function createGithubCopilotProviderRuntime(injectedConfig) {
|
|
|
106
106
|
let nativeInstructions = "";
|
|
107
107
|
return {
|
|
108
108
|
id: "github-copilot",
|
|
109
|
-
model
|
|
109
|
+
model,
|
|
110
110
|
client,
|
|
111
111
|
capabilities,
|
|
112
112
|
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
@@ -32,19 +32,19 @@ function classifyMinimaxError(error) {
|
|
|
32
32
|
}
|
|
33
33
|
const streaming_1 = require("../streaming");
|
|
34
34
|
const model_capabilities_1 = require("../model-capabilities");
|
|
35
|
-
function createMinimaxProviderRuntime(
|
|
35
|
+
function createMinimaxProviderRuntime(model) {
|
|
36
36
|
(0, runtime_1.emitNervesEvent)({
|
|
37
37
|
component: "engine",
|
|
38
38
|
event: "engine.provider_init",
|
|
39
39
|
message: "minimax provider init",
|
|
40
40
|
meta: { provider: "minimax" },
|
|
41
41
|
});
|
|
42
|
-
const minimaxConfig =
|
|
42
|
+
const minimaxConfig = (0, config_1.getMinimaxConfig)();
|
|
43
43
|
if (!minimaxConfig.apiKey) {
|
|
44
44
|
throw new Error("provider 'minimax' is selected in agent.json but providers.minimax.apiKey is missing in secrets.json.");
|
|
45
45
|
}
|
|
46
46
|
// Registry consulted; MiniMax models return empty defaults (no capabilities to derive)
|
|
47
|
-
(0, model_capabilities_1.getModelCapabilities)(
|
|
47
|
+
(0, model_capabilities_1.getModelCapabilities)(model);
|
|
48
48
|
const client = new openai_1.default({
|
|
49
49
|
apiKey: minimaxConfig.apiKey,
|
|
50
50
|
baseURL: "https://api.minimaxi.chat/v1",
|
|
@@ -53,7 +53,7 @@ function createMinimaxProviderRuntime(config) {
|
|
|
53
53
|
});
|
|
54
54
|
return {
|
|
55
55
|
id: "minimax",
|
|
56
|
-
model
|
|
56
|
+
model,
|
|
57
57
|
client,
|
|
58
58
|
capabilities: new Set(),
|
|
59
59
|
resetTurnState(_messages) {
|
|
@@ -110,16 +110,16 @@ function getChatGPTAccountIdFromToken(token) {
|
|
|
110
110
|
return "";
|
|
111
111
|
return accountId.trim();
|
|
112
112
|
}
|
|
113
|
-
function createOpenAICodexProviderRuntime(
|
|
113
|
+
function createOpenAICodexProviderRuntime(model) {
|
|
114
114
|
(0, runtime_1.emitNervesEvent)({
|
|
115
115
|
component: "engine",
|
|
116
116
|
event: "engine.provider_init",
|
|
117
117
|
message: "openai-codex provider init",
|
|
118
118
|
meta: { provider: "openai-codex" },
|
|
119
119
|
});
|
|
120
|
-
const codexConfig =
|
|
121
|
-
if (!
|
|
122
|
-
throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.
|
|
120
|
+
const codexConfig = (0, config_1.getOpenAICodexConfig)();
|
|
121
|
+
if (!codexConfig.oauthAccessToken) {
|
|
122
|
+
throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.oauthAccessToken is missing in secrets.json."));
|
|
123
123
|
}
|
|
124
124
|
const token = codexConfig.oauthAccessToken.trim();
|
|
125
125
|
if (!token) {
|
|
@@ -129,7 +129,7 @@ function createOpenAICodexProviderRuntime(config) {
|
|
|
129
129
|
if (!chatgptAccountId) {
|
|
130
130
|
throw new Error(getOpenAICodexReauthGuidance("OpenAI Codex OAuth access token is missing a chatgpt_account_id claim required for chatgpt.com/backend-api/codex."));
|
|
131
131
|
}
|
|
132
|
-
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(
|
|
132
|
+
const modelCaps = (0, model_capabilities_1.getModelCapabilities)(model);
|
|
133
133
|
const capabilities = new Set();
|
|
134
134
|
if (modelCaps.reasoningEffort)
|
|
135
135
|
capabilities.add("reasoning-effort");
|
|
@@ -150,7 +150,7 @@ function createOpenAICodexProviderRuntime(config) {
|
|
|
150
150
|
let nativeInstructions = "";
|
|
151
151
|
return {
|
|
152
152
|
id: "openai-codex",
|
|
153
|
-
model
|
|
153
|
+
model,
|
|
154
154
|
client,
|
|
155
155
|
capabilities,
|
|
156
156
|
supportedReasoningEfforts: modelCaps.reasoningEffort,
|
|
@@ -2,10 +2,22 @@
|
|
|
2
2
|
// Channel capabilities -- hardcoded const map keyed by channel identifier.
|
|
3
3
|
// Pure lookup, no I/O, cannot fail. Unknown channel gets minimal defaults.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.channelToFacing = channelToFacing;
|
|
5
6
|
exports.getChannelCapabilities = getChannelCapabilities;
|
|
6
7
|
exports.isRemoteChannel = isRemoteChannel;
|
|
7
8
|
exports.getAlwaysOnSenseNames = getAlwaysOnSenseNames;
|
|
8
9
|
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
+
const AGENT_FACING_CHANNELS = new Set(["inner", "mcp"]);
|
|
11
|
+
function channelToFacing(channel) {
|
|
12
|
+
const facing = channel && AGENT_FACING_CHANNELS.has(channel) ? "agent" : "human";
|
|
13
|
+
(0, runtime_1.emitNervesEvent)({
|
|
14
|
+
component: "channels",
|
|
15
|
+
event: "channel.facing_lookup",
|
|
16
|
+
message: "channel facing lookup",
|
|
17
|
+
meta: { channel: channel ?? "undefined", facing },
|
|
18
|
+
});
|
|
19
|
+
return facing;
|
|
20
|
+
}
|
|
9
21
|
const CHANNEL_CAPABILITIES = {
|
|
10
22
|
cli: {
|
|
11
23
|
channel: "cli",
|
package/dist/mind/prompt.js
CHANGED
|
@@ -368,8 +368,8 @@ function senseRuntimeGuidance(channel) {
|
|
|
368
368
|
}
|
|
369
369
|
return lines;
|
|
370
370
|
}
|
|
371
|
-
function providerSection() {
|
|
372
|
-
return `## my provider\n${(0, core_1.getProviderDisplayLabel)()}`;
|
|
371
|
+
function providerSection(channel) {
|
|
372
|
+
return `## my provider\n${(0, core_1.getProviderDisplayLabel)((0, channel_1.channelToFacing)(channel))}`;
|
|
373
373
|
}
|
|
374
374
|
function dateSection() {
|
|
375
375
|
const today = new Date().toISOString().slice(0, 10);
|
|
@@ -943,7 +943,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
943
943
|
runtimeInfoSection(channel),
|
|
944
944
|
rhythmStatusSection(),
|
|
945
945
|
channelNatureSection((0, channel_1.getChannelCapabilities)(channel)),
|
|
946
|
-
providerSection(),
|
|
946
|
+
providerSection(channel),
|
|
947
947
|
dateSection(),
|
|
948
948
|
toolsSection(channel, options, context),
|
|
949
949
|
mcpToolsSection(options?.mcpManager),
|