@amaster.ai/pi-image-gen 0.1.2-beta.15

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.
Files changed (52) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +310 -0
  3. package/dist/config.d.ts +24 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +183 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/errors.d.ts +16 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +70 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/generate.d.ts +12 -0
  12. package/dist/generate.d.ts.map +1 -0
  13. package/dist/generate.js +86 -0
  14. package/dist/generate.js.map +1 -0
  15. package/dist/image-input.d.ts +25 -0
  16. package/dist/image-input.d.ts.map +1 -0
  17. package/dist/image-input.js +153 -0
  18. package/dist/image-input.js.map +1 -0
  19. package/dist/index.d.ts +18 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +147 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/models.d.ts +18 -0
  24. package/dist/models.d.ts.map +1 -0
  25. package/dist/models.js +86 -0
  26. package/dist/models.js.map +1 -0
  27. package/dist/providers/dashscope.d.ts +12 -0
  28. package/dist/providers/dashscope.d.ts.map +1 -0
  29. package/dist/providers/dashscope.js +89 -0
  30. package/dist/providers/dashscope.js.map +1 -0
  31. package/dist/providers/gemini.d.ts +10 -0
  32. package/dist/providers/gemini.d.ts.map +1 -0
  33. package/dist/providers/gemini.js +99 -0
  34. package/dist/providers/gemini.js.map +1 -0
  35. package/dist/providers/index.d.ts +3 -0
  36. package/dist/providers/index.d.ts.map +1 -0
  37. package/dist/providers/index.js +19 -0
  38. package/dist/providers/index.js.map +1 -0
  39. package/dist/providers/openai.d.ts +14 -0
  40. package/dist/providers/openai.d.ts.map +1 -0
  41. package/dist/providers/openai.js +145 -0
  42. package/dist/providers/openai.js.map +1 -0
  43. package/dist/types.d.ts +133 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +2 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/url.d.ts +11 -0
  48. package/dist/url.d.ts.map +1 -0
  49. package/dist/url.js +25 -0
  50. package/dist/url.js.map +1 -0
  51. package/package.json +73 -0
  52. package/preview.png +0 -0
package/dist/config.js ADDED
@@ -0,0 +1,183 @@
1
+ import { loadPiSettings, resolveAgentDir } from '@amaster.ai/pi-shared/settings';
2
+ import { BUILT_IN_MODELS, DEFAULT_API_STYLE, DEFAULT_BASE_URL, ENV_VARS, PROVIDER_DISPLAY_NAME, } from './models.js';
3
+ const SETTINGS_KEY = 'pi-image-gen';
4
+ export function loadImageGenSettings(cwd) {
5
+ try {
6
+ return loadPiSettings(SETTINGS_KEY, {
7
+ cwd,
8
+ agentDir: resolveAgentDir(),
9
+ });
10
+ }
11
+ catch {
12
+ return {};
13
+ }
14
+ }
15
+ /**
16
+ * Returns the resolved value for an apiKey/header field. Supports `$VAR`
17
+ * and `${VAR}` env substitution; returns undefined for missing env vars
18
+ * so downstream code can fall through to defaults.
19
+ *
20
+ * pi-shared/settings already runs `${VAR}` substitution on settings.json
21
+ * payloads, but we re-run resolution here so that settings constructed in
22
+ * code (or read from other sources) get the same treatment.
23
+ */
24
+ function resolveString(value) {
25
+ if (!value)
26
+ return undefined;
27
+ const replaced = value.replace(/\$\{([^}]+)\}|\$([A-Z_][A-Z0-9_]*)/g, (_match, braced, bare) => {
28
+ const name = (braced ?? bare);
29
+ if (!name)
30
+ return '';
31
+ const [varName, ...rest] = name.split(':-');
32
+ const fallback = rest.join(':-');
33
+ const env = process.env[varName];
34
+ return env !== undefined && env !== '' ? env : fallback;
35
+ });
36
+ return replaced.length > 0 ? replaced : undefined;
37
+ }
38
+ function buildBuiltInProvider(id, settings) {
39
+ const override = settings.providers?.[id] ?? {};
40
+ const apiKey = resolveString(override.apiKey) ?? process.env[ENV_VARS[id]];
41
+ const provider = {
42
+ id,
43
+ api: DEFAULT_API_STYLE[id],
44
+ baseUrl: resolveString(override.baseUrl) ?? DEFAULT_BASE_URL[id],
45
+ name: PROVIDER_DISPLAY_NAME[id],
46
+ builtIn: true,
47
+ };
48
+ if (apiKey)
49
+ provider.apiKey = apiKey;
50
+ if (override.headers)
51
+ provider.headers = override.headers;
52
+ return provider;
53
+ }
54
+ function buildCustomProvider(name, raw) {
55
+ const api = raw.api;
56
+ if (!api)
57
+ return null;
58
+ const baseUrl = resolveString(raw.baseUrl) ?? DEFAULT_BASE_URL[api];
59
+ if (!baseUrl)
60
+ return null;
61
+ const provider = {
62
+ id: name,
63
+ api,
64
+ baseUrl,
65
+ name: raw.name ?? name,
66
+ builtIn: false,
67
+ };
68
+ const apiKey = resolveString(raw.apiKey);
69
+ if (apiKey)
70
+ provider.apiKey = apiKey;
71
+ if (raw.headers)
72
+ provider.headers = raw.headers;
73
+ return provider;
74
+ }
75
+ function customModels(raw) {
76
+ const list = raw.models ?? [];
77
+ return list.flatMap((entry) => {
78
+ if (typeof entry === 'string')
79
+ return [{ id: entry, alias: entry }];
80
+ const m = entry;
81
+ if (!m.id)
82
+ return [];
83
+ return [{ id: m.id, alias: m.alias ?? m.id }];
84
+ });
85
+ }
86
+ /**
87
+ * Resolve a model id (or alias) to a (provider, remoteModelId) pair using:
88
+ * 1. Custom providers' explicit model lists (alias or id match).
89
+ * 2. Built-in known models (alias or id match).
90
+ * 3. `<provider>/<remote-id>` fallback for explicit routing.
91
+ * 4. Catch-all: any custom provider that didn't declare a `models` list
92
+ * will accept any unknown model id, passing it through as the remote id.
93
+ * This lets users configure a single OpenAI-compatible gateway and use
94
+ * any model name without restating it in `models`.
95
+ */
96
+ export function resolveModel(modelOrAlias, settings) {
97
+ const requested = modelOrAlias.trim();
98
+ if (!requested)
99
+ return { error: 'Model id is empty.' };
100
+ for (const [name, raw] of Object.entries(settings.customProviders ?? {})) {
101
+ const provider = buildCustomProvider(name, raw);
102
+ if (!provider)
103
+ continue;
104
+ for (const model of customModels(raw)) {
105
+ if (model.alias === requested || model.id === requested) {
106
+ return { provider, remoteId: model.id, requestedId: requested };
107
+ }
108
+ }
109
+ }
110
+ const builtIn = BUILT_IN_MODELS.find((entry) => entry.id === requested || entry.aliases?.includes(requested));
111
+ if (builtIn) {
112
+ const provider = buildBuiltInProvider(builtIn.provider, settings);
113
+ if (provider?.apiKey) {
114
+ return { provider, remoteId: builtIn.remoteId ?? builtIn.id, requestedId: requested };
115
+ }
116
+ // Built-in match without a configured API key — fall through so a
117
+ // catch-all customProvider can still pick this up.
118
+ }
119
+ const slash = requested.indexOf('/');
120
+ if (slash > 0) {
121
+ const providerKey = requested.slice(0, slash);
122
+ const remoteId = requested.slice(slash + 1);
123
+ if (isBuiltInProviderId(providerKey)) {
124
+ const provider = buildBuiltInProvider(providerKey, settings);
125
+ if (provider)
126
+ return { provider, remoteId, requestedId: requested };
127
+ }
128
+ const customRaw = settings.customProviders?.[providerKey];
129
+ if (customRaw) {
130
+ const provider = buildCustomProvider(providerKey, customRaw);
131
+ if (provider)
132
+ return { provider, remoteId, requestedId: requested };
133
+ }
134
+ }
135
+ for (const [name, raw] of Object.entries(settings.customProviders ?? {})) {
136
+ if (raw.models && raw.models.length > 0)
137
+ continue;
138
+ const provider = buildCustomProvider(name, raw);
139
+ if (provider)
140
+ return { provider, remoteId: requested, requestedId: requested };
141
+ }
142
+ return { error: unknownModelError(requested, settings) };
143
+ }
144
+ function unknownModelError(requested, settings) {
145
+ const customNames = Object.keys(settings.customProviders ?? {});
146
+ const lines = [`Unknown image model "${requested}".`];
147
+ if (customNames.length > 0) {
148
+ const explicit = customNames.filter((n) => {
149
+ const m = settings.customProviders?.[n]?.models;
150
+ return m && m.length > 0;
151
+ });
152
+ if (explicit.length > 0) {
153
+ lines.push(`Configured customProviders with explicit model lists: ${explicit.join(', ')}. The requested id didn't match any of their entries.`);
154
+ }
155
+ lines.push(`To accept any model id without listing it, omit the "models" field on a customProvider — that provider then becomes a catch-all.`);
156
+ }
157
+ const builtInIds = listKnownModelIds();
158
+ lines.push(`Built-in model ids: ${builtInIds.slice(0, 10).join(', ')}${builtInIds.length > 10 ? ', ...' : ''}.`);
159
+ return lines.join(' ');
160
+ }
161
+ export function listKnownModelIds() {
162
+ return BUILT_IN_MODELS.flatMap((m) => [m.id, ...(m.aliases ?? [])]);
163
+ }
164
+ export function listConfiguredProviders(settings) {
165
+ const out = [];
166
+ for (const id of ['openai', 'gemini', 'dashscope', 'openrouter']) {
167
+ const provider = buildBuiltInProvider(id, settings);
168
+ if (provider?.apiKey)
169
+ out.push({ ...provider, catchAll: false, modelCount: 0 });
170
+ }
171
+ for (const [name, raw] of Object.entries(settings.customProviders ?? {})) {
172
+ const provider = buildCustomProvider(name, raw);
173
+ if (provider) {
174
+ const modelCount = raw.models?.length ?? 0;
175
+ out.push({ ...provider, catchAll: modelCount === 0, modelCount });
176
+ }
177
+ }
178
+ return out;
179
+ }
180
+ function isBuiltInProviderId(value) {
181
+ return (value === 'openai' || value === 'gemini' || value === 'dashscope' || value === 'openrouter');
182
+ }
183
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ResolvedProvider } from './types.js';
2
+ /**
3
+ * Build an error message that an LLM can act on without a human in the loop.
4
+ *
5
+ * The shape is:
6
+ * "<short verb-phrase>. <hint addressed to the LLM>."
7
+ *
8
+ * The first sentence describes what happened so a human reading the transcript
9
+ * understands. The second sentence tells the LLM what to do — typically "tell
10
+ * the user to verify X" — so the model doesn't fall back to vague apologies or
11
+ * pointless retries.
12
+ */
13
+ export declare function classifyHttpError(res: Response, body: string, provider: ResolvedProvider): string;
14
+ /** Wrap a non-HTTP error (timeout, network, parse) with a hint for the LLM. */
15
+ export declare function describeNetworkError(error: unknown, provider: ResolvedProvider): string;
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAoBjG;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAYvF"}
package/dist/errors.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Build an error message that an LLM can act on without a human in the loop.
3
+ *
4
+ * The shape is:
5
+ * "<short verb-phrase>. <hint addressed to the LLM>."
6
+ *
7
+ * The first sentence describes what happened so a human reading the transcript
8
+ * understands. The second sentence tells the LLM what to do — typically "tell
9
+ * the user to verify X" — so the model doesn't fall back to vague apologies or
10
+ * pointless retries.
11
+ */
12
+ export function classifyHttpError(res, body, provider) {
13
+ const where = providerLocator(provider);
14
+ const peek = body.slice(0, 200).replace(/\s+/g, ' ');
15
+ if (res.status === 401 || res.status === 403) {
16
+ return `${provider.name} rejected the API key (HTTP ${res.status}). Tell the user to verify ${where}. Do not retry — this will keep failing until the key is fixed.`;
17
+ }
18
+ if (res.status === 404) {
19
+ return `${provider.name} returned 404 at this baseUrl. Tell the user to verify ${providerBaseUrlLocator(provider)} — the model id may be wrong, or this gateway doesn't expose the image API. Body: ${peek}`;
20
+ }
21
+ if (res.status === 429) {
22
+ return `${provider.name} rate-limited the request (HTTP 429). Wait a few seconds before retrying, or suggest a different provider/model. Body: ${peek}`;
23
+ }
24
+ if (res.status >= 500 && res.status < 600) {
25
+ return `${provider.name} had a server-side failure (HTTP ${res.status}). This is likely transient — one retry is reasonable, but if it keeps failing tell the user the provider is down. Body: ${peek}`;
26
+ }
27
+ if (res.status === 400 || res.status === 422) {
28
+ return `${provider.name} rejected the request (HTTP ${res.status}) — likely a bad parameter or unsupported model id. Tell the user the model name or size may not be supported by this provider. Body: ${peek}`;
29
+ }
30
+ return `${provider.name} returned HTTP ${res.status}. Body: ${peek}`;
31
+ }
32
+ /** Wrap a non-HTTP error (timeout, network, parse) with a hint for the LLM. */
33
+ export function describeNetworkError(error, provider) {
34
+ const msg = error instanceof Error ? error.message : String(error);
35
+ if (/abort/i.test(msg)) {
36
+ return `Request to ${provider.name} was cancelled.`;
37
+ }
38
+ if (/timeout|timed out|ETIMEDOUT/i.test(msg)) {
39
+ return `Request to ${provider.name} timed out. The provider was too slow — try a smaller \`n\`, a different model, or check ${providerBaseUrlLocator(provider)}. Original: ${msg}`;
40
+ }
41
+ if (/ENOTFOUND|EAI_AGAIN|ECONNREFUSED|ECONNRESET/i.test(msg)) {
42
+ return `Cannot reach ${provider.name}. Tell the user to check network connectivity or verify ${providerBaseUrlLocator(provider)}. Original: ${msg}`;
43
+ }
44
+ return `${provider.name} request failed: ${msg}`;
45
+ }
46
+ /**
47
+ * Returns a settings-path string that points to where the user should fix
48
+ * the apiKey. For built-ins we name the env var; for customProviders we name
49
+ * the JSON path.
50
+ */
51
+ function providerLocator(provider) {
52
+ if (provider.builtIn) {
53
+ const envVar = BUILT_IN_ENV_VAR[provider.id] ?? `${provider.id.toUpperCase()}_API_KEY`;
54
+ return `the ${envVar} env var (or pi-image-gen.providers.${provider.id}.apiKey in settings.json)`;
55
+ }
56
+ return `pi-image-gen.customProviders.${provider.id}.apiKey in settings.json`;
57
+ }
58
+ function providerBaseUrlLocator(provider) {
59
+ if (provider.builtIn) {
60
+ return `pi-image-gen.providers.${provider.id}.baseUrl`;
61
+ }
62
+ return `pi-image-gen.customProviders.${provider.id}.baseUrl`;
63
+ }
64
+ const BUILT_IN_ENV_VAR = {
65
+ openai: 'OPENAI_API_KEY',
66
+ gemini: 'GEMINI_API_KEY',
67
+ dashscope: 'DASHSCOPE_API_KEY',
68
+ openrouter: 'OPENROUTER_API_KEY',
69
+ };
70
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAa,EAAE,IAAY,EAAE,QAA0B;IACvF,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAErD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,OAAO,GAAG,QAAQ,CAAC,IAAI,+BAA+B,GAAG,CAAC,MAAM,8BAA8B,KAAK,iEAAiE,CAAC;IACvK,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,GAAG,QAAQ,CAAC,IAAI,0DAA0D,sBAAsB,CAAC,QAAQ,CAAC,qFAAqF,IAAI,EAAE,CAAC;IAC/M,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QACvB,OAAO,GAAG,QAAQ,CAAC,IAAI,0HAA0H,IAAI,EAAE,CAAC;IAC1J,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC1C,OAAO,GAAG,QAAQ,CAAC,IAAI,oCAAoC,GAAG,CAAC,MAAM,4HAA4H,IAAI,EAAE,CAAC;IAC1M,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7C,OAAO,GAAG,QAAQ,CAAC,IAAI,+BAA+B,GAAG,CAAC,MAAM,yIAAyI,IAAI,EAAE,CAAC;IAClN,CAAC;IACD,OAAO,GAAG,QAAQ,CAAC,IAAI,kBAAkB,GAAG,CAAC,MAAM,WAAW,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB,CAAC,KAAc,EAAE,QAA0B;IAC7E,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,cAAc,QAAQ,CAAC,IAAI,iBAAiB,CAAC;IACtD,CAAC;IACD,IAAI,8BAA8B,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,cAAc,QAAQ,CAAC,IAAI,4FAA4F,sBAAsB,CAAC,QAAQ,CAAC,eAAe,GAAG,EAAE,CAAC;IACrL,CAAC;IACD,IAAI,8CAA8C,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7D,OAAO,gBAAgB,QAAQ,CAAC,IAAI,2DAA2D,sBAAsB,CAAC,QAAQ,CAAC,eAAe,GAAG,EAAE,CAAC;IACtJ,CAAC;IACD,OAAO,GAAG,QAAQ,CAAC,IAAI,oBAAoB,GAAG,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,QAA0B;IACjD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,UAAU,CAAC;QACvF,OAAO,OAAO,MAAM,uCAAuC,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IACpG,CAAC;IACD,OAAO,gCAAgC,QAAQ,CAAC,EAAE,0BAA0B,CAAC;AAC/E,CAAC;AAED,SAAS,sBAAsB,CAAC,QAA0B;IACxD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,0BAA0B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACzD,CAAC;IACD,OAAO,gCAAgC,QAAQ,CAAC,EAAE,UAAU,CAAC;AAC/D,CAAC;AAED,MAAM,gBAAgB,GAA2B;IAC/C,MAAM,EAAE,gBAAgB;IACxB,MAAM,EAAE,gBAAgB;IACxB,SAAS,EAAE,mBAAmB;IAC9B,UAAU,EAAE,oBAAoB;CACjC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { GenerateImageParams, ImageGenResult, ImageGenSettings } from './types.js';
2
+ export type GenerateImageOptions = {
3
+ cwd: string;
4
+ settings: ImageGenSettings;
5
+ fetchImpl?: typeof fetch;
6
+ /** Cancellation signal — propagated to every fetch and the DashScope poll loop. */
7
+ signal?: AbortSignal;
8
+ /** Override the wall-clock used for filenames. Useful for tests. */
9
+ now?: () => Date;
10
+ };
11
+ export declare function generateImage(params: GenerateImageParams, options: GenerateImageOptions): Promise<ImageGenResult>;
12
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAEV,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,mFAAmF;IACnF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAUF,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAkDzB"}
@@ -0,0 +1,86 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { isAbsolute, resolve } from 'node:path';
3
+ import { resolveModel } from './config.js';
4
+ import { resolveImageInputs } from './image-input.js';
5
+ import { getAdapter } from './providers/index.js';
6
+ const MIME_TO_EXT = {
7
+ 'image/png': 'png',
8
+ 'image/jpeg': 'jpg',
9
+ 'image/jpg': 'jpg',
10
+ 'image/webp': 'webp',
11
+ 'image/gif': 'gif',
12
+ };
13
+ export async function generateImage(params, options) {
14
+ const fetchImpl = options.fetchImpl ?? fetch;
15
+ const now = options.now ?? (() => new Date());
16
+ const requested = (options.settings.defaultModel ?? '').trim();
17
+ if (!requested) {
18
+ throw new Error('pi-image-gen.defaultModel is not set. Configure it in settings.json (e.g. "defaultModel": "nano-banana"). Run /image-gen list to see configured providers.');
19
+ }
20
+ const resolved = resolveModel(requested, options.settings);
21
+ if ('error' in resolved)
22
+ throw new Error(resolved.error);
23
+ const adapter = getAdapter(resolved.provider.api);
24
+ const inputs = await resolveImageInputs(params.image, options.cwd, fetchImpl, options.signal);
25
+ const raws = await adapter.generate(resolved.provider, resolved.remoteId, params, fetchImpl, options.signal, inputs);
26
+ options.signal?.throwIfAborted();
27
+ const outDir = resolveOutputDir(params.outputDir ?? options.settings.outputDir, options.cwd);
28
+ await mkdir(outDir, { recursive: true });
29
+ const stamp = formatStamp(now());
30
+ const baseFilename = sanitizeFilename(params.filename ?? `${resolved.requestedId}-${stamp}`);
31
+ const images = [];
32
+ for (let i = 0; i < raws.length; i++) {
33
+ const raw = raws[i];
34
+ const fetched = await materialize(raw, fetchImpl, options.signal);
35
+ const ext = MIME_TO_EXT[fetched.mimeType] ?? 'png';
36
+ const suffix = raws.length > 1 ? `-${i + 1}` : '';
37
+ const path = resolve(outDir, `${baseFilename}${suffix}.${ext}`);
38
+ await writeFile(path, fetched.bytes);
39
+ const image = { path, mimeType: fetched.mimeType };
40
+ if (raw.revisedPrompt)
41
+ image.revisedPrompt = raw.revisedPrompt;
42
+ images.push(image);
43
+ }
44
+ return {
45
+ model: resolved.requestedId,
46
+ provider: providerLabel(resolved.provider),
47
+ images,
48
+ };
49
+ }
50
+ function providerLabel(provider) {
51
+ return provider.builtIn ? provider.id : `${provider.id} (custom)`;
52
+ }
53
+ function resolveOutputDir(configured, cwd) {
54
+ const target = configured && configured.trim().length > 0 ? configured : '.pi/images';
55
+ return isAbsolute(target) ? target : resolve(cwd, target);
56
+ }
57
+ function formatStamp(date) {
58
+ const pad = (n) => String(n).padStart(2, '0');
59
+ return `${date.getUTCFullYear()}${pad(date.getUTCMonth() + 1)}${pad(date.getUTCDate())}-${pad(date.getUTCHours())}${pad(date.getUTCMinutes())}${pad(date.getUTCSeconds())}`;
60
+ }
61
+ function sanitizeFilename(name) {
62
+ const trimmed = name
63
+ .trim()
64
+ .replace(/[\\/:*?"<>|]+/g, '-')
65
+ .replace(/\s+/g, '_');
66
+ return trimmed.length > 0 ? trimmed.slice(0, 100) : 'image';
67
+ }
68
+ async function materialize(raw, fetchImpl, signal) {
69
+ if (raw.data.kind === 'base64') {
70
+ return {
71
+ bytes: Buffer.from(raw.data.bytes, 'base64'),
72
+ mimeType: raw.data.mimeType ?? 'image/png',
73
+ };
74
+ }
75
+ if (!raw.data.url || !/^https?:\/\//i.test(raw.data.url)) {
76
+ throw new Error(`Provider returned a non-URL image reference (${raw.data.url ? raw.data.url.slice(0, 60) : 'empty'}). The response shape may have changed.`);
77
+ }
78
+ const res = await fetchImpl(raw.data.url, { signal: signal ?? null });
79
+ if (!res.ok) {
80
+ throw new Error(`Failed to download generated image (${res.status} ${res.statusText}).`);
81
+ }
82
+ const buf = new Uint8Array(await res.arrayBuffer());
83
+ const mimeType = res.headers.get('content-type')?.split(';')[0]?.trim() || 'image/png';
84
+ return { bytes: buf, mimeType };
85
+ }
86
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ResolvedImageInput } from './types.js';
2
+ export declare function resolveImageInputs(raw: string[] | undefined, cwd: string, fetchImpl: typeof fetch, signal?: AbortSignal): Promise<ResolvedImageInput[]>;
3
+ export declare function toDataUri(input: ResolvedImageInput): string;
4
+ /**
5
+ * Classify a string returned by an image-generation API as either a URL the
6
+ * caller should fetch, or base64 image bytes the caller already has.
7
+ *
8
+ * Different providers / gateways return image output in different shapes:
9
+ * - http(s):// URL → fetch it
10
+ * - `data:image/...;base64,...` → strip prefix, decode bytes
11
+ * - bare base64 string (PNG/JPEG/WebP/GIF magic bytes) → decode bytes
12
+ * - empty / whitespace → invalid, return null
13
+ *
14
+ * Returning `null` lets adapters skip junk entries (e.g. when a provider's
15
+ * response had `text` parts but no actual image).
16
+ */
17
+ export declare function classifyImageOutput(value: string | undefined | null): {
18
+ kind: 'url';
19
+ url: string;
20
+ } | {
21
+ kind: 'base64';
22
+ bytes: string;
23
+ mimeType: string;
24
+ } | null;
25
+ //# sourceMappingURL=image-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.d.ts","sourceRoot":"","sources":["../src/image-input.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAYrD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,EACzB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,OAAO,KAAK,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAO/B;AAqGD,wBAAgB,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAG3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAC/B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+B3F"}
@@ -0,0 +1,153 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { isAbsolute, resolve } from 'node:path';
3
+ const MAGIC_BYTES = [
4
+ { mimeType: 'image/png', bytes: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a] },
5
+ { mimeType: 'image/jpeg', bytes: [0xff, 0xd8, 0xff] },
6
+ { mimeType: 'image/gif', bytes: [0x47, 0x49, 0x46, 0x38] },
7
+ // WebP: "RIFF....WEBP" — bytes 0..3 = RIFF, bytes 8..11 = WEBP
8
+ { mimeType: 'image/webp', bytes: [0x52, 0x49, 0x46, 0x46] },
9
+ ];
10
+ const DATA_URI_RE = /^data:(image\/[a-z+.-]+);base64,(.+)$/i;
11
+ export async function resolveImageInputs(raw, cwd, fetchImpl, signal) {
12
+ if (!raw || raw.length === 0)
13
+ return [];
14
+ const out = [];
15
+ for (const entry of raw) {
16
+ out.push(await resolveOne(entry, cwd, fetchImpl, signal));
17
+ }
18
+ return out;
19
+ }
20
+ async function resolveOne(value, cwd, fetchImpl, signal) {
21
+ const trimmed = value.trim();
22
+ if (!trimmed)
23
+ throw new Error('image input is empty.');
24
+ // Reject base64 / data: URIs — tool-call payloads don't survive megabyte-sized
25
+ // string arguments cleanly across providers. Force callers to point us at a
26
+ // path or URL instead, which is also what /image_generate's tool description
27
+ // tells the model.
28
+ if (/^data:/i.test(trimmed)) {
29
+ throw new Error('Image input as a `data:` URI is not supported. Pass a file path (absolute or relative to cwd) or an http(s) URL instead. If you have raw image bytes, write them to a file under .pi/uploads first and pass that path.');
30
+ }
31
+ // Heuristic for raw base64: long, only base64 chars. Not foolproof but
32
+ // catches the common case where the model dumps a giant base64 blob.
33
+ if (trimmed.length > 256 && !/[\s/\\]/.test(trimmed) && /^[A-Za-z0-9+/]+={0,2}$/.test(trimmed)) {
34
+ throw new Error('Image input looks like a raw base64 blob; this is not supported because it bloats the tool argument. Write the bytes to a file path and pass that path instead.');
35
+ }
36
+ if (/^https?:\/\//i.test(trimmed)) {
37
+ const res = await fetchImpl(trimmed, { signal: signal ?? null });
38
+ if (!res.ok) {
39
+ throw new Error(`Failed to download image input from ${trimmed} (HTTP ${res.status}). Tell the user to verify the URL is reachable.`);
40
+ }
41
+ const buf = new Uint8Array(await res.arrayBuffer());
42
+ const mimeType = res.headers.get('content-type')?.split(';')[0]?.trim() || sniffMime(buf) || 'image/png';
43
+ return { bytes: buf, mimeType };
44
+ }
45
+ // Anything else — treat as a file path (absolute or relative to cwd).
46
+ const absolute = isAbsolute(trimmed) ? trimmed : resolve(cwd, trimmed);
47
+ let bytes;
48
+ try {
49
+ bytes = await readFile(absolute);
50
+ }
51
+ catch (error) {
52
+ throw new Error(`Image input "${trimmed}" is not a readable file path or http(s) URL (tried ${absolute}): ${error.message}. Pass an absolute path, a path relative to the session cwd, or an http(s) URL.`);
53
+ }
54
+ const mimeType = sniffMime(bytes) ?? extToMime(absolute) ?? 'image/png';
55
+ return { bytes, mimeType };
56
+ }
57
+ function sniffMime(bytes) {
58
+ for (const { mimeType, bytes: magic } of MAGIC_BYTES) {
59
+ if (bytes.length < magic.length)
60
+ continue;
61
+ let match = true;
62
+ for (let i = 0; i < magic.length; i++) {
63
+ if (bytes[i] !== magic[i]) {
64
+ match = false;
65
+ break;
66
+ }
67
+ }
68
+ if (!match)
69
+ continue;
70
+ if (mimeType === 'image/webp') {
71
+ // RIFF prefix matched — verify WEBP at offset 8.
72
+ if (bytes.length >= 12 &&
73
+ bytes[8] === 0x57 &&
74
+ bytes[9] === 0x45 &&
75
+ bytes[10] === 0x42 &&
76
+ bytes[11] === 0x50) {
77
+ return 'image/webp';
78
+ }
79
+ continue;
80
+ }
81
+ return mimeType;
82
+ }
83
+ return undefined;
84
+ }
85
+ function extToMime(path) {
86
+ const ext = path.split('.').pop()?.toLowerCase();
87
+ switch (ext) {
88
+ case 'png':
89
+ return 'image/png';
90
+ case 'jpg':
91
+ case 'jpeg':
92
+ return 'image/jpeg';
93
+ case 'webp':
94
+ return 'image/webp';
95
+ case 'gif':
96
+ return 'image/gif';
97
+ default:
98
+ return undefined;
99
+ }
100
+ }
101
+ export function toDataUri(input) {
102
+ const b64 = Buffer.from(input.bytes).toString('base64');
103
+ return `data:${input.mimeType};base64,${b64}`;
104
+ }
105
+ /**
106
+ * Classify a string returned by an image-generation API as either a URL the
107
+ * caller should fetch, or base64 image bytes the caller already has.
108
+ *
109
+ * Different providers / gateways return image output in different shapes:
110
+ * - http(s):// URL → fetch it
111
+ * - `data:image/...;base64,...` → strip prefix, decode bytes
112
+ * - bare base64 string (PNG/JPEG/WebP/GIF magic bytes) → decode bytes
113
+ * - empty / whitespace → invalid, return null
114
+ *
115
+ * Returning `null` lets adapters skip junk entries (e.g. when a provider's
116
+ * response had `text` parts but no actual image).
117
+ */
118
+ export function classifyImageOutput(value) {
119
+ if (!value)
120
+ return null;
121
+ const trimmed = value.trim();
122
+ if (!trimmed)
123
+ return null;
124
+ if (/^https?:\/\//i.test(trimmed)) {
125
+ return { kind: 'url', url: trimmed };
126
+ }
127
+ const dataMatch = DATA_URI_RE.exec(trimmed);
128
+ if (dataMatch) {
129
+ return {
130
+ kind: 'base64',
131
+ bytes: dataMatch[2],
132
+ mimeType: dataMatch[1].toLowerCase(),
133
+ };
134
+ }
135
+ // Maybe bare base64 — try to decode and sniff. Bail cheaply on anything that
136
+ // can't possibly be an image (too short, contains non-base64 chars).
137
+ if (trimmed.length < 16 || /[^A-Za-z0-9+/=\s]/.test(trimmed))
138
+ return null;
139
+ let decoded;
140
+ try {
141
+ decoded = Buffer.from(trimmed, 'base64');
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ if (decoded.length < 8)
147
+ return null;
148
+ const mimeType = sniffMime(decoded);
149
+ if (!mimeType)
150
+ return null;
151
+ return { kind: 'base64', bytes: trimmed, mimeType };
152
+ }
153
+ //# sourceMappingURL=image-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.js","sourceRoot":"","sources":["../src/image-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
+ import type { ImageGenResult } from './types.js';
3
+ export { loadImageGenSettings, resolveModel } from './config.js';
4
+ export { generateImage } from './generate.js';
5
+ export type { GenerateImageParams, ImageGenSettings } from './types.js';
6
+ export default function piImageGenExtension(pi: ExtensionAPI): void;
7
+ /**
8
+ * Format a generated-image result as text the LLM can paste verbatim into its
9
+ * reply. Uses inline markdown image syntax with the file stem as the alt text.
10
+ */
11
+ export declare function formatToolResultText(result: ImageGenResult): string;
12
+ /**
13
+ * Derive a markdown `alt` from the saved file path. We use the filename without
14
+ * its extension so the user-supplied `filename` (or our auto-generated stamp)
15
+ * shows up in the rendered image label, not the model id.
16
+ */
17
+ export declare function altFromPath(absolutePath: string): string;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAStF,OAAO,KAAK,EAAuB,cAAc,EAAoB,MAAM,YAAY,CAAC;AAExF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAExE,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAyHlE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAWnE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAOxD"}