@ouro.bot/cli 0.1.0-alpha.364 → 0.1.0-alpha.365
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -6
- package/changelog.json +9 -0
- package/dist/heart/auth/auth-flow.js +25 -110
- package/dist/heart/config.js +69 -55
- package/dist/heart/core.js +83 -33
- package/dist/heart/daemon/agent-config-check.js +41 -238
- package/dist/heart/daemon/agentic-repair.js +1 -1
- package/dist/heart/daemon/cli-defaults.js +15 -68
- package/dist/heart/daemon/cli-exec.js +246 -89
- package/dist/heart/daemon/cli-parse.js +71 -0
- package/dist/heart/daemon/daemon-cli.js +1 -2
- package/dist/heart/daemon/daemon-entry.js +1 -3
- package/dist/heart/daemon/doctor.js +9 -29
- package/dist/heart/daemon/provider-discovery.js +32 -59
- package/dist/heart/hatch/hatch-flow.js +9 -12
- package/dist/heart/hatch/specialist-prompt.js +1 -1
- package/dist/heart/hatch/specialist-tools.js +21 -1
- package/dist/heart/migrate-config.js +15 -42
- package/dist/heart/provider-binding-resolver.js +6 -7
- package/dist/heart/provider-credentials.js +379 -0
- package/dist/heart/provider-failover.js +3 -11
- package/dist/heart/provider-ping.js +13 -3
- package/dist/heart/provider-state.js +8 -0
- package/dist/heart/provider-visibility.js +3 -6
- package/dist/heart/providers/anthropic-token.js +15 -47
- package/dist/heart/providers/anthropic.js +4 -9
- package/dist/heart/providers/azure.js +3 -3
- package/dist/heart/providers/github-copilot.js +2 -2
- package/dist/heart/providers/minimax-vlm.js +2 -2
- package/dist/heart/providers/minimax.js +1 -1
- package/dist/heart/providers/openai-codex.js +4 -9
- package/dist/repertoire/bitwarden-store.js +63 -17
- package/dist/repertoire/bundle-templates.js +2 -2
- package/dist/repertoire/credential-access.js +47 -467
- package/dist/repertoire/tools-attachments.js +5 -4
- package/dist/repertoire/tools-vault.js +10 -80
- package/dist/repertoire/vault-unlock.js +359 -0
- package/dist/senses/bluebubbles/client.js +39 -4
- package/dist/senses/pipeline.js +0 -1
- package/package.json +1 -1
- package/dist/heart/provider-credential-pool.js +0 -395
|
@@ -300,38 +300,18 @@ function checkHabits(deps) {
|
|
|
300
300
|
function checkSecurity(deps) {
|
|
301
301
|
const checks = [];
|
|
302
302
|
const agents = discoverAgents(deps);
|
|
303
|
-
const providerPoolPath = `${deps.secretsRoot}/providers.json`;
|
|
304
|
-
if (deps.existsSync(providerPoolPath)) {
|
|
305
|
-
const stat = deps.statSync(providerPoolPath);
|
|
306
|
-
const worldReadable = (stat.mode & 0o004) !== 0;
|
|
307
|
-
checks.push({
|
|
308
|
-
label: "machine provider credentials perms",
|
|
309
|
-
status: worldReadable ? "warn" : "pass",
|
|
310
|
-
detail: worldReadable ? "world-readable — consider chmod 600" : "not world-readable",
|
|
311
|
-
});
|
|
312
|
-
try {
|
|
313
|
-
JSON.parse(deps.readFileSync(providerPoolPath));
|
|
314
|
-
checks.push({ label: "machine provider credentials", status: "pass", detail: "readable JSON" });
|
|
315
|
-
}
|
|
316
|
-
catch {
|
|
317
|
-
checks.push({ label: "machine provider credentials", status: "fail", detail: "unparseable JSON" });
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
303
|
for (const agentDir of agents) {
|
|
321
304
|
const agentName = agentDir.replace(/\.ouro$/, "");
|
|
322
305
|
const secretsPath = `${deps.secretsRoot}/${agentName}/secrets.json`;
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
checks.push({ label: `${agentDir} secrets.json perms`, status: "pass", detail: "not world-readable" });
|
|
306
|
+
if (deps.existsSync(secretsPath)) {
|
|
307
|
+
const stat = deps.statSync(secretsPath);
|
|
308
|
+
const worldReadable = (stat.mode & 0o004) !== 0;
|
|
309
|
+
if (worldReadable) {
|
|
310
|
+
checks.push({ label: `${agentDir} legacy secrets.json perms`, status: "warn", detail: "world-readable — consider deleting or chmod 600" });
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
checks.push({ label: `${agentDir} legacy secrets.json perms`, status: "pass", detail: "not world-readable" });
|
|
314
|
+
}
|
|
335
315
|
}
|
|
336
316
|
// Check agent.json for leaked credential keys
|
|
337
317
|
const configPath = `${deps.bundlesRoot}/${agentDir}/agent.json`;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Shared provider discovery
|
|
3
|
+
* Shared provider discovery for repair.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Runtime repair only trusts the agent vault. First-run conveniences may still
|
|
6
|
+
* inspect env vars before credentials are stored, but once an agent exists the
|
|
7
|
+
* vault is the source of truth.
|
|
7
8
|
*/
|
|
8
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
10
|
exports.scanEnvVarCredentials = scanEnvVarCredentials;
|
|
10
11
|
exports.discoverWorkingProvider = discoverWorkingProvider;
|
|
11
12
|
const identity_1 = require("../identity");
|
|
12
|
-
const
|
|
13
|
+
const provider_credentials_1 = require("../provider-credentials");
|
|
13
14
|
const runtime_1 = require("../../nerves/runtime");
|
|
14
15
|
/**
|
|
15
|
-
* Scan environment variables for API keys
|
|
16
|
-
*
|
|
16
|
+
* Scan environment variables for API keys during first-run bootstrap.
|
|
17
|
+
* This does not participate in runtime provider repair.
|
|
17
18
|
*/
|
|
18
19
|
function scanEnvVarCredentials(env) {
|
|
19
20
|
const results = [];
|
|
@@ -25,7 +26,6 @@ function scanEnvVarCredentials(env) {
|
|
|
25
26
|
cred[credKey] = value;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
|
-
// Only register if at least one required field was found
|
|
29
29
|
const hasRequired = desc.required.some((key) => !!cred[key]);
|
|
30
30
|
if (hasRequired) {
|
|
31
31
|
results.push({
|
|
@@ -45,62 +45,35 @@ function stringifyProviderFields(fields) {
|
|
|
45
45
|
}
|
|
46
46
|
return result;
|
|
47
47
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const homeDir = (0, provider_credential_pool_1.providerCredentialHomeDirFromSecretsRoot)(secretsRoot);
|
|
56
|
-
const poolResult = (0, provider_credential_pool_1.readProviderCredentialPool)(homeDir);
|
|
57
|
-
if (!poolResult.ok)
|
|
58
|
-
return [];
|
|
59
|
-
const credentials = [];
|
|
60
|
-
for (const [, record] of Object.entries(poolResult.pool.providers)) {
|
|
61
|
-
credentials.push({
|
|
62
|
-
provider: record.provider,
|
|
63
|
-
agentName: machinePoolSource(record),
|
|
64
|
-
credentials: stringifyProviderFields(record.credentials),
|
|
65
|
-
providerConfig: stringifyProviderFields(record.config),
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return credentials;
|
|
48
|
+
function discoveredFromVaultRecord(record) {
|
|
49
|
+
return {
|
|
50
|
+
provider: record.provider,
|
|
51
|
+
agentName: "vault",
|
|
52
|
+
credentials: stringifyProviderFields(record.credentials),
|
|
53
|
+
providerConfig: stringifyProviderFields(record.config),
|
|
54
|
+
};
|
|
69
55
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Discover the first working provider by scanning configured credential sources,
|
|
72
|
-
* deduplicating by provider, and pinging each candidate.
|
|
73
|
-
*/
|
|
74
56
|
async function discoverWorkingProvider(deps) {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
for (const cred of diskCreds) {
|
|
86
|
-
if (!seenProviders.has(cred.provider)) {
|
|
87
|
-
seenProviders.add(cred.provider);
|
|
88
|
-
candidates.push(cred);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
for (const cred of envCreds) {
|
|
92
|
-
if (!seenProviders.has(cred.provider)) {
|
|
93
|
-
seenProviders.add(cred.provider);
|
|
94
|
-
candidates.push(cred);
|
|
95
|
-
}
|
|
57
|
+
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(deps.agentName);
|
|
58
|
+
if (!poolResult.ok) {
|
|
59
|
+
(0, runtime_1.emitNervesEvent)({
|
|
60
|
+
level: "warn",
|
|
61
|
+
component: "daemon",
|
|
62
|
+
event: "daemon.provider_discovery_none",
|
|
63
|
+
message: "provider discovery could not read agent vault",
|
|
64
|
+
meta: { agentName: deps.agentName, reason: poolResult.reason },
|
|
65
|
+
});
|
|
66
|
+
return null;
|
|
96
67
|
}
|
|
68
|
+
const candidates = Object.entries(poolResult.pool.providers)
|
|
69
|
+
.map(([, record]) => discoveredFromVaultRecord(record));
|
|
97
70
|
if (candidates.length === 0) {
|
|
98
71
|
(0, runtime_1.emitNervesEvent)({
|
|
99
72
|
level: "info",
|
|
100
73
|
component: "daemon",
|
|
101
74
|
event: "daemon.provider_discovery_none",
|
|
102
|
-
message: "no provider credentials found in
|
|
103
|
-
meta: {},
|
|
75
|
+
message: "no provider credentials found in agent vault",
|
|
76
|
+
meta: { agentName: deps.agentName },
|
|
104
77
|
});
|
|
105
78
|
return null;
|
|
106
79
|
}
|
|
@@ -111,7 +84,7 @@ async function discoverWorkingProvider(deps) {
|
|
|
111
84
|
component: "daemon",
|
|
112
85
|
event: "daemon.provider_discovery_ping",
|
|
113
86
|
message: `pinging provider: ${candidate.provider}`,
|
|
114
|
-
meta: { provider: candidate.provider, source: candidate.agentName },
|
|
87
|
+
meta: { agentName: deps.agentName, provider: candidate.provider, source: candidate.agentName },
|
|
115
88
|
});
|
|
116
89
|
const result = await deps.pingProvider(candidate.provider, config);
|
|
117
90
|
if (result.ok) {
|
|
@@ -120,7 +93,7 @@ async function discoverWorkingProvider(deps) {
|
|
|
120
93
|
component: "daemon",
|
|
121
94
|
event: "daemon.provider_discovery_ok",
|
|
122
95
|
message: `provider discovery succeeded: ${candidate.provider}`,
|
|
123
|
-
meta: { provider: candidate.provider, source: candidate.agentName },
|
|
96
|
+
meta: { agentName: deps.agentName, provider: candidate.provider, source: candidate.agentName },
|
|
124
97
|
});
|
|
125
98
|
return {
|
|
126
99
|
provider: candidate.provider,
|
|
@@ -133,8 +106,8 @@ async function discoverWorkingProvider(deps) {
|
|
|
133
106
|
level: "warn",
|
|
134
107
|
component: "daemon",
|
|
135
108
|
event: "daemon.provider_discovery_all_failed",
|
|
136
|
-
message: "all provider candidates failed ping",
|
|
137
|
-
meta: { candidateCount: candidates.length },
|
|
109
|
+
message: "all vault provider candidates failed ping",
|
|
110
|
+
meta: { agentName: deps.agentName, candidateCount: candidates.length },
|
|
138
111
|
});
|
|
139
112
|
return null;
|
|
140
113
|
}
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
36
|
+
exports.storeHatchlingProviderCredentials = storeHatchlingProviderCredentials;
|
|
37
37
|
exports.runHatchFlow = runHatchFlow;
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const os = __importStar(require("os"));
|
|
@@ -45,7 +45,7 @@ const auth_flow_1 = require("../auth/auth-flow");
|
|
|
45
45
|
const provider_models_1 = require("../provider-models");
|
|
46
46
|
const habit_parser_1 = require("../habits/habit-parser");
|
|
47
47
|
const machine_identity_1 = require("../machine-identity");
|
|
48
|
-
const
|
|
48
|
+
const provider_credentials_1 = require("../provider-credentials");
|
|
49
49
|
const provider_state_1 = require("../provider-state");
|
|
50
50
|
const hatch_specialist_1 = require("./hatch-specialist");
|
|
51
51
|
function requiredCredentialKeys(provider) {
|
|
@@ -67,8 +67,8 @@ function validateCredentials(provider, credentials) {
|
|
|
67
67
|
throw new Error(`Missing required credentials for ${provider}: ${missing.join(", ")}`);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
return (0, auth_flow_1.
|
|
70
|
+
async function storeHatchlingProviderCredentials(agentName, provider, credentials) {
|
|
71
|
+
return (await (0, auth_flow_1.storeProviderCredentials)(agentName, provider, credentials)).credentialPath;
|
|
72
72
|
}
|
|
73
73
|
function writeReadme(dir, purpose) {
|
|
74
74
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -135,10 +135,10 @@ function writeHatchlingAgentConfig(bundleRoot, input) {
|
|
|
135
135
|
template.enabled = true;
|
|
136
136
|
fs.writeFileSync(path.join(bundleRoot, "agent.json"), `${JSON.stringify(template, null, 2)}\n`, "utf-8");
|
|
137
137
|
}
|
|
138
|
-
function writeHatchlingProviderState(bundleRoot, input,
|
|
138
|
+
function writeHatchlingProviderState(bundleRoot, input, now) {
|
|
139
139
|
const model = (0, provider_models_1.getDefaultModelForProvider)(input.provider);
|
|
140
140
|
const machine = (0, machine_identity_1.loadOrCreateMachineIdentity)({
|
|
141
|
-
homeDir: (0,
|
|
141
|
+
homeDir: (0, provider_credentials_1.providerCredentialMachineHomeDir)(),
|
|
142
142
|
now: () => now,
|
|
143
143
|
});
|
|
144
144
|
const state = (0, provider_state_1.bootstrapProviderStateFromAgentConfig)({
|
|
@@ -160,7 +160,6 @@ async function runHatchFlow(input, deps = {}) {
|
|
|
160
160
|
});
|
|
161
161
|
validateCredentials(input.provider, input.credentials);
|
|
162
162
|
const bundlesRoot = deps.bundlesRoot ?? path.join(os.homedir(), "AgentBundles");
|
|
163
|
-
const secretsRoot = deps.secretsRoot ?? path.join(os.homedir(), ".agentsecrets");
|
|
164
163
|
const sourceIdentities = deps.specialistIdentitySourceDir ?? (0, hatch_specialist_1.getSpecialistIdentitySourceDir)();
|
|
165
164
|
const targetIdentities = deps.specialistIdentityTargetDir ?? (0, hatch_specialist_1.getRepoSpecialistIdentitiesDir)();
|
|
166
165
|
const now = deps.now ? deps.now() : new Date();
|
|
@@ -173,8 +172,6 @@ async function runHatchFlow(input, deps = {}) {
|
|
|
173
172
|
identitiesDir: targetIdentities,
|
|
174
173
|
random,
|
|
175
174
|
});
|
|
176
|
-
const specialistSecretsPath = writeSecretsFile("SerpentGuide", input.provider, input.credentials, secretsRoot);
|
|
177
|
-
const hatchlingSecretsPath = writeSecretsFile(input.agentName, input.provider, input.credentials, secretsRoot);
|
|
178
175
|
const bundleRoot = path.join(bundlesRoot, `${input.agentName}.ouro`);
|
|
179
176
|
fs.mkdirSync(bundleRoot, { recursive: true });
|
|
180
177
|
writeReadme(bundleRoot, "Root of this agent bundle.");
|
|
@@ -189,7 +186,8 @@ async function runHatchFlow(input, deps = {}) {
|
|
|
189
186
|
writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
|
|
190
187
|
writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
|
|
191
188
|
writeHatchlingAgentConfig(bundleRoot, input);
|
|
192
|
-
|
|
189
|
+
const credentialPath = await storeHatchlingProviderCredentials(input.agentName, input.provider, input.credentials);
|
|
190
|
+
writeHatchlingProviderState(bundleRoot, input, now);
|
|
193
191
|
writeDiaryScaffold(bundleRoot);
|
|
194
192
|
writeFriendImprint(bundleRoot, input.humanName, now);
|
|
195
193
|
writeHeartbeatHabit(bundleRoot, now);
|
|
@@ -202,7 +200,6 @@ async function runHatchFlow(input, deps = {}) {
|
|
|
202
200
|
return {
|
|
203
201
|
bundleRoot,
|
|
204
202
|
selectedIdentity: selected.fileName,
|
|
205
|
-
|
|
206
|
-
hatchlingSecretsPath,
|
|
203
|
+
credentialPath,
|
|
207
204
|
};
|
|
208
205
|
}
|
|
@@ -44,7 +44,7 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles, co
|
|
|
44
44
|
`Provider: ${context.provider}`,
|
|
45
45
|
`Temp directory: ${context.tempDir}`,
|
|
46
46
|
"Final home: ~/AgentBundles/<Name>.ouro/",
|
|
47
|
-
"
|
|
47
|
+
"Provider credentials: the hatch tool stores them in the agent's vault.",
|
|
48
48
|
].join("\n"));
|
|
49
49
|
sections.push([
|
|
50
50
|
"## Bundle creation guidelines",
|
|
@@ -42,7 +42,10 @@ const tools_base_1 = require("../../repertoire/tools-base");
|
|
|
42
42
|
const hatch_flow_1 = require("./hatch-flow");
|
|
43
43
|
const hatch_animation_1 = require("./hatch-animation");
|
|
44
44
|
const bundle_manifest_1 = require("../../mind/bundle-manifest");
|
|
45
|
+
const identity_1 = require("../identity");
|
|
45
46
|
const runtime_1 = require("../../nerves/runtime");
|
|
47
|
+
const vault_setup_1 = require("../../repertoire/vault-setup");
|
|
48
|
+
const vault_unlock_1 = require("../../repertoire/vault-unlock");
|
|
46
49
|
const completeAdoptionTool = {
|
|
47
50
|
type: "function",
|
|
48
51
|
function: {
|
|
@@ -171,8 +174,17 @@ async function execCompleteAdoption(args, deps) {
|
|
|
171
174
|
// Move tempDir -> final bundle location
|
|
172
175
|
moveDir(deps.tempDir, targetBundle);
|
|
173
176
|
// Write secrets
|
|
177
|
+
let generatedVaultUnlockSecret = null;
|
|
174
178
|
try {
|
|
175
|
-
(0,
|
|
179
|
+
const vault = (0, identity_1.resolveVaultConfig)(name);
|
|
180
|
+
const vaultUnlockSecret = crypto.randomBytes(32).toString("base64");
|
|
181
|
+
const vaultResult = await (0, vault_setup_1.createVaultAccount)(name, vault.serverUrl, vault.email, vaultUnlockSecret);
|
|
182
|
+
if (!vaultResult.success) {
|
|
183
|
+
throw new Error(`failed to create vault: ${vaultResult.error}`);
|
|
184
|
+
}
|
|
185
|
+
(0, vault_unlock_1.storeVaultUnlockSecret)({ agentName: name, email: vault.email, serverUrl: vault.serverUrl }, vaultUnlockSecret);
|
|
186
|
+
generatedVaultUnlockSecret = vaultUnlockSecret;
|
|
187
|
+
await (0, hatch_flow_1.storeHatchlingProviderCredentials)(name, deps.provider, deps.credentials);
|
|
176
188
|
}
|
|
177
189
|
catch (e) {
|
|
178
190
|
// Rollback: remove the moved bundle
|
|
@@ -217,6 +229,14 @@ async function execCompleteAdoption(args, deps) {
|
|
|
217
229
|
if (handoffMessage && deps.animationWriter) {
|
|
218
230
|
deps.animationWriter(`\n${handoffMessage}\n`);
|
|
219
231
|
}
|
|
232
|
+
if (generatedVaultUnlockSecret && deps.animationWriter) {
|
|
233
|
+
deps.animationWriter([
|
|
234
|
+
"",
|
|
235
|
+
`Vault unlock secret for ${name}: ${generatedVaultUnlockSecret}`,
|
|
236
|
+
`Use this with \`ouro vault unlock --agent ${name}\` on another machine.`,
|
|
237
|
+
"",
|
|
238
|
+
].join("\n"));
|
|
239
|
+
}
|
|
220
240
|
(0, runtime_1.emitNervesEvent)({
|
|
221
241
|
component: "daemon",
|
|
222
242
|
event: "daemon.adoption_complete",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// v1 → v2 agent.json migration.
|
|
3
|
-
//
|
|
4
|
-
// Uses raw fs — NO import from config.ts
|
|
3
|
+
// Creates explicit humanFacing/agentFacing blocks from the legacy provider.
|
|
4
|
+
// Uses raw fs and provider-model defaults — NO import from config.ts.
|
|
5
5
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
6
|
if (k2 === undefined) k2 = k;
|
|
7
7
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -40,19 +40,15 @@ exports.migrateAgentConfigV1ToV2 = migrateAgentConfigV1ToV2;
|
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const runtime_1 = require("../nerves/runtime");
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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");
|
|
43
|
+
const provider_models_1 = require("./provider-models");
|
|
44
|
+
function isAgentProvider(value) {
|
|
45
|
+
return value === "azure" ||
|
|
46
|
+
value === "minimax" ||
|
|
47
|
+
value === "anthropic" ||
|
|
48
|
+
value === "openai-codex" ||
|
|
49
|
+
value === "github-copilot";
|
|
54
50
|
}
|
|
55
|
-
function migrateAgentConfigV1ToV2(agentRoot
|
|
51
|
+
function migrateAgentConfigV1ToV2(agentRoot) {
|
|
56
52
|
const configPath = path.join(agentRoot, "agent.json");
|
|
57
53
|
let raw;
|
|
58
54
|
try {
|
|
@@ -84,44 +80,21 @@ function migrateAgentConfigV1ToV2(agentRoot, deps) {
|
|
|
84
80
|
message: "migrating agent config v1 → v2",
|
|
85
81
|
meta: { agentRoot },
|
|
86
82
|
});
|
|
87
|
-
const provider = config.provider;
|
|
88
|
-
|
|
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
|
-
}
|
|
83
|
+
const provider = isAgentProvider(config.provider) ? config.provider : "anthropic";
|
|
84
|
+
const model = (0, provider_models_1.getDefaultModelForProvider)(provider);
|
|
112
85
|
// Write v2 config
|
|
113
86
|
const { provider: _removed, ...rest } = config;
|
|
114
87
|
const v2Config = {
|
|
115
88
|
...rest,
|
|
116
89
|
version: 2,
|
|
117
|
-
humanFacing: { provider
|
|
118
|
-
agentFacing: { provider
|
|
90
|
+
humanFacing: { provider, model },
|
|
91
|
+
agentFacing: { provider, model },
|
|
119
92
|
};
|
|
120
93
|
fs.writeFileSync(configPath, JSON.stringify(v2Config, null, 2) + "\n", "utf-8");
|
|
121
94
|
(0, runtime_1.emitNervesEvent)({
|
|
122
95
|
component: "config/identity",
|
|
123
96
|
event: "config_identity.migrate_end",
|
|
124
97
|
message: "agent config migration complete",
|
|
125
|
-
meta: { agentRoot, provider
|
|
98
|
+
meta: { agentRoot, provider, model },
|
|
126
99
|
});
|
|
127
100
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizeProviderLane = normalizeProviderLane;
|
|
4
4
|
exports.resolveEffectiveProviderBinding = resolveEffectiveProviderBinding;
|
|
5
5
|
const runtime_1 = require("../nerves/runtime");
|
|
6
|
-
const
|
|
6
|
+
const provider_credentials_1 = require("./provider-credentials");
|
|
7
7
|
const provider_state_1 = require("./provider-state");
|
|
8
8
|
function legacyLaneWarning(selector, lane) {
|
|
9
9
|
return {
|
|
@@ -36,7 +36,7 @@ function buildUseRepair(agentName, lane, force = false) {
|
|
|
36
36
|
function buildAuthRepair(agentName, provider) {
|
|
37
37
|
return {
|
|
38
38
|
command: `ouro auth --agent ${agentName} --provider ${provider}`,
|
|
39
|
-
message: `
|
|
39
|
+
message: `Store ${provider} credentials in ${agentName}'s vault.`,
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
function missingProviderStateWarning(agentName) {
|
|
@@ -54,13 +54,13 @@ function invalidProviderStateWarning(agentName) {
|
|
|
54
54
|
function missingCredentialWarning(provider) {
|
|
55
55
|
return {
|
|
56
56
|
code: "credential-missing",
|
|
57
|
-
message: `${provider} has no credential record in the
|
|
57
|
+
message: `${provider} has no credential record in the agent vault.`,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
function invalidCredentialPoolWarning(provider) {
|
|
61
61
|
return {
|
|
62
62
|
code: "credential-pool-invalid",
|
|
63
|
-
message: `${provider} cannot read credentials
|
|
63
|
+
message: `${provider} cannot read credentials from the agent vault.`,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
function presentCredential(record) {
|
|
@@ -69,7 +69,6 @@ function presentCredential(record) {
|
|
|
69
69
|
provider: record.provider,
|
|
70
70
|
revision: record.revision,
|
|
71
71
|
source: record.provenance.source,
|
|
72
|
-
contributedByAgent: record.provenance.contributedByAgent,
|
|
73
72
|
updatedAt: record.updatedAt,
|
|
74
73
|
credentialFields: Object.keys(record.credentials).sort(),
|
|
75
74
|
configFields: Object.keys(record.config).sort(),
|
|
@@ -90,7 +89,7 @@ function resolveCredential(poolResult, provider, agentName) {
|
|
|
90
89
|
warnings: [missingCredentialWarning(provider)],
|
|
91
90
|
};
|
|
92
91
|
}
|
|
93
|
-
if (poolResult.reason === "invalid") {
|
|
92
|
+
if (poolResult.reason === "invalid" || poolResult.reason === "unavailable") {
|
|
94
93
|
return {
|
|
95
94
|
credential: {
|
|
96
95
|
status: "invalid-pool",
|
|
@@ -198,7 +197,7 @@ function resolveEffectiveProviderBinding(input) {
|
|
|
198
197
|
return result;
|
|
199
198
|
}
|
|
200
199
|
const laneBinding = stateResult.state.lanes[laneResolution.lane];
|
|
201
|
-
const poolResult = (0,
|
|
200
|
+
const poolResult = (0, provider_credentials_1.readProviderCredentialPool)(input.agentName);
|
|
202
201
|
const credentialResult = resolveCredential(poolResult, laneBinding.provider, input.agentName);
|
|
203
202
|
const readinessResult = resolveReadiness({
|
|
204
203
|
provider: laneBinding.provider,
|