@ouro.bot/cli 0.1.0-alpha.158 → 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 +10 -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 +36 -10
- 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/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 +3 -2
- package/dist/senses/teams.js +1 -1
- package/package.json +1 -1
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),
|
|
@@ -441,7 +441,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
|
|
|
441
441
|
hydrated.balloonBundleId !== "com.apple.messages.URLBalloonProvider" &&
|
|
442
442
|
hydrated.attachments.length > 0) {
|
|
443
443
|
const media = await (0, bluebubbles_media_1.hydrateBlueBubblesAttachments)(hydrated.attachments, config, channelConfig, {
|
|
444
|
-
preferAudioInput: providerSupportsAudioInput((0, identity_1.loadAgentConfig)().provider),
|
|
444
|
+
preferAudioInput: providerSupportsAudioInput((0, identity_1.loadAgentConfig)().humanFacing.provider),
|
|
445
445
|
});
|
|
446
446
|
const transcriptSuffix = media.transcriptAdditions.map((entry) => `[${entry}]`).join("\n");
|
|
447
447
|
const noticeSuffix = media.notices.map((entry) => `[${entry}]`).join("\n");
|
|
@@ -711,7 +711,7 @@ async function handleBlueBubblesNormalizedEvent(event, resolvedDeps, source) {
|
|
|
711
711
|
const callbacks = createBlueBubblesCallbacks(client, event.chat, replyTarget, event.chat.isGroup);
|
|
712
712
|
const controller = new AbortController();
|
|
713
713
|
// BB-specific tool context wrappers
|
|
714
|
-
const summarize = (0, core_1.createSummarize)();
|
|
714
|
+
const summarize = (0, core_1.createSummarize)("human");
|
|
715
715
|
const bbCapabilities = (0, channel_1.getChannelCapabilities)("bluebubbles");
|
|
716
716
|
const pendingDir = (0, pending_1.getPendingDir)(resolvedDeps.getAgentName(), friendId, "bluebubbles", event.chat.sessionKey);
|
|
717
717
|
// ── Compute trust gate context for group/acquaintance rules ─────
|
package/dist/senses/cli.js
CHANGED
|
@@ -72,6 +72,7 @@ const channel_1 = require("../mind/friends/channel");
|
|
|
72
72
|
const session_lock_1 = require("./session-lock");
|
|
73
73
|
const update_hooks_1 = require("../heart/daemon/update-hooks");
|
|
74
74
|
const bundle_meta_1 = require("../heart/daemon/hooks/bundle-meta");
|
|
75
|
+
const agent_config_v2_1 = require("../heart/daemon/hooks/agent-config-v2");
|
|
75
76
|
const bundle_manifest_1 = require("../mind/bundle-manifest");
|
|
76
77
|
const cli_layout_1 = require("./cli-layout");
|
|
77
78
|
var cli_layout_2 = require("./cli-layout");
|
|
@@ -782,9 +783,10 @@ async function main(agentName, options) {
|
|
|
782
783
|
(0, nerves_1.registerSpinnerHooks)(pauseActiveSpinner, resumeActiveSpinner);
|
|
783
784
|
// Fallback: apply pending updates for daemon-less direct CLI usage
|
|
784
785
|
(0, update_hooks_1.registerUpdateHook)(bundle_meta_1.bundleMetaHook);
|
|
786
|
+
(0, update_hooks_1.registerUpdateHook)(agent_config_v2_1.agentConfigV2Hook);
|
|
785
787
|
await (0, update_hooks_1.applyPendingUpdates)((0, identity_1.getAgentBundlesRoot)(), (0, bundle_manifest_1.getPackageVersion)());
|
|
786
788
|
// Fail fast if provider is misconfigured (triggers human-readable error + exit)
|
|
787
|
-
(0, core_1.getProvider)();
|
|
789
|
+
(0, core_1.getProvider)("human");
|
|
788
790
|
// Resolve context kernel (identity + channel) for CLI
|
|
789
791
|
const friendsPath = path.join((0, identity_1.getAgentRoot)(), "friends");
|
|
790
792
|
const friendStore = new store_file_1.FileFriendStore(friendsPath);
|
|
@@ -829,7 +831,7 @@ async function main(agentName, options) {
|
|
|
829
831
|
const cliCapabilities = (0, channel_1.getChannelCapabilities)("cli");
|
|
830
832
|
const currentAgentName = (0, identity_1.getAgentName)();
|
|
831
833
|
const pendingDir = (0, pending_1.getPendingDir)(currentAgentName, friendId, "cli", "session");
|
|
832
|
-
const summarize = (0, core_1.createSummarize)();
|
|
834
|
+
const summarize = (0, core_1.createSummarize)("human");
|
|
833
835
|
const cliFailoverState = { pending: null };
|
|
834
836
|
try {
|
|
835
837
|
await runCliSession({
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -124,7 +124,8 @@ async function handleInboundTurn(input) {
|
|
|
124
124
|
if (failoverAction.action === "switch") {
|
|
125
125
|
let switchSucceeded = false;
|
|
126
126
|
try {
|
|
127
|
-
(0, auth_flow_1.writeAgentProviderSelection)(failoverAgentName, failoverAction.provider);
|
|
127
|
+
(0, auth_flow_1.writeAgentProviderSelection)(failoverAgentName, "human", failoverAction.provider);
|
|
128
|
+
(0, auth_flow_1.writeAgentProviderSelection)(failoverAgentName, "agent", failoverAction.provider);
|
|
128
129
|
switchSucceeded = true;
|
|
129
130
|
/* v8 ignore start -- defensive: write failure during provider switch @preserve */
|
|
130
131
|
}
|
|
@@ -416,7 +417,7 @@ async function handleInboundTurn(input) {
|
|
|
416
417
|
try {
|
|
417
418
|
const agentName = (0, identity_1.getAgentName)();
|
|
418
419
|
const agentConfig = (0, identity_1.loadAgentConfig)();
|
|
419
|
-
const currentProvider = agentConfig.provider;
|
|
420
|
+
const currentProvider = agentConfig.humanFacing.provider;
|
|
420
421
|
/* v8 ignore next -- defensive: errorClassification always set when errored @preserve */
|
|
421
422
|
const classification = result.errorClassification ?? "unknown";
|
|
422
423
|
const inventory = await (0, provider_ping_1.runHealthInventory)(agentName, currentProvider);
|