@ouro.bot/cli 0.1.0-alpha.372 → 0.1.0-alpha.374
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/changelog.json
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.374",
|
|
6
|
+
"changes": [
|
|
7
|
+
"SerpentGuide bootstrap now stays in the credential picker when a selected discovered credential fails ping, letting the human choose another saved source or enter a new key without restarting `ouro hatch`.",
|
|
8
|
+
"The stale discovered-credential retry path is covered by a focused SerpentGuide bootstrap test that fails the first provider ping and succeeds after manual replacement credentials.",
|
|
9
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the SerpentGuide credential retry release."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"version": "0.1.0-alpha.373",
|
|
14
|
+
"changes": [
|
|
15
|
+
"SerpentGuide bootstrap now discovers provider credentials from unlockable installed agent vaults, so a new hatch can reuse sources such as `minimax from slugger's vault` without creating persistent SerpentGuide credentials.",
|
|
16
|
+
"SerpentGuide credential options now preserve provenance for installed-agent vault sources and env sources while keeping secret values out of terminal labels.",
|
|
17
|
+
"`@ouro.bot/cli` and the `ouro.bot` wrapper are version-synced for the SerpentGuide installed-agent credential discovery release."
|
|
18
|
+
]
|
|
19
|
+
},
|
|
4
20
|
{
|
|
5
21
|
"version": "0.1.0-alpha.372",
|
|
6
22
|
"changes": [
|
|
@@ -244,13 +244,23 @@ async function defaultRunSerpentGuide() {
|
|
|
244
244
|
let providerRaw;
|
|
245
245
|
let credentials = {};
|
|
246
246
|
let providerConfig = {};
|
|
247
|
+
let selectedCredentialPayload = {};
|
|
247
248
|
const tempDir = path.join(os.tmpdir(), `ouro-hatch-${crypto.randomUUID()}`);
|
|
248
249
|
try {
|
|
249
250
|
const discovered = [];
|
|
250
|
-
const
|
|
251
|
+
const existingBundles = (0, specialist_orchestrator_1.listExistingBundles)((0, identity_1.getAgentBundlesRoot)());
|
|
252
|
+
const existingBundleCount = existingBundles.length;
|
|
251
253
|
const hatchVerb = existingBundleCount > 0 ? "let's hatch a new agent." : "let's hatch your first agent.";
|
|
252
254
|
// Default models per provider (used when entering new credentials)
|
|
253
255
|
const defaultModels = provider_models_1.DEFAULT_PROVIDER_MODELS;
|
|
256
|
+
const { pingProvider } = await Promise.resolve().then(() => __importStar(require("../provider-ping")));
|
|
257
|
+
const installedAgentCreds = await (0, provider_discovery_1.discoverInstalledAgentCredentials)(existingBundles);
|
|
258
|
+
for (const cred of installedAgentCreds) {
|
|
259
|
+
discovered.push({
|
|
260
|
+
...cred,
|
|
261
|
+
providerConfig: { model: defaultModels[cred.provider], ...cred.providerConfig },
|
|
262
|
+
});
|
|
263
|
+
}
|
|
254
264
|
// Scan environment variables for API keys using the shared helper
|
|
255
265
|
const envCreds = (0, provider_discovery_1.scanEnvVarCredentials)(process.env);
|
|
256
266
|
const envDiscovered = [];
|
|
@@ -265,26 +275,48 @@ async function defaultRunSerpentGuide() {
|
|
|
265
275
|
envDiscovered.push({ ...enriched, envVar: firstEnvVar });
|
|
266
276
|
discovered.push(enriched);
|
|
267
277
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const model = unique[i].providerConfig.model || unique[i].providerConfig.deployment || "";
|
|
274
|
-
const modelLabel = model ? `, ${model}` : "";
|
|
275
|
-
const envMatch = envDiscovered.find((e) => e.provider === unique[i].provider && unique[i].agentName === "env");
|
|
276
|
-
const sourceLabel = envMatch ? `from env: $${envMatch.envVar}` : `from ${unique[i].agentName}`;
|
|
277
|
-
process.stdout.write(` ${i + 1}. ${unique[i].provider}${modelLabel} (${sourceLabel})\n`);
|
|
278
|
+
let welcomed = false;
|
|
279
|
+
while (true) {
|
|
280
|
+
if (!welcomed) {
|
|
281
|
+
process.stdout.write(`\n\ud83d\udc0d welcome to ouroboros! ${hatchVerb}\n`);
|
|
282
|
+
welcomed = true;
|
|
278
283
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
if (discovered.length > 0) {
|
|
285
|
+
process.stdout.write("i found existing API credentials:\n\n");
|
|
286
|
+
const credentialOptions = discovered;
|
|
287
|
+
for (let i = 0; i < credentialOptions.length; i++) {
|
|
288
|
+
const model = credentialOptions[i].providerConfig.model || credentialOptions[i].providerConfig.deployment || "";
|
|
289
|
+
const modelLabel = model ? `, ${model}` : "";
|
|
290
|
+
const envMatch = envDiscovered.find((e) => e.provider === credentialOptions[i].provider && credentialOptions[i].agentName === "env");
|
|
291
|
+
const sourceLabel = (0, provider_discovery_1.describeDiscoveredCredentialSource)(credentialOptions[i], envMatch?.envVar);
|
|
292
|
+
process.stdout.write(` ${i + 1}. ${credentialOptions[i].provider}${modelLabel} (${sourceLabel})\n`);
|
|
293
|
+
}
|
|
294
|
+
process.stdout.write("\n");
|
|
295
|
+
const choice = await coldPrompt("use one of these? enter number, or 'new' for a different key, or 'q' to cancel: ");
|
|
296
|
+
if (["q", "quit", "cancel"].includes(choice.toLowerCase())) {
|
|
297
|
+
coldRl.close();
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
const idx = parseInt(choice, 10) - 1;
|
|
301
|
+
if (idx >= 0 && idx < credentialOptions.length) {
|
|
302
|
+
providerRaw = credentialOptions[idx].provider;
|
|
303
|
+
credentials = credentialOptions[idx].credentials;
|
|
304
|
+
providerConfig = credentialOptions[idx].providerConfig;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
const pRaw = await coldPrompt("provider (anthropic/azure/minimax/openai-codex/github-copilot): ");
|
|
308
|
+
if (!(0, cli_parse_1.isAgentProvider)(pRaw)) {
|
|
309
|
+
process.stdout.write("unknown provider. run `ouro hatch` to try again.\n");
|
|
310
|
+
coldRl.close();
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
providerRaw = pRaw;
|
|
314
|
+
providerConfig = { model: defaultModels[providerRaw] };
|
|
315
|
+
credentials = await (0, auth_flow_1.collectRuntimeAuthCredentials)({ agentName: "SerpentGuide", provider: providerRaw, promptInput: coldPrompt }, {});
|
|
316
|
+
}
|
|
286
317
|
}
|
|
287
318
|
else {
|
|
319
|
+
process.stdout.write("i need an API key to power our conversation.\n\n");
|
|
288
320
|
const pRaw = await coldPrompt("provider (anthropic/azure/minimax/openai-codex/github-copilot): ");
|
|
289
321
|
if (!(0, cli_parse_1.isAgentProvider)(pRaw)) {
|
|
290
322
|
process.stdout.write("unknown provider. run `ouro hatch` to try again.\n");
|
|
@@ -295,23 +327,21 @@ async function defaultRunSerpentGuide() {
|
|
|
295
327
|
providerConfig = { model: defaultModels[providerRaw] };
|
|
296
328
|
credentials = await (0, auth_flow_1.collectRuntimeAuthCredentials)({ agentName: "SerpentGuide", provider: providerRaw, promptInput: coldPrompt }, {});
|
|
297
329
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
330
|
+
selectedCredentialPayload = { ...providerConfig, ...credentials };
|
|
331
|
+
const pingResult = await pingProvider(providerRaw, selectedCredentialPayload);
|
|
332
|
+
if (pingResult.ok) {
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
process.stdout.write(`credentials didn't work (${pingResult.message}). `);
|
|
336
|
+
if (discovered.length > 0) {
|
|
337
|
+
process.stdout.write("choose another saved credential or enter 'new'.\n\n");
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
process.stdout.write("let's try again.\n\n");
|
|
307
341
|
}
|
|
308
|
-
providerRaw = pRaw;
|
|
309
|
-
providerConfig = { model: defaultModels[providerRaw] };
|
|
310
|
-
credentials = await (0, auth_flow_1.collectRuntimeAuthCredentials)({ agentName: "SerpentGuide", provider: providerRaw, promptInput: coldPrompt }, {});
|
|
311
342
|
}
|
|
312
343
|
coldRl.close();
|
|
313
344
|
process.stdout.write("\n");
|
|
314
|
-
const selectedCredentialPayload = { ...providerConfig, ...credentials };
|
|
315
345
|
const split = (0, provider_credentials_1.splitProviderCredentialFields)(providerRaw, selectedCredentialPayload);
|
|
316
346
|
(0, provider_credentials_1.cacheProviderCredentialRecords)("SerpentGuide", [
|
|
317
347
|
(0, provider_credentials_1.createProviderCredentialRecord)({
|
|
@@ -347,14 +377,6 @@ async function defaultRunSerpentGuide() {
|
|
|
347
377
|
agentFacing: { provider: providerRaw, model: resolvedModel },
|
|
348
378
|
phrases,
|
|
349
379
|
});
|
|
350
|
-
// Ping-verify credentials before entering the serpent guide session
|
|
351
|
-
const { pingProvider } = await Promise.resolve().then(() => __importStar(require("../provider-ping")));
|
|
352
|
-
const pingResult = await pingProvider(providerRaw, selectedCredentialPayload);
|
|
353
|
-
if (!pingResult.ok) {
|
|
354
|
-
process.stdout.write(`credentials didn't work (${pingResult.message}). run 'ouro hatch' to try again.\n`);
|
|
355
|
-
return null;
|
|
356
|
-
}
|
|
357
|
-
const existingBundles = (0, specialist_orchestrator_1.listExistingBundles)(bundlesRoot);
|
|
358
380
|
const systemPrompt = (0, specialist_prompt_1.buildSpecialistSystemPrompt)(soulText, identity.content, existingBundles, {
|
|
359
381
|
tempDir,
|
|
360
382
|
provider: providerRaw,
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.scanEnvVarCredentials = scanEnvVarCredentials;
|
|
11
|
+
exports.discoverInstalledAgentCredentials = discoverInstalledAgentCredentials;
|
|
12
|
+
exports.describeDiscoveredCredentialSource = describeDiscoveredCredentialSource;
|
|
11
13
|
exports.discoverWorkingProvider = discoverWorkingProvider;
|
|
12
14
|
const identity_1 = require("../identity");
|
|
13
15
|
const provider_credentials_1 = require("../provider-credentials");
|
|
@@ -45,14 +47,36 @@ function stringifyProviderFields(fields) {
|
|
|
45
47
|
}
|
|
46
48
|
return result;
|
|
47
49
|
}
|
|
48
|
-
function discoveredFromVaultRecord(record) {
|
|
50
|
+
function discoveredFromVaultRecord(record, agentName = "vault") {
|
|
49
51
|
return {
|
|
50
52
|
provider: record.provider,
|
|
51
|
-
agentName
|
|
53
|
+
agentName,
|
|
52
54
|
credentials: stringifyProviderFields(record.credentials),
|
|
53
55
|
providerConfig: stringifyProviderFields(record.config),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
58
|
+
async function discoverInstalledAgentCredentials(agentNames) {
|
|
59
|
+
const discovered = [];
|
|
60
|
+
for (const agentName of agentNames) {
|
|
61
|
+
if (agentName === "SerpentGuide")
|
|
62
|
+
continue;
|
|
63
|
+
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(agentName, { preserveCachedOnFailure: true });
|
|
64
|
+
if (!poolResult.ok)
|
|
65
|
+
continue;
|
|
66
|
+
for (const record of Object.values(poolResult.pool.providers)) {
|
|
67
|
+
if (!record)
|
|
68
|
+
continue;
|
|
69
|
+
discovered.push(discoveredFromVaultRecord(record, agentName));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return discovered;
|
|
73
|
+
}
|
|
74
|
+
function describeDiscoveredCredentialSource(credential, envVar) {
|
|
75
|
+
if (credential.agentName === "env") {
|
|
76
|
+
return envVar ? `from env: $${envVar}` : "from env";
|
|
77
|
+
}
|
|
78
|
+
return `from ${credential.agentName}'s vault`;
|
|
79
|
+
}
|
|
56
80
|
async function discoverWorkingProvider(deps) {
|
|
57
81
|
const poolResult = await (0, provider_credentials_1.refreshProviderCredentialPool)(deps.agentName);
|
|
58
82
|
if (!poolResult.ok) {
|