panoma 0.1.7 → 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 +125 -125
- package/app/apps/web/.next-bundle/app-path-routes-manifest.json +28 -28
- 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.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 +28 -28
- 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 +12 -12
- 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/apps/web/.next-bundle/static/chunks/app/(app)/bridge/{page-95d7d92ca0b30f20.js → page-9f270ffcd9da75ca.js} +1 -1
- package/app/node_modules/@panoma/ai/dist/index.d.ts +100 -1
- package/app/node_modules/@panoma/ai/dist/index.js +135 -57
- package/dist/{ai-command-ICITNELE.js → ai-command-W6FV3QW5.js} +2 -2
- package/dist/{chunk-N7EEJ4U6.js → chunk-ROPR3LUO.js} +133 -57
- package/dist/{dist-C7GE6UXH.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-c6622f219724e580.js +0 -1
- /package/app/apps/web/.next-bundle/static/{Ac5gZ0DbQ_SywHZXjduqm → GWFC4d9IgsD38wa3aUlsQ}/_buildManifest.js +0 -0
- /package/app/apps/web/.next-bundle/static/{Ac5gZ0DbQ_SywHZXjduqm → 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";
|
|
@@ -246,8 +296,8 @@ var PROVIDERS = [
|
|
|
246
296
|
id: "openai-codex",
|
|
247
297
|
name: "ChatGPT (Codex)",
|
|
248
298
|
auth: "oauth",
|
|
249
|
-
description: "Tu suscripci\xF3n de ChatGPT Plus o Pro, sin clave. Uso personal: se apoya en el inicio de sesi\xF3n del CLI de Codex y en un endpoint privado de OpenAI, as\xED que puede dejar de funcionar el d\xEDa que ellos lo cambien.",
|
|
250
|
-
descriptionEn: "Your ChatGPT Plus or Pro subscription, no key. Personal use: it leans on the Codex CLI sign-in and a private OpenAI endpoint, so it can stop working the day they change it.",
|
|
299
|
+
description: "Tu suscripci\xF3n de ChatGPT Plus o Pro, sin clave y sin binario local. Uso personal: se apoya en el inicio de sesi\xF3n del CLI de Codex y en un endpoint privado de OpenAI, as\xED que puede dejar de funcionar el d\xEDa que ellos lo cambien.",
|
|
300
|
+
descriptionEn: "Your ChatGPT Plus or Pro subscription, no key and no local binary. Personal use: it leans on the Codex CLI sign-in and a private OpenAI endpoint, so it can stop working the day they change it.",
|
|
251
301
|
api: "codex",
|
|
252
302
|
// The backup of ChatGPT, not `api.openai.com`: the subscription token is the only thing from
|
|
253
303
|
// OpenAI that is charged from the plan, and it is only valid against this gate.
|
|
@@ -298,11 +348,23 @@ var PROVIDERS = [
|
|
|
298
348
|
]
|
|
299
349
|
},
|
|
300
350
|
{
|
|
351
|
+
/*
|
|
352
|
+
«Codex CLI» and not «Codex», which is what it said.
|
|
353
|
+
|
|
354
|
+
Two entries away sits `openai-codex`, called «ChatGPT (Codex)», and a list showing both
|
|
355
|
+
offered the reader the same word twice with no way to tell them apart. They are not variants:
|
|
356
|
+
this one runs the `codex` binary on this machine as a subprocess, and that one talks to
|
|
357
|
+
OpenAI over your ChatGPT sign-in without any local binary at all. Whoever picked wrong was
|
|
358
|
+
not being careless — the screen gave them nothing to pick with.
|
|
359
|
+
|
|
360
|
+
The descriptions say the mechanism now, for the same reason: «uses your signed-in session,
|
|
361
|
+
no keys» was true of both.
|
|
362
|
+
*/
|
|
301
363
|
id: "codex-cli",
|
|
302
|
-
name: "Codex",
|
|
364
|
+
name: "Codex CLI",
|
|
303
365
|
auth: "cli",
|
|
304
|
-
description: "Usa
|
|
305
|
-
descriptionEn: "
|
|
366
|
+
description: "Ejecuta el binario `codex` de esta m\xE1quina. Usa su sesi\xF3n ya iniciada, sin claves.",
|
|
367
|
+
descriptionEn: "Runs the `codex` binary on this machine, using its signed-in session. No keys.",
|
|
306
368
|
command: "codex",
|
|
307
369
|
args: ["exec"],
|
|
308
370
|
bundles: ["/Applications/ChatGPT.app/Contents/Resources/codex"]
|
|
@@ -431,7 +493,7 @@ function awaitCallback(provider, challenge) {
|
|
|
431
493
|
const close = () => server?.close();
|
|
432
494
|
const deadline = setTimeout(() => {
|
|
433
495
|
close();
|
|
434
|
-
reject(new
|
|
496
|
+
reject(new AiError({ code: "oauthTimeout" }));
|
|
435
497
|
}, DEADLINE_MS);
|
|
436
498
|
const finish = (error, code) => {
|
|
437
499
|
clearTimeout(deadline);
|
|
@@ -510,9 +572,13 @@ async function requestToken(provider, fields) {
|
|
|
510
572
|
});
|
|
511
573
|
const body = await response.json().catch(() => ({}));
|
|
512
574
|
if (!response.ok || !body.access_token) {
|
|
513
|
-
throw new
|
|
514
|
-
|
|
515
|
-
|
|
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
|
+
});
|
|
516
582
|
}
|
|
517
583
|
return {
|
|
518
584
|
access: body.access_token,
|
|
@@ -539,7 +605,7 @@ function expired(token) {
|
|
|
539
605
|
return token.expiresAt !== void 0 && Date.now() > token.expiresAt - MARGIN_MS;
|
|
540
606
|
}
|
|
541
607
|
function requireOauth(provider) {
|
|
542
|
-
if (!provider.oauth) throw new
|
|
608
|
+
if (!provider.oauth) throw new AiError({ code: "noOauth", provider: provider.name });
|
|
543
609
|
return provider.oauth;
|
|
544
610
|
}
|
|
545
611
|
|
|
@@ -549,22 +615,25 @@ function checkBaseUrl(provider, value) {
|
|
|
549
615
|
try {
|
|
550
616
|
url = new URL(value);
|
|
551
617
|
} catch {
|
|
552
|
-
throw new
|
|
553
|
-
|
|
554
|
-
|
|
618
|
+
throw new AiError({
|
|
619
|
+
code: "badUrl",
|
|
620
|
+
provider: provider.name,
|
|
621
|
+
value,
|
|
622
|
+
where: provider.baseUrlEnvVar ?? "the configuration"
|
|
623
|
+
});
|
|
555
624
|
}
|
|
556
625
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
557
|
-
throw new
|
|
626
|
+
throw new AiError({ code: "notHttp", provider: provider.name });
|
|
558
627
|
}
|
|
559
628
|
if (url.username || url.password) {
|
|
560
|
-
throw new
|
|
561
|
-
`La direcci\xF3n de ${provider.name} lleva usuario o contrase\xF1a dentro. Qu\xEDtalos y usa la clave.`
|
|
562
|
-
);
|
|
629
|
+
throw new AiError({ code: "urlHasCredentials", provider: provider.name });
|
|
563
630
|
}
|
|
564
631
|
if (url.protocol === "http:" && !isLocal(url.hostname)) {
|
|
565
|
-
throw new
|
|
566
|
-
|
|
567
|
-
|
|
632
|
+
throw new AiError({
|
|
633
|
+
code: "insecureHost",
|
|
634
|
+
provider: provider.name,
|
|
635
|
+
host: url.hostname
|
|
636
|
+
});
|
|
568
637
|
}
|
|
569
638
|
return value;
|
|
570
639
|
}
|
|
@@ -612,17 +681,21 @@ function backupPath() {
|
|
|
612
681
|
}
|
|
613
682
|
var ConfigCorruptError = class extends Error {
|
|
614
683
|
constructor(path, problem, recovery) {
|
|
615
|
-
const lines = [`
|
|
684
|
+
const lines = [`Could not read the AI configuration at ${path}: ${problem.message}`];
|
|
616
685
|
if (recovery) {
|
|
617
686
|
lines.push(
|
|
618
|
-
|
|
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:`,
|
|
619
692
|
` mv ${recovery.path} ${path}`,
|
|
620
|
-
"
|
|
693
|
+
"Do not run 'panoma ai key' first: it would overwrite the file and whatever is left in it."
|
|
621
694
|
);
|
|
622
695
|
} else {
|
|
623
696
|
lines.push(
|
|
624
|
-
"
|
|
625
|
-
"
|
|
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."
|
|
626
699
|
);
|
|
627
700
|
}
|
|
628
701
|
super(lines.join("\n"), { cause: problem });
|
|
@@ -664,7 +737,7 @@ async function readFileConfig(path) {
|
|
|
664
737
|
}
|
|
665
738
|
const parsed = JSON.parse(raw);
|
|
666
739
|
if (!isConfig(parsed)) {
|
|
667
|
-
throw new
|
|
740
|
+
throw new AiError({ code: "configShape" });
|
|
668
741
|
}
|
|
669
742
|
return parsed;
|
|
670
743
|
}
|
|
@@ -752,12 +825,11 @@ async function withLock(action) {
|
|
|
752
825
|
if (error.code !== "EEXIST") throw error;
|
|
753
826
|
if (Date.now() > deadline) {
|
|
754
827
|
const owner = await readFile(lock, "utf8").catch(() => "");
|
|
755
|
-
throw new
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
);
|
|
828
|
+
throw new AiError({
|
|
829
|
+
code: "configLocked",
|
|
830
|
+
lock,
|
|
831
|
+
holder: owner.trim() ? `pid ${owner.trim()}` : void 0
|
|
832
|
+
});
|
|
761
833
|
}
|
|
762
834
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
763
835
|
}
|
|
@@ -771,8 +843,8 @@ Si no hay ninguno corriendo, el cerrojo se qued\xF3 de una ejecuci\xF3n anterior
|
|
|
771
843
|
}
|
|
772
844
|
var NoCredentialError = class extends Error {
|
|
773
845
|
constructor(provider) {
|
|
774
|
-
const how = provider.auth === "cli" ? `
|
|
775
|
-
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}`);
|
|
776
848
|
this.provider = provider;
|
|
777
849
|
this.name = "NoCredentialError";
|
|
778
850
|
}
|
|
@@ -782,12 +854,10 @@ async function resolveCredential(providerId, config) {
|
|
|
782
854
|
const settings = config ?? await readConfig();
|
|
783
855
|
const id = providerId ?? settings.provider;
|
|
784
856
|
if (!id) {
|
|
785
|
-
throw new
|
|
786
|
-
"No hay proveedor de IA configurado. Ejecuta 'panoma ai' para ver las opciones."
|
|
787
|
-
);
|
|
857
|
+
throw new AiError({ code: "noProvider" });
|
|
788
858
|
}
|
|
789
859
|
const provider = findProvider(id);
|
|
790
|
-
if (!provider) throw new
|
|
860
|
+
if (!provider) throw new AiError({ code: "unknownProvider", id });
|
|
791
861
|
if (provider.auth === "cli") {
|
|
792
862
|
return { provider, model: settings.model ?? "", source: "agent-session" };
|
|
793
863
|
}
|
|
@@ -914,7 +984,7 @@ async function detectCliAgents(providers) {
|
|
|
914
984
|
var MAX_OUTPUT = 2e5;
|
|
915
985
|
async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
916
986
|
const command = options.command ?? provider.command;
|
|
917
|
-
if (!command) throw new
|
|
987
|
+
if (!command) throw new AiError({ code: "noCommand", provider: provider.name });
|
|
918
988
|
return new Promise((resolve, reject) => {
|
|
919
989
|
const launch = resolveExecutable(command, provider.args ?? []);
|
|
920
990
|
const child = spawn(launch.file, launch.args, {
|
|
@@ -934,7 +1004,7 @@ async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
|
934
1004
|
const timer = setTimeout(() => child.kill("SIGKILL"), options.timeoutMs ?? 18e4);
|
|
935
1005
|
child.on("error", (error) => {
|
|
936
1006
|
clearTimeout(timer);
|
|
937
|
-
reject(new
|
|
1007
|
+
reject(new AiError({ code: "launchFailed", command, reason: error.message }));
|
|
938
1008
|
});
|
|
939
1009
|
child.on("close", (code) => {
|
|
940
1010
|
clearTimeout(timer);
|
|
@@ -942,7 +1012,12 @@ async function completeWithCliAgent(provider, prompt, options = {}) {
|
|
|
942
1012
|
reject(
|
|
943
1013
|
new Error(
|
|
944
1014
|
redact(
|
|
945
|
-
|
|
1015
|
+
failureMessage({
|
|
1016
|
+
code: "exited",
|
|
1017
|
+
provider: provider.name,
|
|
1018
|
+
status: code ?? -1,
|
|
1019
|
+
output: stderr.trim().slice(0, 600)
|
|
1020
|
+
})
|
|
946
1021
|
)
|
|
947
1022
|
)
|
|
948
1023
|
);
|
|
@@ -1025,9 +1100,7 @@ async function callProvider(name, url, init, options = {}) {
|
|
|
1025
1100
|
if (attempt < attempts) await wait(WAITS[Math.min(attempt - 1, WAITS.length - 1)] ?? 0);
|
|
1026
1101
|
}
|
|
1027
1102
|
}
|
|
1028
|
-
throw new
|
|
1029
|
-
`${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.`
|
|
1030
|
-
);
|
|
1103
|
+
throw new AiError({ code: "neverAnswered", provider: name, last: String(last), attempts });
|
|
1031
1104
|
}
|
|
1032
1105
|
function sleep(ms) {
|
|
1033
1106
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -1037,7 +1110,7 @@ function sleep(ms) {
|
|
|
1037
1110
|
var VisionUnsupportedError = class extends Error {
|
|
1038
1111
|
constructor(provider) {
|
|
1039
1112
|
super(
|
|
1040
|
-
`${provider}
|
|
1113
|
+
`${provider} cannot take images. Configure a provider with a key \u2014'panoma ai key'\u2014 or pass one with --provider.`
|
|
1041
1114
|
);
|
|
1042
1115
|
this.provider = provider;
|
|
1043
1116
|
this.name = "VisionUnsupportedError";
|
|
@@ -1054,7 +1127,7 @@ async function complete(request) {
|
|
|
1054
1127
|
|
|
1055
1128
|
${request.prompt}` : request.prompt;
|
|
1056
1129
|
const text = await completeWithCliAgent(credential.provider, prompt);
|
|
1057
|
-
return { text, provider: credential.provider.id, model: credential.model || "
|
|
1130
|
+
return { text, provider: credential.provider.id, model: credential.model || "session" };
|
|
1058
1131
|
}
|
|
1059
1132
|
if (credential.provider.api === "anthropic") return completeAnthropic(credential, request);
|
|
1060
1133
|
if (credential.provider.api === "codex") return completeCodex(credential, request);
|
|
@@ -1135,14 +1208,17 @@ async function completeCodex(credential, request) {
|
|
|
1135
1208
|
});
|
|
1136
1209
|
if (!response.ok) {
|
|
1137
1210
|
const failure = await response.json().catch(() => ({}));
|
|
1138
|
-
throw new
|
|
1139
|
-
|
|
1140
|
-
|
|
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),
|
|
1141
1217
|
[credential.apiKey]
|
|
1142
1218
|
)
|
|
1143
|
-
);
|
|
1219
|
+
});
|
|
1144
1220
|
}
|
|
1145
|
-
if (!response.body) throw new
|
|
1221
|
+
if (!response.body) throw new AiError({ code: "emptyBody", provider: credential.provider.name });
|
|
1146
1222
|
const { text, final } = await readCodexStream(response.body);
|
|
1147
1223
|
const outputText = (final?.output ?? []).flatMap((block) => block.content ?? []).flatMap((chunk) => chunk.text ? [chunk.text] : []).join("\n");
|
|
1148
1224
|
const shortcut = Array.isArray(final?.output_text) ? final.output_text.join("\n") : final?.output_text;
|
|
@@ -1231,12 +1307,12 @@ async function completeOpenAi(credential, request) {
|
|
|
1231
1307
|
);
|
|
1232
1308
|
const body = await response.json().catch(() => ({}));
|
|
1233
1309
|
if (!response.ok) {
|
|
1234
|
-
throw new
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
)
|
|
1239
|
-
);
|
|
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
|
+
});
|
|
1240
1316
|
}
|
|
1241
1317
|
return {
|
|
1242
1318
|
text: (body.choices?.[0]?.message?.content ?? "").trim(),
|
|
@@ -1250,6 +1326,7 @@ function dataUrl(image) {
|
|
|
1250
1326
|
}
|
|
1251
1327
|
export {
|
|
1252
1328
|
ATTEMPTS,
|
|
1329
|
+
AiError,
|
|
1253
1330
|
ConfigCorruptError,
|
|
1254
1331
|
NoCredentialError,
|
|
1255
1332
|
PROVIDERS,
|
|
@@ -1267,6 +1344,7 @@ export {
|
|
|
1267
1344
|
detectCliAgents,
|
|
1268
1345
|
exchangeCode,
|
|
1269
1346
|
expired,
|
|
1347
|
+
failureMessage,
|
|
1270
1348
|
findProvider,
|
|
1271
1349
|
forgetCredential,
|
|
1272
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
|
`
|