panoma 0.1.8 → 0.1.9
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/app/BUILD-INFO.json +2 -2
- package/app/apps/web/.next-bundle/BUILD_ID +1 -1
- package/app/apps/web/.next-bundle/app-build-manifest.json +123 -123
- package/app/apps/web/.next-bundle/app-path-routes-manifest.json +30 -30
- package/app/apps/web/.next-bundle/build-manifest.json +2 -2
- package/app/apps/web/.next-bundle/prerender-manifest.json +3 -3
- package/app/apps/web/.next-bundle/server/app/(app)/agents/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/ai/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/bridge/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/copies/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/credentials/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/disk/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/hidden/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/p/[slug]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/packages/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/runs/[id]/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/runs/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/search/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/twin/look/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/twin/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/(app)/unsaved/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/accounts/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/consult/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/context/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/hello/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/journal/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/keys/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/log/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/mcp/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/notes/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/tasks/[id]/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/agent/tasks/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/ai/route.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/ai/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/assets/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/assignments/launch/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/assignments/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/catalog/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/check/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/consultations/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/describe/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/disk/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/enrich/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/environment/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/ingest/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/md/apply/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/md/context/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/md/inspect/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/md/repair/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/md/review/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/north/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/notes/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/open/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/project/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/rescan/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/roots/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/runs/[id]/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/runs/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/scale/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/secrets/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/tasks/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/today/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/assign/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/classify/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/critique/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/design/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/distill/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/look/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/mine/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/score/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/shot/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/sources/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/synthesize/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/taste/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/twin/verdicts/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/api/watch/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app/icon/[id]/route_client-reference-manifest.js +1 -1
- package/app/apps/web/.next-bundle/server/app-paths-manifest.json +30 -30
- package/app/apps/web/.next-bundle/server/chunks/2930.js +1 -1
- package/app/apps/web/.next-bundle/server/chunks/3610.js +6 -6
- package/app/apps/web/.next-bundle/server/chunks/3677.js +1 -1
- package/app/apps/web/.next-bundle/server/chunks/7876.js +1 -1
- package/app/apps/web/.next-bundle/server/functions-config-manifest.json +9 -9
- package/app/apps/web/.next-bundle/server/middleware-manifest.json +5 -5
- package/app/apps/web/.next-bundle/server/pages/500.html +1 -1
- package/app/apps/web/.next-bundle/server/server-reference-manifest.json +1 -1
- package/app/apps/web/.next-bundle/static/chunks/7911-1f2ce7063b83e142.js +1 -0
- package/app/node_modules/@panoma/ai/dist/index.d.ts +100 -1
- package/app/node_modules/@panoma/ai/dist/index.js +118 -52
- package/dist/{ai-command-2LSCDGUE.js → ai-command-W6FV3QW5.js} +2 -2
- package/dist/{chunk-RC6OXHI6.js → chunk-ROPR3LUO.js} +116 -52
- package/dist/{dist-ON3THUVO.js → dist-XTIHMRQM.js} +5 -1
- package/dist/index.js +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/app/apps/web/.next-bundle/static/chunks/7911-1730eba8c196e698.js +0 -1
- /package/app/apps/web/.next-bundle/static/{IoWYBo4jj6B8WTfswm-wr → GWFC4d9IgsD38wa3aUlsQ}/_buildManifest.js +0 -0
- /package/app/apps/web/.next-bundle/static/{IoWYBo4jj6B8WTfswm-wr → GWFC4d9IgsD38wa3aUlsQ}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What went wrong, said once and readable by both audiences.
|
|
3
|
+
*
|
|
4
|
+
* This package threw sentences in fixed Spanish, and both of its readers were wrong ones. The
|
|
5
|
+
* terminal prints `error.message` raw and is a machine surface, where the house rule is English.
|
|
6
|
+
* The browser is bilingual and got Spanish whichever language it was showing. `model-errors.ts`
|
|
7
|
+
* had already patched the two worst cases, and its own comment admits how: one by a typed error,
|
|
8
|
+
* the other by matching a Spanish substring — a sentence used as a key, which stops working the
|
|
9
|
+
* day somebody rewords it and says nothing.
|
|
10
|
+
*
|
|
11
|
+
* So the failure travels as data. `message` is English, because that is what a machine reads and
|
|
12
|
+
* what the CLI prints; `failure` carries the code and its parts, so the web can say the same thing
|
|
13
|
+
* in the language in front of it without parsing prose.
|
|
14
|
+
*
|
|
15
|
+
* What is NOT here: anything a provider said. A 429, a refusal, the text of somebody else's API —
|
|
16
|
+
* those are quotes, and translating a quote is inventing one. They travel inside `detail`, whole.
|
|
17
|
+
*/
|
|
18
|
+
type AiFailure = {
|
|
19
|
+
code: "noCommand";
|
|
20
|
+
provider: string;
|
|
21
|
+
} | {
|
|
22
|
+
code: "launchFailed";
|
|
23
|
+
command: string;
|
|
24
|
+
reason: string;
|
|
25
|
+
} | {
|
|
26
|
+
code: "exited";
|
|
27
|
+
provider: string;
|
|
28
|
+
status: number;
|
|
29
|
+
output: string;
|
|
30
|
+
} | {
|
|
31
|
+
code: "emptyBody";
|
|
32
|
+
provider: string;
|
|
33
|
+
} | {
|
|
34
|
+
code: "providerRefused";
|
|
35
|
+
provider: string;
|
|
36
|
+
status: number;
|
|
37
|
+
detail: string;
|
|
38
|
+
} | {
|
|
39
|
+
code: "tokenRefused";
|
|
40
|
+
provider: string;
|
|
41
|
+
status: number;
|
|
42
|
+
detail: string;
|
|
43
|
+
} | {
|
|
44
|
+
code: "neverAnswered";
|
|
45
|
+
provider: string;
|
|
46
|
+
last: string;
|
|
47
|
+
attempts: number;
|
|
48
|
+
} | {
|
|
49
|
+
code: "configShape";
|
|
50
|
+
} | {
|
|
51
|
+
code: "configLocked";
|
|
52
|
+
lock: string;
|
|
53
|
+
holder: string | undefined;
|
|
54
|
+
} | {
|
|
55
|
+
code: "noProvider";
|
|
56
|
+
} | {
|
|
57
|
+
code: "unknownProvider";
|
|
58
|
+
id: string;
|
|
59
|
+
} | {
|
|
60
|
+
code: "oauthTimeout";
|
|
61
|
+
} | {
|
|
62
|
+
code: "noOauth";
|
|
63
|
+
provider: string;
|
|
64
|
+
} | {
|
|
65
|
+
code: "badUrl";
|
|
66
|
+
provider: string;
|
|
67
|
+
value: string;
|
|
68
|
+
where: string;
|
|
69
|
+
} | {
|
|
70
|
+
code: "notHttp";
|
|
71
|
+
provider: string;
|
|
72
|
+
} | {
|
|
73
|
+
code: "urlHasCredentials";
|
|
74
|
+
provider: string;
|
|
75
|
+
} | {
|
|
76
|
+
code: "insecureHost";
|
|
77
|
+
provider: string;
|
|
78
|
+
host: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The English sentence for a failure, written in one place.
|
|
82
|
+
*
|
|
83
|
+
* One place because two would drift: the whole point of carrying the code is that the message and
|
|
84
|
+
* the translation cannot disagree about what happened.
|
|
85
|
+
*/
|
|
86
|
+
declare function failureMessage(failure: AiFailure): string;
|
|
87
|
+
/**
|
|
88
|
+
* An error this package raised about itself.
|
|
89
|
+
*
|
|
90
|
+
* `instanceof` rather than a string check, so that whoever translates it is reading a type and not
|
|
91
|
+
* guessing at prose. The two typed errors that already existed —`NoCredentialError` and
|
|
92
|
+
* `ConfigCorruptError`— keep their own classes: they carry more than a code and were already
|
|
93
|
+
* being read that way.
|
|
94
|
+
*/
|
|
95
|
+
declare class AiError extends Error {
|
|
96
|
+
readonly failure: AiFailure;
|
|
97
|
+
constructor(failure: AiFailure);
|
|
98
|
+
}
|
|
99
|
+
|
|
1
100
|
/**
|
|
2
101
|
* AI suppliers catalog.
|
|
3
102
|
*
|
|
@@ -487,4 +586,4 @@ interface CompleteResult {
|
|
|
487
586
|
}
|
|
488
587
|
declare function complete(request: CompleteRequest): Promise<CompleteResult>;
|
|
489
588
|
|
|
490
|
-
export { ATTEMPTS, type AgentAvailability, type AiConfig, type ApiFamily, type AuthType, type CallOptions, type Challenge, type CompleteImage, type CompleteRequest, type CompleteResult, ConfigCorruptError, NoCredentialError, type OauthConfig, type OauthToken, PROVIDERS, type Provider, REDACTED, type ResolvedCredential, VisionUnsupportedError, accountFrom, authorizeUrl, awaitCallback, callProvider, checkBaseUrl, complete, completeWithCliAgent, configPath, createChallenge, detectCliAgents, exchangeCode, expired, findProvider, forgetCredential, listModels, maskKey, pointsElsewhere, providersByAuth, readConfig, redact, redirectUri, refresh, resolveCredential, saveKey, saveToken, transportFailure, updateConfig, writeConfig };
|
|
589
|
+
export { ATTEMPTS, type AgentAvailability, type AiConfig, AiError, type AiFailure, type ApiFamily, type AuthType, type CallOptions, type Challenge, type CompleteImage, type CompleteRequest, type CompleteResult, ConfigCorruptError, NoCredentialError, type OauthConfig, type OauthToken, PROVIDERS, type Provider, REDACTED, type ResolvedCredential, VisionUnsupportedError, accountFrom, authorizeUrl, awaitCallback, callProvider, checkBaseUrl, complete, completeWithCliAgent, configPath, createChallenge, detectCliAgents, exchangeCode, expired, failureMessage, findProvider, forgetCredential, listModels, maskKey, pointsElsewhere, providersByAuth, readConfig, redact, redirectUri, refresh, resolveCredential, saveKey, saveToken, transportFailure, updateConfig, writeConfig };
|
|
@@ -1,3 +1,53 @@
|
|
|
1
|
+
// src/failures.ts
|
|
2
|
+
function failureMessage(failure) {
|
|
3
|
+
switch (failure.code) {
|
|
4
|
+
case "noCommand":
|
|
5
|
+
return `${failure.provider} declares no command to run.`;
|
|
6
|
+
case "launchFailed":
|
|
7
|
+
return `Could not launch ${failure.command}: ${failure.reason}`;
|
|
8
|
+
case "exited":
|
|
9
|
+
return `${failure.provider} exited with code ${failure.status}. ${failure.output}`.trim();
|
|
10
|
+
case "emptyBody":
|
|
11
|
+
return `${failure.provider} answered with no body.`;
|
|
12
|
+
case "providerRefused":
|
|
13
|
+
return `${failure.provider} answered ${failure.status}: ${failure.detail}`;
|
|
14
|
+
case "tokenRefused":
|
|
15
|
+
return `${failure.provider} refused the token request (${failure.status}): ${failure.detail}`;
|
|
16
|
+
case "neverAnswered":
|
|
17
|
+
return `${failure.provider} never answered: ${failure.last}. Attempts: ${failure.attempts}. The model did not say no \u2014 the request never left this machine.`;
|
|
18
|
+
case "configShape":
|
|
19
|
+
return "the contents are not shaped like a panoma configuration";
|
|
20
|
+
case "configLocked":
|
|
21
|
+
return `Another panoma process is writing the configuration${failure.holder ? ` (${failure.holder})` : ""}.
|
|
22
|
+
If none is running, the lock was left behind by an earlier run:
|
|
23
|
+
rm ${failure.lock}`;
|
|
24
|
+
case "noProvider":
|
|
25
|
+
return "No AI provider is configured. Run 'panoma ai' to see the options.";
|
|
26
|
+
case "unknownProvider":
|
|
27
|
+
return `Unknown provider: ${failure.id}`;
|
|
28
|
+
case "oauthTimeout":
|
|
29
|
+
return "Timed out waiting for you to come back from the browser.";
|
|
30
|
+
case "noOauth":
|
|
31
|
+
return `${failure.provider} does not use sign-in.`;
|
|
32
|
+
case "badUrl":
|
|
33
|
+
return `${failure.provider}'s address is not a valid URL: \xAB${failure.value}\xBB. Check ${failure.where}.`;
|
|
34
|
+
case "notHttp":
|
|
35
|
+
return `${failure.provider}'s address has to be http or https.`;
|
|
36
|
+
case "urlHasCredentials":
|
|
37
|
+
return `${failure.provider}'s address carries a user or a password inside. Take them out and use the key.`;
|
|
38
|
+
case "insecureHost":
|
|
39
|
+
return `panoma will not send ${failure.provider}'s credential unencrypted to ${failure.host}. Use https, or a server on your own machine.`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
var AiError = class extends Error {
|
|
43
|
+
failure;
|
|
44
|
+
constructor(failure) {
|
|
45
|
+
super(failureMessage(failure));
|
|
46
|
+
this.name = "AiError";
|
|
47
|
+
this.failure = failure;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
1
51
|
// src/providers.ts
|
|
2
52
|
import { homedir } from "os";
|
|
3
53
|
import { join } from "path";
|
|
@@ -443,7 +493,7 @@ function awaitCallback(provider, challenge) {
|
|
|
443
493
|
const close = () => server?.close();
|
|
444
494
|
const deadline = setTimeout(() => {
|
|
445
495
|
close();
|
|
446
|
-
reject(new
|
|
496
|
+
reject(new AiError({ code: "oauthTimeout" }));
|
|
447
497
|
}, DEADLINE_MS);
|
|
448
498
|
const finish = (error, code) => {
|
|
449
499
|
clearTimeout(deadline);
|
|
@@ -522,9 +572,13 @@ async function requestToken(provider, fields) {
|
|
|
522
572
|
});
|
|
523
573
|
const body = await response.json().catch(() => ({}));
|
|
524
574
|
if (!response.ok || !body.access_token) {
|
|
525
|
-
throw new
|
|
526
|
-
|
|
527
|
-
|
|
575
|
+
throw new AiError({
|
|
576
|
+
code: "tokenRefused",
|
|
577
|
+
provider: provider.name,
|
|
578
|
+
status: response.status,
|
|
579
|
+
/* The provider's own words, whole: translating somebody else's refusal invents one. */
|
|
580
|
+
detail: body.error_description ?? body.error ?? response.statusText
|
|
581
|
+
});
|
|
528
582
|
}
|
|
529
583
|
return {
|
|
530
584
|
access: body.access_token,
|
|
@@ -551,7 +605,7 @@ function expired(token) {
|
|
|
551
605
|
return token.expiresAt !== void 0 && Date.now() > token.expiresAt - MARGIN_MS;
|
|
552
606
|
}
|
|
553
607
|
function requireOauth(provider) {
|
|
554
|
-
if (!provider.oauth) throw new
|
|
608
|
+
if (!provider.oauth) throw new AiError({ code: "noOauth", provider: provider.name });
|
|
555
609
|
return provider.oauth;
|
|
556
610
|
}
|
|
557
611
|
|
|
@@ -561,22 +615,25 @@ function checkBaseUrl(provider, value) {
|
|
|
561
615
|
try {
|
|
562
616
|
url = new URL(value);
|
|
563
617
|
} catch {
|
|
564
|
-
throw new
|
|
565
|
-
|
|
566
|
-
|
|
618
|
+
throw new AiError({
|
|
619
|
+
code: "badUrl",
|
|
620
|
+
provider: provider.name,
|
|
621
|
+
value,
|
|
622
|
+
where: provider.baseUrlEnvVar ?? "the configuration"
|
|
623
|
+
});
|
|
567
624
|
}
|
|
568
625
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
569
|
-
throw new
|
|
626
|
+
throw new AiError({ code: "notHttp", provider: provider.name });
|
|
570
627
|
}
|
|
571
628
|
if (url.username || url.password) {
|
|
572
|
-
throw new
|
|
573
|
-
`La direcci\xF3n de ${provider.name} lleva usuario o contrase\xF1a dentro. Qu\xEDtalos y usa la clave.`
|
|
574
|
-
);
|
|
629
|
+
throw new AiError({ code: "urlHasCredentials", provider: provider.name });
|
|
575
630
|
}
|
|
576
631
|
if (url.protocol === "http:" && !isLocal(url.hostname)) {
|
|
577
|
-
throw new
|
|
578
|
-
|
|
579
|
-
|
|
632
|
+
throw new AiError({
|
|
633
|
+
code: "insecureHost",
|
|
634
|
+
provider: provider.name,
|
|
635
|
+
host: url.hostname
|
|
636
|
+
});
|
|
580
637
|
}
|
|
581
638
|
return value;
|
|
582
639
|
}
|
|
@@ -624,17 +681,21 @@ function backupPath() {
|
|
|
624
681
|
}
|
|
625
682
|
var ConfigCorruptError = class extends Error {
|
|
626
683
|
constructor(path, problem, recovery) {
|
|
627
|
-
const lines = [`
|
|
684
|
+
const lines = [`Could not read the AI configuration at ${path}: ${problem.message}`];
|
|
628
685
|
if (recovery) {
|
|
629
686
|
lines.push(
|
|
630
|
-
|
|
687
|
+
/*
|
|
688
|
+
Both forms written whole rather than an `s` glued to the figure. The house rule: never
|
|
689
|
+
attach an inflected word to a digit, and this line only ever reads wrong at one.
|
|
690
|
+
*/
|
|
691
|
+
recovery.keys === 1 ? `There is an earlier copy at ${recovery.path} holding one key. Recover it with:` : `There is an earlier copy at ${recovery.path} holding ${recovery.keys} keys. Recover it with:`,
|
|
631
692
|
` mv ${recovery.path} ${path}`,
|
|
632
|
-
"
|
|
693
|
+
"Do not run 'panoma ai key' first: it would overwrite the file and whatever is left in it."
|
|
633
694
|
);
|
|
634
695
|
} else {
|
|
635
696
|
lines.push(
|
|
636
|
-
"
|
|
637
|
-
"
|
|
697
|
+
"There is no earlier copy. Open it and fix it by hand, or delete it to start over \u2014",
|
|
698
|
+
"you will lose whatever keys were saved inside."
|
|
638
699
|
);
|
|
639
700
|
}
|
|
640
701
|
super(lines.join("\n"), { cause: problem });
|
|
@@ -676,7 +737,7 @@ async function readFileConfig(path) {
|
|
|
676
737
|
}
|
|
677
738
|
const parsed = JSON.parse(raw);
|
|
678
739
|
if (!isConfig(parsed)) {
|
|
679
|
-
throw new
|
|
740
|
+
throw new AiError({ code: "configShape" });
|
|
680
741
|
}
|
|
681
742
|
return parsed;
|
|
682
743
|
}
|
|
@@ -764,12 +825,11 @@ async function withLock(action) {
|
|
|
764
825
|
if (error.code !== "EEXIST") throw error;
|
|
765
826
|
if (Date.now() > deadline) {
|
|
766
827
|
const owner = await readFile(lock, "utf8").catch(() => "");
|
|
767
|
-
throw new
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
);
|
|
828
|
+
throw new AiError({
|
|
829
|
+
code: "configLocked",
|
|
830
|
+
lock,
|
|
831
|
+
holder: owner.trim() ? `pid ${owner.trim()}` : void 0
|
|
832
|
+
});
|
|
773
833
|
}
|
|
774
834
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
775
835
|
}
|
|
@@ -783,8 +843,8 @@ Si no hay ninguno corriendo, el cerrojo se qued\xF3 de una ejecuci\xF3n anterior
|
|
|
783
843
|
}
|
|
784
844
|
var NoCredentialError = class extends Error {
|
|
785
845
|
constructor(provider) {
|
|
786
|
-
const how = provider.auth === "cli" ? `
|
|
787
|
-
super(`
|
|
846
|
+
const how = provider.auth === "cli" ? `Install ${provider.name} and sign in; panoma will call '${provider.command}'.` : provider.auth === "oauth" ? `Sign in to ${provider.name} from the model page in panoma.` : `Run 'panoma ai key ${provider.id}' or export ${provider.apiKeyEnvVars?.[0]}. The key comes from ${provider.signupUrl}.`;
|
|
847
|
+
super(`No credential for ${provider.name}. ${how}`);
|
|
788
848
|
this.provider = provider;
|
|
789
849
|
this.name = "NoCredentialError";
|
|
790
850
|
}
|
|
@@ -794,12 +854,10 @@ async function resolveCredential(providerId, config) {
|
|
|
794
854
|
const settings = config ?? await readConfig();
|
|
795
855
|
const id = providerId ?? settings.provider;
|
|
796
856
|
if (!id) {
|
|
797
|
-
throw new
|
|
798
|
-
"No hay proveedor de IA configurado. Ejecuta 'panoma ai' para ver las opciones."
|
|
799
|
-
);
|
|
857
|
+
throw new AiError({ code: "noProvider" });
|
|
800
858
|
}
|
|
801
859
|
const provider = findProvider(id);
|
|
802
|
-
if (!provider) throw new
|
|
860
|
+
if (!provider) throw new AiError({ code: "unknownProvider", id });
|
|
803
861
|
if (provider.auth === "cli") {
|
|
804
862
|
return { provider, model: settings.model ?? "", source: "agent-session" };
|
|
805
863
|
}
|
|
@@ -926,7 +984,7 @@ async function detectCliAgents(providers) {
|
|
|
926
984
|
var MAX_OUTPUT = 2e5;
|
|
927
985
|
async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
928
986
|
const command = options.command ?? provider.command;
|
|
929
|
-
if (!command) throw new
|
|
987
|
+
if (!command) throw new AiError({ code: "noCommand", provider: provider.name });
|
|
930
988
|
return new Promise((resolve, reject) => {
|
|
931
989
|
const launch = resolveExecutable(command, provider.args ?? []);
|
|
932
990
|
const child = spawn(launch.file, launch.args, {
|
|
@@ -946,7 +1004,7 @@ async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
|
946
1004
|
const timer = setTimeout(() => child.kill("SIGKILL"), options.timeoutMs ?? 18e4);
|
|
947
1005
|
child.on("error", (error) => {
|
|
948
1006
|
clearTimeout(timer);
|
|
949
|
-
reject(new
|
|
1007
|
+
reject(new AiError({ code: "launchFailed", command, reason: error.message }));
|
|
950
1008
|
});
|
|
951
1009
|
child.on("close", (code) => {
|
|
952
1010
|
clearTimeout(timer);
|
|
@@ -954,7 +1012,12 @@ async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
|
954
1012
|
reject(
|
|
955
1013
|
new Error(
|
|
956
1014
|
redact(
|
|
957
|
-
|
|
1015
|
+
failureMessage({
|
|
1016
|
+
code: "exited",
|
|
1017
|
+
provider: provider.name,
|
|
1018
|
+
status: code ?? -1,
|
|
1019
|
+
output: stderr.trim().slice(0, 600)
|
|
1020
|
+
})
|
|
958
1021
|
)
|
|
959
1022
|
)
|
|
960
1023
|
);
|
|
@@ -1037,9 +1100,7 @@ async function callProvider(name, url, init, options = {}) {
|
|
|
1037
1100
|
if (attempt < attempts) await wait(WAITS[Math.min(attempt - 1, WAITS.length - 1)] ?? 0);
|
|
1038
1101
|
}
|
|
1039
1102
|
}
|
|
1040
|
-
throw new
|
|
1041
|
-
`${name} no lleg\xF3 a contestar: ${last}. Intentos: ${attempts}. No es que el modelo dijera que no: la petici\xF3n no sali\xF3 de esta m\xE1quina.`
|
|
1042
|
-
);
|
|
1103
|
+
throw new AiError({ code: "neverAnswered", provider: name, last: String(last), attempts });
|
|
1043
1104
|
}
|
|
1044
1105
|
function sleep(ms) {
|
|
1045
1106
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -1049,7 +1110,7 @@ function sleep(ms) {
|
|
|
1049
1110
|
var VisionUnsupportedError = class extends Error {
|
|
1050
1111
|
constructor(provider) {
|
|
1051
1112
|
super(
|
|
1052
|
-
`${provider}
|
|
1113
|
+
`${provider} cannot take images. Configure a provider with a key \u2014'panoma ai key'\u2014 or pass one with --provider.`
|
|
1053
1114
|
);
|
|
1054
1115
|
this.provider = provider;
|
|
1055
1116
|
this.name = "VisionUnsupportedError";
|
|
@@ -1066,7 +1127,7 @@ async function complete(request) {
|
|
|
1066
1127
|
|
|
1067
1128
|
${request.prompt}` : request.prompt;
|
|
1068
1129
|
const text = await completeWithCliAgent(credential.provider, prompt);
|
|
1069
|
-
return { text, provider: credential.provider.id, model: credential.model || "
|
|
1130
|
+
return { text, provider: credential.provider.id, model: credential.model || "session" };
|
|
1070
1131
|
}
|
|
1071
1132
|
if (credential.provider.api === "anthropic") return completeAnthropic(credential, request);
|
|
1072
1133
|
if (credential.provider.api === "codex") return completeCodex(credential, request);
|
|
@@ -1147,14 +1208,17 @@ async function completeCodex(credential, request) {
|
|
|
1147
1208
|
});
|
|
1148
1209
|
if (!response.ok) {
|
|
1149
1210
|
const failure = await response.json().catch(() => ({}));
|
|
1150
|
-
throw new
|
|
1151
|
-
|
|
1152
|
-
|
|
1211
|
+
throw new AiError({
|
|
1212
|
+
code: "providerRefused",
|
|
1213
|
+
provider: credential.provider.name,
|
|
1214
|
+
status: response.status,
|
|
1215
|
+
detail: redact(
|
|
1216
|
+
String(failure.error?.message ?? failure.detail ?? response.statusText),
|
|
1153
1217
|
[credential.apiKey]
|
|
1154
1218
|
)
|
|
1155
|
-
);
|
|
1219
|
+
});
|
|
1156
1220
|
}
|
|
1157
|
-
if (!response.body) throw new
|
|
1221
|
+
if (!response.body) throw new AiError({ code: "emptyBody", provider: credential.provider.name });
|
|
1158
1222
|
const { text, final } = await readCodexStream(response.body);
|
|
1159
1223
|
const outputText = (final?.output ?? []).flatMap((block) => block.content ?? []).flatMap((chunk) => chunk.text ? [chunk.text] : []).join("\n");
|
|
1160
1224
|
const shortcut = Array.isArray(final?.output_text) ? final.output_text.join("\n") : final?.output_text;
|
|
@@ -1243,12 +1307,12 @@ async function completeOpenAi(credential, request) {
|
|
|
1243
1307
|
);
|
|
1244
1308
|
const body = await response.json().catch(() => ({}));
|
|
1245
1309
|
if (!response.ok) {
|
|
1246
|
-
throw new
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
)
|
|
1251
|
-
);
|
|
1310
|
+
throw new AiError({
|
|
1311
|
+
code: "providerRefused",
|
|
1312
|
+
provider: credential.provider.name,
|
|
1313
|
+
status: response.status,
|
|
1314
|
+
detail: redact(String(body.error?.message ?? response.statusText), [credential.apiKey])
|
|
1315
|
+
});
|
|
1252
1316
|
}
|
|
1253
1317
|
return {
|
|
1254
1318
|
text: (body.choices?.[0]?.message?.content ?? "").trim(),
|
|
@@ -1262,6 +1326,7 @@ function dataUrl(image) {
|
|
|
1262
1326
|
}
|
|
1263
1327
|
export {
|
|
1264
1328
|
ATTEMPTS,
|
|
1329
|
+
AiError,
|
|
1265
1330
|
ConfigCorruptError,
|
|
1266
1331
|
NoCredentialError,
|
|
1267
1332
|
PROVIDERS,
|
|
@@ -1279,6 +1344,7 @@ export {
|
|
|
1279
1344
|
detectCliAgents,
|
|
1280
1345
|
exchangeCode,
|
|
1281
1346
|
expired,
|
|
1347
|
+
failureMessage,
|
|
1282
1348
|
findProvider,
|
|
1283
1349
|
forgetCredential,
|
|
1284
1350
|
listModels,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
readConfig,
|
|
11
11
|
resolveCredential,
|
|
12
12
|
updateConfig
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ROPR3LUO.js";
|
|
14
14
|
import {
|
|
15
15
|
say
|
|
16
16
|
} from "./chunk-FN63LYZH.js";
|
|
@@ -154,7 +154,7 @@ ${say("ai.keyEmpty")}
|
|
|
154
154
|
`));
|
|
155
155
|
return 1;
|
|
156
156
|
}
|
|
157
|
-
const { saveKey } = await import("./dist-
|
|
157
|
+
const { saveKey } = await import("./dist-XTIHMRQM.js");
|
|
158
158
|
await saveKey(provider.id, key);
|
|
159
159
|
process.stdout.write(
|
|
160
160
|
`
|