@xinizai/pi-image-gen 0.1.0

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 (62) hide show
  1. package/README.md +337 -0
  2. package/dist/core/cache.d.ts +11 -0
  3. package/dist/core/cache.js +42 -0
  4. package/dist/core/cache.js.map +1 -0
  5. package/dist/core/capabilities.d.ts +2 -0
  6. package/dist/core/capabilities.js +65 -0
  7. package/dist/core/capabilities.js.map +1 -0
  8. package/dist/core/errors.d.ts +11 -0
  9. package/dist/core/errors.js +71 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/global-config.d.ts +25 -0
  12. package/dist/core/global-config.js +172 -0
  13. package/dist/core/global-config.js.map +1 -0
  14. package/dist/core/image-service.d.ts +14 -0
  15. package/dist/core/image-service.js +42 -0
  16. package/dist/core/image-service.js.map +1 -0
  17. package/dist/core/model-browser.d.ts +5 -0
  18. package/dist/core/model-browser.js +76 -0
  19. package/dist/core/model-browser.js.map +1 -0
  20. package/dist/core/model-registry.d.ts +10 -0
  21. package/dist/core/model-registry.js +44 -0
  22. package/dist/core/model-registry.js.map +1 -0
  23. package/dist/core/provider.d.ts +2 -0
  24. package/dist/core/provider.js +8 -0
  25. package/dist/core/provider.js.map +1 -0
  26. package/dist/core/types.d.ts +122 -0
  27. package/dist/core/types.js +2 -0
  28. package/dist/core/types.js.map +1 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +490 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/providers/openai-compatible.d.ts +16 -0
  33. package/dist/providers/openai-compatible.js +216 -0
  34. package/dist/providers/openai-compatible.js.map +1 -0
  35. package/dist/tools/shared.d.ts +42 -0
  36. package/dist/tools/shared.js +241 -0
  37. package/dist/tools/shared.js.map +1 -0
  38. package/dist/utils/config.d.ts +5 -0
  39. package/dist/utils/config.js +65 -0
  40. package/dist/utils/config.js.map +1 -0
  41. package/dist/utils/download.d.ts +8 -0
  42. package/dist/utils/download.js +139 -0
  43. package/dist/utils/download.js.map +1 -0
  44. package/dist/utils/files.d.ts +18 -0
  45. package/dist/utils/files.js +83 -0
  46. package/dist/utils/files.js.map +1 -0
  47. package/package.json +34 -0
  48. package/src/core/cache.ts +43 -0
  49. package/src/core/capabilities.ts +55 -0
  50. package/src/core/errors.ts +92 -0
  51. package/src/core/global-config.ts +167 -0
  52. package/src/core/image-service.ts +40 -0
  53. package/src/core/model-browser.ts +73 -0
  54. package/src/core/model-registry.ts +43 -0
  55. package/src/core/provider.ts +8 -0
  56. package/src/core/types.ts +135 -0
  57. package/src/index.ts +394 -0
  58. package/src/providers/openai-compatible.ts +198 -0
  59. package/src/tools/shared.ts +235 -0
  60. package/src/utils/config.ts +61 -0
  61. package/src/utils/download.ts +103 -0
  62. package/src/utils/files.ts +78 -0
package/README.md ADDED
@@ -0,0 +1,337 @@
1
+ # pi-image-gen
2
+
3
+ 一个通用 Pi Agent 图片生成扩展。用户只配置 `IMAGE_BASE_URL` 和 `IMAGE_API_KEY`,扩展会尽可能自动探测 OpenAI-compatible API、发现模型、识别模型能力,并向 Pi Agent 注册图片生成/编辑/变体工具。
4
+
5
+ > 第一版重点支持 OpenAI-compatible API:`GET /models`、`POST /images/generations`、`POST /images/edits`、`POST /images/variations`。其它 Provider 通过 Adapter 架构预留。
6
+
7
+ ## 功能
8
+
9
+ - 通过唯一用户入口 `/image-config` 管理多个跨项目共享的 Provider(环境变量仍可作为兼容 fallback)
10
+ - 有限、安全地探测 `GET /models`
11
+ - 自动识别模型能力:`image_generation`、`image_edit`、`image_variation`、`vision`、`text`、`unknown`
12
+ - 模型发现缓存,默认 10 分钟
13
+ - 自动选择稳定默认图片模型
14
+ - 支持 base64 和 URL 图片响应,统一保存为本地文件
15
+ - 图片保存目录默认:`~/.pi/agent/generated/`
16
+ - 不把 API Key 返回给 Agent 或写入输出
17
+ - 注册 Pi Tools:`image_generate`、`image_edit`、`image_variation`、`image_models`、`image_config`、`image_providers`
18
+ - 唯一面向用户的 Slash Command:`/image-config`
19
+
20
+ ## 安装
21
+
22
+ 开发目录中:
23
+
24
+ ```bash
25
+ npm install
26
+ npm run build
27
+ ```
28
+
29
+ 作为 Pi package 安装时,`package.json` 已声明:
30
+
31
+ ```json
32
+ {
33
+ "pi": {
34
+ "extensions": ["./dist/index.js"]
35
+ }
36
+ }
37
+ ```
38
+
39
+ 也可以在当前项目直接使用 `.pi/extensions/pi-image-gen.ts` 开发入口,然后在 Pi 中 `/reload`。
40
+
41
+ ## 配置
42
+
43
+ ## 配置入口
44
+
45
+ 在 Pi 中运行:
46
+
47
+ ```text
48
+ /image-config
49
+ ```
50
+
51
+ 即可添加 Provider、测试 `/models`、选择默认图片模型、设置默认 Provider,以及设置图片响应格式(自动兼容、URL、Base64 JSON)。配置跨项目保存在:
52
+
53
+ ```text
54
+ ~/.pi/agent/pi-image-gen/providers.json
55
+ ```
56
+
57
+ 最小环境变量配置(无全局 Provider 时的兼容 fallback):
58
+
59
+ ```bash
60
+ export IMAGE_BASE_URL=https://example.com/v1
61
+ export IMAGE_API_KEY=sk-xxxx
62
+ ```
63
+
64
+ Windows PowerShell:
65
+
66
+ ```powershell
67
+ $env:IMAGE_BASE_URL="https://example.com/v1"
68
+ $env:IMAGE_API_KEY="sk-xxxx"
69
+ ```
70
+
71
+ 可选配置:
72
+
73
+ ```bash
74
+ export IMAGE_MODEL=gpt-image-1 # fallback 或显式默认文生图模型
75
+ export IMAGE_EDIT_MODEL=gpt-image-1 # 默认编辑模型
76
+ export IMAGE_VARIATION_MODEL=dall-e-2 # 默认变体模型
77
+ export IMAGE_TIMEOUT_SECONDS=60
78
+ export IMAGE_CACHE_TTL_SECONDS=600
79
+ export IMAGE_OUTPUT_DIR=/path/to/generated
80
+ export IMAGE_MAX_RESPONSE_BYTES=8000000
81
+ export IMAGE_MAX_DOWNLOAD_BYTES=25000000
82
+ ```
83
+
84
+ 手动声明模型能力(当 API 无法自动识别时):
85
+
86
+ ```bash
87
+ export IMAGE_MODEL_CAPABILITIES="my-model:image_generation,image_edit;other-model:vision"
88
+ ```
89
+
90
+ ## API URL
91
+
92
+ `IMAGE_BASE_URL` 应指向 API 版本根路径,例如:
93
+
94
+ ```bash
95
+ https://api.example.com/v1
96
+ ```
97
+
98
+ 扩展只会针对该 Base URL 进行有限兼容探测:当前仅尝试 `GET /models`。不会扫描端口、不会递归探测大量 URL。
99
+
100
+ ## 自动发现模型
101
+
102
+ 启动后或首次调用工具时:
103
+
104
+ 1. 读取 Base URL 与 API Key
105
+ 2. 调用 `GET {IMAGE_BASE_URL}/models`
106
+ 3. 解析 `data[]`
107
+ 4. 优先使用 API metadata 中的能力字段
108
+ 5. 如果没有 metadata,则使用模型 ID 和 metadata 做启发式候选识别
109
+ 6. 写入缓存 `~/.pi/agent/image-gen-cache.json`
110
+
111
+ 如果 `/models` 不存在:
112
+
113
+ - 若设置了 `IMAGE_MODEL`,会把它作为 fallback 模型;
114
+ - 否则明确报错,并提示配置 `IMAGE_MODEL`。
115
+
116
+ ## 模型能力识别
117
+
118
+ 能力类型:
119
+
120
+ - `text`
121
+ - `vision`
122
+ - `image_generation`
123
+ - `image_edit`
124
+ - `image_variation`
125
+ - `unknown`
126
+
127
+ 识别优先级:
128
+
129
+ 1. 用户手动声明:`IMAGE_MODEL_CAPABILITIES`
130
+ 2. API 返回 metadata:`capabilities`、`modalities`、`input_modalities`、`output_modalities` 等
131
+ 3. 启发式识别:模型名包含 `image`、`img`、`dall-e`、`gpt-image`、`flux`、`stable-diffusion` 等
132
+ 4. 无法确认则标记为 `unknown`
133
+
134
+ 启发式识别只表示候选,不保证 100% 正确。扩展不会默认发送真实付费生图请求来验证能力。
135
+
136
+ ## 查看模型
137
+
138
+ 普通用户请在 Pi 中运行 `/image-config` 后进入 Provider 的“选择默认图片模型”。
139
+
140
+ Agent 仍可调用工具:
141
+
142
+ ```text
143
+ image_models({ "refresh": true })
144
+ ```
145
+
146
+ 输出按能力分组:
147
+
148
+ ```text
149
+ Image Generation:
150
+ - model-a
151
+ - model-b
152
+
153
+ Vision:
154
+ - model-c
155
+
156
+ Text:
157
+ - model-d
158
+
159
+ Unknown:
160
+ - model-e
161
+ ```
162
+
163
+ ## 文生图
164
+
165
+ 用户可以直接说:
166
+
167
+ ```text
168
+ 生成一张赛博朋克东京街头,16:9。
169
+ ```
170
+
171
+ Agent 应调用:
172
+
173
+ ```text
174
+ image_generate({
175
+ "prompt": "赛博朋克东京街头",
176
+ "aspect_ratio": "16:9"
177
+ })
178
+ ```
179
+
180
+ 参数:
181
+
182
+ - `prompt` 必填
183
+ - `model` 可选,默认自动选择
184
+ - `size` 可选,例如 `1024x1024`
185
+ - `aspect_ratio` 可选,例如 `16:9`
186
+ - `quality` 可选
187
+ - `output_format` 可选:`png`、`jpeg`、`jpg`、`webp`
188
+ - `n` 可选
189
+
190
+ ## 图片编辑
191
+
192
+ 工具:`image_edit`
193
+
194
+ 参数:
195
+
196
+ - `image`:Windows 本地路径、Linux 本地路径、`file://`、`https://`
197
+ - `prompt`
198
+ - `model?`
199
+ - `size?`
200
+ - `output_format?`
201
+
202
+ 支持输入格式:`.png`、`.jpg`、`.jpeg`、`.webp`。
203
+
204
+ 如果没有发现支持 `image_edit` 的模型,会明确报错,而不是伪造成功。
205
+
206
+ ## 图片变体
207
+
208
+ 工具:`image_variation`
209
+
210
+ 参数:
211
+
212
+ - `image`
213
+ - `model?`
214
+ - `size?`
215
+ - `n?`
216
+
217
+ 需要模型具备 `image_variation` 能力。
218
+
219
+ ## 缓存
220
+
221
+ 模型发现缓存默认有效期 10 分钟。
222
+
223
+ 缓存按 Provider 隔离,位于:
224
+
225
+ ```text
226
+ ~/.pi/agent/pi-image-gen/cache/providers/{providerId}.json
227
+ ```
228
+
229
+ 缓存包含 Base URL、Provider type、模型、能力和发现时间;不保存 API Key 明文。缓存 key 使用 Provider ID、Provider type、Base URL 与 API Key 指纹,API Key 或 Base URL 变化会自动失效。
230
+
231
+ 刷新模型、浏览模型和管理 Provider 都在:
232
+
233
+ ```text
234
+ /image-config
235
+ ```
236
+
237
+ ## 安全策略
238
+
239
+ - 不打印完整 API Key
240
+ - 不返回 Authorization Header
241
+ - 请求有 timeout
242
+ - API 响应大小有限制
243
+ - 图片下载大小有限制
244
+ - 只支持 http/https 图片 URL
245
+ - 不执行图片文件
246
+ - 不使用 eval
247
+ - 不执行用户输入
248
+ - 不进行端口扫描或大范围 API 探测
249
+
250
+ ## 添加 Provider
251
+
252
+ 核心接口在 `src/core/types.ts`:
253
+
254
+ ```ts
255
+ interface ImageProvider {
256
+ discoverModels(): Promise<ModelInfo[]>;
257
+ generate(...): Promise<ImageOperationResult>;
258
+ edit(...): Promise<ImageOperationResult>;
259
+ variation(...): Promise<ImageOperationResult>;
260
+ }
261
+ ```
262
+
263
+ 新增 Provider:
264
+
265
+ 1. 在 `src/providers/` 新建实现
266
+ 2. 实现 `ImageProvider`
267
+ 3. 在 `src/core/provider.ts` 中注册 resolver
268
+ 4. 添加 mock 测试
269
+
270
+ ## 故障排查
271
+
272
+ ### 401
273
+
274
+ API Key 错误或过期。检查 `IMAGE_API_KEY`。
275
+
276
+ ### 403
277
+
278
+ API Key 无权访问模型或图片接口。
279
+
280
+ ### 404 /models
281
+
282
+ Base URL 可能不包含 `/v1`,或服务商不支持 `/models`。可以设置 `IMAGE_MODEL` fallback。
283
+
284
+ ### 429
285
+
286
+ 限流或额度不足。稍后重试。
287
+
288
+ ### unknown 模型
289
+
290
+ 扩展无法确认模型能力。使用:
291
+
292
+ ```bash
293
+ export IMAGE_MODEL_CAPABILITIES="model-id:image_generation"
294
+ ```
295
+
296
+ ## 开发
297
+
298
+ ```bash
299
+ npm install
300
+ npm run typecheck
301
+ npm run build
302
+ npm test
303
+ npm pack --dry-run
304
+ ```
305
+
306
+ 测试使用 mock fetch,不会调用真实付费 API。
307
+
308
+ ## npm 发布
309
+
310
+ 发布前检查:
311
+
312
+ ```bash
313
+ npm pack --dry-run
314
+ ```
315
+
316
+ 确认包内没有:
317
+
318
+ - `.env`
319
+ - API Key
320
+ - 本地缓存
321
+ - 测试垃圾
322
+ - 大文件
323
+
324
+ 发布需手动执行:
325
+
326
+ ```bash
327
+ npm publish
328
+ ```
329
+
330
+ 本项目不会自动发布。
331
+
332
+ ## 已知限制
333
+
334
+ - 第一版仅实现 OpenAI-compatible Provider。
335
+ - 不会默认发送真实图片生成请求来验证能力,避免潜在付费。
336
+ - 不同服务商图片接口参数可能有差异;当前传递 OpenAI 风格常见字段。
337
+ - `image_edit` 使用 multipart/form-data,某些兼容 API 可能要求不同字段名。
@@ -0,0 +1,11 @@
1
+ import type { DiscoveryResult, ImageGenConfig } from "./types.js";
2
+ export declare class ModelDiscoveryCache {
3
+ private readonly cacheDir;
4
+ constructor(cacheDir?: string);
5
+ get(config: ImageGenConfig, now?: number): Promise<DiscoveryResult | undefined>;
6
+ set(config: ImageGenConfig, result: DiscoveryResult): Promise<void>;
7
+ key(config: ImageGenConfig): string;
8
+ apiKeyFingerprint(config: ImageGenConfig): string;
9
+ private fileFor;
10
+ private read;
11
+ }
@@ -0,0 +1,42 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readFile, writeFile, rename, chmod } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import { GLOBAL_DIR } from "./global-config.js";
5
+ export class ModelDiscoveryCache {
6
+ cacheDir;
7
+ constructor(cacheDir = resolve(GLOBAL_DIR, "cache", "providers")) {
8
+ this.cacheDir = cacheDir;
9
+ }
10
+ async get(config, now = Date.now()) {
11
+ const entry = await this.read(config.providerId).catch(() => undefined);
12
+ if (!entry)
13
+ return undefined;
14
+ if (entry.key !== this.key(config))
15
+ return undefined;
16
+ const discovered = Date.parse(entry.result.discoveredAt);
17
+ if (!Number.isFinite(discovered) || now - discovered > config.cacheTtlMs)
18
+ return undefined;
19
+ return entry.result;
20
+ }
21
+ async set(config, result) {
22
+ await mkdir(this.cacheDir, { recursive: true });
23
+ const file = this.fileFor(config.providerId);
24
+ const temp = `${file}.${process.pid}.tmp`;
25
+ await writeFile(temp, JSON.stringify({ key: this.key(config), result: { ...result, apiKeyFingerprint: this.apiKeyFingerprint(config) } }, null, 2), { encoding: "utf8", mode: 0o600 });
26
+ await chmod(temp, 0o600).catch(() => undefined);
27
+ await rename(temp, file);
28
+ }
29
+ key(config) {
30
+ return createHash("sha256").update(`${config.providerId}\n${config.providerType}\n${config.baseUrl}\n${config.apiKeyUpdatedAt}\n${this.apiKeyFingerprint(config)}`).digest("hex");
31
+ }
32
+ apiKeyFingerprint(config) {
33
+ return createHash("sha256").update(config.apiKey).digest("hex").slice(0, 12);
34
+ }
35
+ fileFor(providerId) {
36
+ return resolve(this.cacheDir, `${providerId.replace(/[^a-zA-Z0-9._-]/g, "_")}.json`);
37
+ }
38
+ async read(providerId) {
39
+ return JSON.parse(await readFile(this.fileFor(providerId), "utf8"));
40
+ }
41
+ }
42
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,WAAW,OAAO,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC;QAApD,aAAQ,GAAR,QAAQ,CAA4C;IAAG,CAAC;IAErF,KAAK,CAAC,GAAG,CAAC,MAAsB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;QAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACxE,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,SAAS,CAAC;QACrD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,UAAU,GAAG,MAAM,CAAC,UAAU;YAAE,OAAO,SAAS,CAAC;QAC3F,OAAO,KAAK,CAAC,MAAM,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAsB,EAAE,MAAuB;QACvD,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QAC1C,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvL,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED,GAAG,CAAC,MAAsB;QACxB,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,YAAY,KAAK,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,eAAe,KAAK,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpL,CAAC;IAED,iBAAiB,CAAC,MAAsB;QACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/E,CAAC;IAEO,OAAO,CAAC,UAAkB;QAChC,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACvF,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,UAAkB;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,CAA6C,CAAC;IAClH,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { ModelCapability, ModelInfo } from "./types.js";
2
+ export declare function detectCapabilities(id: string, metadata: Record<string, unknown>, manual?: ModelCapability[]): Pick<ModelInfo, "capabilities" | "capabilitySource" | "inputModalities" | "outputModalities" | "supportsImageInput" | "supportsMultipleImages" | "supportsSize" | "supportsQuality" | "supportsAspectRatio">;
@@ -0,0 +1,65 @@
1
+ const imageHints = ["image", "img", "dall-e", "dalle", "gpt-image", "flux", "stable-diffusion", "sdxl", "midjourney", "ideogram", "recraft"];
2
+ const visionHints = ["vision", "vl", "visual", "omni", "gpt-4o", "qwen-vl", "llava"];
3
+ const textHints = ["gpt", "claude", "llama", "mistral", "deepseek", "qwen", "kimi", "mimo"];
4
+ export function detectCapabilities(id, metadata, manual) {
5
+ if (manual?.length)
6
+ return base(manual, "manual", metadata);
7
+ const metaCaps = explicitCapabilities(metadata);
8
+ if (metaCaps.length)
9
+ return base(metaCaps, "metadata", metadata);
10
+ const haystack = `${id} ${JSON.stringify(metadata)}`.toLowerCase();
11
+ const caps = new Set();
12
+ if (imageHints.some((h) => haystack.includes(h))) {
13
+ caps.add("image_generation");
14
+ if (haystack.includes("edit") || haystack.includes("gpt-image"))
15
+ caps.add("image_edit");
16
+ if (haystack.includes("variation") || haystack.includes("dall-e"))
17
+ caps.add("image_variation");
18
+ }
19
+ if (visionHints.some((h) => haystack.includes(h)))
20
+ caps.add("vision");
21
+ if (caps.size === 0 && textHints.some((h) => haystack.includes(h)))
22
+ caps.add("text");
23
+ if (caps.size === 0)
24
+ caps.add("unknown");
25
+ return base([...caps], caps.has("unknown") ? "unknown" : "heuristic", metadata);
26
+ }
27
+ function explicitCapabilities(metadata) {
28
+ const values = [];
29
+ for (const key of ["capabilities", "capability", "modalities", "input_modalities", "output_modalities", "supported_generation_methods"]) {
30
+ const value = metadata[key];
31
+ if (Array.isArray(value))
32
+ values.push(...value.filter((v) => typeof v === "string"));
33
+ else if (typeof value === "string")
34
+ values.push(value);
35
+ }
36
+ const text = values.join(" ").toLowerCase();
37
+ const caps = new Set();
38
+ if (/image[_ -]?generation|text-to-image|generate_images|image_out|output:image/.test(text))
39
+ caps.add("image_generation");
40
+ if (/image[_ -]?edit|edit_images|inpaint|input:image/.test(text))
41
+ caps.add("image_edit");
42
+ if (/image[_ -]?variation|variations/.test(text))
43
+ caps.add("image_variation");
44
+ if (/vision|image_input|input:image/.test(text))
45
+ caps.add("vision");
46
+ if (/text|chat|completion/.test(text))
47
+ caps.add("text");
48
+ return [...caps];
49
+ }
50
+ function base(capabilities, source, metadata) {
51
+ const lower = JSON.stringify(metadata).toLowerCase();
52
+ const supportsImageInput = capabilities.includes("image_edit") || capabilities.includes("vision") || lower.includes("input:image") || lower.includes("image_input");
53
+ return {
54
+ capabilities,
55
+ capabilitySource: source,
56
+ inputModalities: supportsImageInput ? ["text", "image"] : ["text"],
57
+ outputModalities: capabilities.includes("image_generation") || capabilities.includes("image_edit") || capabilities.includes("image_variation") ? ["image"] : ["text"],
58
+ supportsImageInput,
59
+ supportsMultipleImages: lower.includes("multiple") || lower.includes("multi_image"),
60
+ supportsSize: true,
61
+ supportsQuality: lower.includes("quality") || capabilities.includes("image_generation"),
62
+ supportsAspectRatio: lower.includes("aspect") || capabilities.includes("image_generation"),
63
+ };
64
+ }
65
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/core/capabilities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export type ImageErrorCode = "missing_config" | "invalid_base_url" | "auth_failed" | "forbidden" | "not_found" | "rate_limited" | "server_error" | "timeout" | "network_error" | "invalid_request" | "invalid_json" | "invalid_image" | "unsupported_format" | "model_unavailable" | "capability_unknown" | "response_too_large" | "request_too_large" | "download_too_large" | "unsupported_provider";
2
+ export declare class ImageGenError extends Error {
3
+ readonly code: ImageErrorCode;
4
+ readonly suggestion: string;
5
+ readonly status?: number | undefined;
6
+ constructor(code: ImageErrorCode, message: string, suggestion: string, status?: number | undefined);
7
+ toUserMessage(): string;
8
+ }
9
+ export declare function sanitizeSecret(text: string, apiKey?: string): string;
10
+ export declare function maskApiKey(key: string): string;
11
+ export declare function errorFromStatus(status: number, action: string, detail?: string): ImageGenError;
@@ -0,0 +1,71 @@
1
+ export class ImageGenError extends Error {
2
+ code;
3
+ suggestion;
4
+ status;
5
+ constructor(code, message, suggestion, status) {
6
+ super(message);
7
+ this.code = code;
8
+ this.suggestion = suggestion;
9
+ this.status = status;
10
+ this.name = "ImageGenError";
11
+ }
12
+ toUserMessage() {
13
+ const status = this.status ? `HTTP ${this.status}。` : "";
14
+ return `${this.message}\n原因:${status}${reasonForCode(this.code)}\n解决办法:${this.suggestion}`;
15
+ }
16
+ }
17
+ export function sanitizeSecret(text, apiKey) {
18
+ let out = text;
19
+ if (apiKey)
20
+ out = out.split(apiKey).join(maskApiKey(apiKey));
21
+ out = out.replace(/Bearer\s+[A-Za-z0-9._\-]+/g, "Bearer ****");
22
+ out = out.replace(/sk-[A-Za-z0-9._\-]{8,}/g, (m) => maskApiKey(m));
23
+ return out;
24
+ }
25
+ export function maskApiKey(key) {
26
+ if (!key)
27
+ return "未配置";
28
+ if (key.length <= 8)
29
+ return "****";
30
+ return `${key.slice(0, 3)}-****${key.slice(-4)}`;
31
+ }
32
+ export function errorFromStatus(status, action, detail) {
33
+ switch (status) {
34
+ case 401: return new ImageGenError("auth_failed", `${action}失败:认证失败。`, "检查 IMAGE_API_KEY 是否正确、是否过期。", status);
35
+ case 403: return new ImageGenError("forbidden", `${action}失败:权限不足。`, "确认 API Key 有访问模型和图片接口的权限。", status);
36
+ case 404: return new ImageGenError("not_found", `${action}失败:接口不存在。`, "确认 IMAGE_BASE_URL 是否包含正确版本路径,例如 https://host/v1。", status);
37
+ case 408: return new ImageGenError("timeout", `${action}失败:请求超时。`, "稍后重试,或增大 IMAGE_TIMEOUT_SECONDS。", status);
38
+ case 409: return new ImageGenError("model_unavailable", `${action}失败:请求冲突或模型不可用。`, "尝试换模型,或检查服务商状态。", status);
39
+ case 413: return new ImageGenError("request_too_large", `${action}失败:请求体过大。`, "降低图片尺寸、减少 n,或使用更小的输入图片。", status);
40
+ case 429: return new ImageGenError("rate_limited", `${action}失败:触发限流。`, "稍后重试,或检查额度/并发限制。", status);
41
+ case 500:
42
+ case 502:
43
+ case 503: return new ImageGenError("server_error", `${action}失败:服务端错误。`, "稍后重试;若持续失败请联系 API 服务商。", status);
44
+ default: return new ImageGenError(status >= 500 ? "server_error" : status >= 400 ? "invalid_request" : "network_error", `${action}失败:HTTP ${status}${detail ? `:${detail}` : "。"}`, status >= 400 && status < 500 ? "检查模型名称、图片尺寸、响应格式和服务商文档。" : "检查网络连接和服务商状态。", status);
45
+ }
46
+ }
47
+ function reasonForCode(code) {
48
+ const map = {
49
+ missing_config: "缺少必要配置。",
50
+ invalid_base_url: "Base URL 格式不正确或不是 http/https。",
51
+ auth_failed: "API Key 无效或未授权。",
52
+ forbidden: "当前凭证没有访问权限。",
53
+ not_found: "目标 API 路径不存在。",
54
+ rate_limited: "请求过快或额度不足。",
55
+ server_error: "API 服务端返回错误。",
56
+ timeout: "网络请求超过超时时间。",
57
+ network_error: "网络连接失败或响应异常。",
58
+ invalid_request: "请求已到达 API,但参数或模型不符合服务商要求。",
59
+ invalid_json: "API 返回的 JSON 无法解析。",
60
+ invalid_image: "图片内容为空或不是有效图片。",
61
+ unsupported_format: "仅支持 png、jpg、jpeg、webp。",
62
+ model_unavailable: "模型不存在、不可用或不支持该操作。",
63
+ capability_unknown: "无法自动确认模型能力。",
64
+ response_too_large: "响应超过安全大小限制。",
65
+ request_too_large: "请求体超过服务商限制。",
66
+ download_too_large: "下载图片超过大小限制。",
67
+ unsupported_provider: "暂不支持该 Provider 类型。",
68
+ };
69
+ return map[code];
70
+ }
71
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAqBA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEpB;IAEA;IACA;IAJlB,YACkB,IAAoB,EACpC,OAAe,EACC,UAAkB,EAClB,MAAe;QAE/B,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAgB;QAEpB,eAAU,GAAV,UAAU,CAAQ;QAClB,WAAM,GAAN,MAAM,CAAS;QAG/B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;IAED,aAAa;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,OAAO,GAAG,IAAI,CAAC,OAAO,QAAQ,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;IAC7F,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAe;IAC1D,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,IAAI,MAAM;QAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,4BAA4B,EAAE,aAAa,CAAC,CAAC;IAC/D,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACnC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,MAAc,EAAE,MAAe;IAC7E,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,aAAa,EAAE,GAAG,MAAM,UAAU,EAAE,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAC9G,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,WAAW,EAAE,GAAG,MAAM,UAAU,EAAE,2BAA2B,EAAE,MAAM,CAAC,CAAC;QAC1G,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,WAAW,EAAE,GAAG,MAAM,WAAW,EAAE,kDAAkD,EAAE,MAAM,CAAC,CAAC;QAClI,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,SAAS,EAAE,GAAG,MAAM,UAAU,EAAE,iCAAiC,EAAE,MAAM,CAAC,CAAC;QAC9G,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,mBAAmB,EAAE,GAAG,MAAM,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;QAC9G,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,mBAAmB,EAAE,GAAG,MAAM,WAAW,EAAE,yBAAyB,EAAE,MAAM,CAAC,CAAC;QACjH,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,cAAc,EAAE,GAAG,MAAM,UAAU,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QACpG,KAAK,GAAG,CAAC;QACT,KAAK,GAAG,CAAC;QACT,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,cAAc,EAAE,GAAG,MAAM,WAAW,EAAE,wBAAwB,EAAE,MAAM,CAAC,CAAC;QAC3G,OAAO,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,eAAe,EAAE,GAAG,MAAM,WAAW,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAC3Q,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAoB;IACzC,MAAM,GAAG,GAAmC;QAC1C,cAAc,EAAE,SAAS;QACzB,gBAAgB,EAAE,+BAA+B;QACjD,WAAW,EAAE,iBAAiB;QAC9B,SAAS,EAAE,aAAa;QACxB,SAAS,EAAE,eAAe;QAC1B,YAAY,EAAE,YAAY;QAC1B,YAAY,EAAE,cAAc;QAC5B,OAAO,EAAE,aAAa;QACtB,aAAa,EAAE,cAAc;QAC7B,eAAe,EAAE,2BAA2B;QAC5C,YAAY,EAAE,oBAAoB;QAClC,aAAa,EAAE,gBAAgB;QAC/B,kBAAkB,EAAE,wBAAwB;QAC5C,iBAAiB,EAAE,mBAAmB;QACtC,kBAAkB,EAAE,aAAa;QACjC,kBAAkB,EAAE,aAAa;QACjC,iBAAiB,EAAE,aAAa;QAChC,kBAAkB,EAAE,aAAa;QACjC,oBAAoB,EAAE,oBAAoB;KAC3C,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { GlobalImageGenConfig, ImageGenConfig, StoredProviderConfig } from "./types.js";
2
+ export declare const GLOBAL_DIR: string;
3
+ export declare const PROVIDERS_FILE: string;
4
+ export declare class GlobalConfigStore {
5
+ private readonly filePath;
6
+ constructor(filePath?: string);
7
+ read(): Promise<GlobalImageGenConfig>;
8
+ write(config: GlobalImageGenConfig): Promise<void>;
9
+ addProvider(input: {
10
+ id?: string;
11
+ name: string;
12
+ baseUrl: string;
13
+ apiKey: string;
14
+ defaultModel?: string;
15
+ responseFormat?: "auto" | "url" | "b64_json";
16
+ manualCapabilities?: string;
17
+ }): Promise<StoredProviderConfig>;
18
+ updateProvider(id: string, patch: Partial<Omit<StoredProviderConfig, "id" | "createdAt">>): Promise<StoredProviderConfig>;
19
+ deleteProvider(id: string): Promise<void>;
20
+ setDefaultProvider(id: string): Promise<void>;
21
+ resolveProvider(idOrName?: string): Promise<StoredProviderConfig | undefined>;
22
+ toRuntimeConfig(provider: StoredProviderConfig, env?: NodeJS.ProcessEnv): Promise<ImageGenConfig>;
23
+ }
24
+ export declare function envFallbackProvider(env?: NodeJS.ProcessEnv): StoredProviderConfig | undefined;
25
+ export declare function resolveRuntimeConfig(providerId?: string, env?: NodeJS.ProcessEnv, store?: GlobalConfigStore): Promise<ImageGenConfig>;