@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.
@@ -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: 1,
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
- * Load and parse `<agentRoot>/agent.json`.
236
- * Reads the file fresh on each call unless an override is set.
237
- * Throws descriptive error if file is missing or contains invalid JSON.
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
- parsed = JSON.parse(raw);
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
- const rawProvider = parsed.provider;
301
- if (rawProvider !== "azure" &&
302
- rawProvider !== "minimax" &&
303
- rawProvider !== "anthropic" &&
304
- rawProvider !== "openai-codex" &&
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: rawVersion,
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, config) {
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)(config);
81
+ return (0, anthropic_1.createAnthropicProviderRuntime)(model);
69
82
  case "azure":
70
- return (0, azure_1.createAzureProviderRuntime)(config);
83
+ return (0, azure_1.createAzureProviderRuntime)(model);
71
84
  case "minimax":
72
- return (0, minimax_1.createMinimaxProviderRuntime)(config);
85
+ return (0, minimax_1.createMinimaxProviderRuntime)(model);
73
86
  case "openai-codex":
74
- return (0, openai_codex_1.createOpenAICodexProviderRuntime)(config);
87
+ return (0, openai_codex_1.createOpenAICodexProviderRuntime)(model);
75
88
  case "github-copilot":
76
- return (0, github_copilot_1.createGithubCopilotProviderRuntime)(config);
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(config) {
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 = config ?? (0, config_1.getAnthropicConfig)();
428
- if (!(anthropicConfig.model && anthropicConfig.setupToken)) {
429
- throw new Error(getAnthropicReauthGuidance("provider 'anthropic' is selected in agent.json but providers.anthropic.model/setupToken is incomplete in secrets.json."));
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)(anthropicConfig.model);
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 fullConfig = config ?? (0, config_1.getAnthropicConfig)();
437
- const refreshToken = fullConfig.refreshToken;
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: anthropicConfig.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, anthropicConfig.model, request);
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(config) {
96
- const azureConfig = config ?? (0, config_1.getAzureConfig)();
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 && azureConfig.modelName)) {
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)(azureConfig.modelName);
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: azureConfig.modelName,
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(injectedConfig) {
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 = injectedConfig ?? (0, config_1.getGithubCopilotConfig)();
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 = config.model.startsWith("claude");
52
- const modelCaps = (0, model_capabilities_1.getModelCapabilities)(config.model);
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: config.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: config.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(config) {
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 = config ?? (0, config_1.getMinimaxConfig)();
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)(minimaxConfig.model);
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: minimaxConfig.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(config) {
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 = config ?? (0, config_1.getOpenAICodexConfig)();
121
- if (!(codexConfig.model && codexConfig.oauthAccessToken)) {
122
- throw new Error(getOpenAICodexReauthGuidance("provider 'openai-codex' is selected in agent.json but providers.openai-codex.model/oauthAccessToken is incomplete in secrets.json."));
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)(codexConfig.model);
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: codexConfig.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",
@@ -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 ─────
@@ -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({
@@ -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);