@aexol/spectral 0.9.73 → 0.9.74

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.
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../../sdk/coding-agent/index.js";
2
+ export default function imageGenerationExtension(ext: ExtensionAPI): Promise<void>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/image-generation/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,YAAY,EAAkB,MAAM,iCAAiC,CAAC;AAmCrG,wBAA8B,wBAAwB,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDvF"}
@@ -0,0 +1,79 @@
1
+ import { Type } from "typebox";
2
+ import { generateImages, getImageModel, getImageModels } from "../../sdk/ai/index.js";
3
+ const imageGenerateSchema = Type.Object({
4
+ prompt: Type.String({ description: "Text prompt describing the image to generate." }),
5
+ model: Type.Optional(Type.String({ default: "google/gemini-3.1-flash-lite-image", description: "OpenRouter image model id." })),
6
+ images: Type.Optional(Type.Array(Type.Object({
7
+ data: Type.String({ description: "Reference image as raw base64 or data URL." }),
8
+ mimeType: Type.Optional(Type.String({ default: "image/png", description: "Reference image MIME type." })),
9
+ }), { description: "Optional reference images for image-to-image generation." })),
10
+ n: Type.Optional(Type.Number({ minimum: 1, maximum: 10, default: 1 })),
11
+ resolution: Type.Optional(Type.String({ description: "Resolution tier, e.g. 512, 1K, 2K, 4K." })),
12
+ aspect_ratio: Type.Optional(Type.String({ description: "Aspect ratio, e.g. 1:1, 16:9, 9:16, auto." })),
13
+ size: Type.Optional(Type.String({ description: "OpenRouter size shorthand, e.g. 2K or 2048x2048." })),
14
+ quality: Type.Optional(Type.Union([Type.Literal("auto"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high")])),
15
+ output_format: Type.Optional(Type.Union([Type.Literal("png"), Type.Literal("jpeg"), Type.Literal("webp")])),
16
+ background: Type.Optional(Type.Union([Type.Literal("auto"), Type.Literal("transparent"), Type.Literal("opaque")])),
17
+ output_compression: Type.Optional(Type.Number({ minimum: 0, maximum: 100 })),
18
+ seed: Type.Optional(Type.Number()),
19
+ });
20
+ function imageModel(modelId) {
21
+ const exact = getImageModel("openrouter", modelId);
22
+ if (exact)
23
+ return exact;
24
+ return getImageModels("openrouter").find((model) => model.id === modelId);
25
+ }
26
+ function resultText(count, model, usageCost) {
27
+ const lines = [`✓ Generated ${count} image${count === 1 ? "" : "s"}`, `Model: ${model}`];
28
+ if (usageCost != null && Number.isFinite(usageCost))
29
+ lines.push(`Cost: $${usageCost.toFixed(6)}`);
30
+ return lines.join("\n");
31
+ }
32
+ export default async function imageGenerationExtension(ext) {
33
+ const tool = {
34
+ name: "image_generate",
35
+ label: "Generate Image",
36
+ description: "Generate images through OpenRouter's Images API. Supports text-to-image and image-to-image via optional reference images.",
37
+ promptSnippet: "`image_generate { prompt, model?, images?, aspect_ratio?, resolution? }` — generate image content",
38
+ parameters: imageGenerateSchema,
39
+ async execute(_toolCallId, params, signal) {
40
+ const input = params;
41
+ const modelId = input.model ?? "google/gemini-3.1-flash-lite-image";
42
+ const model = imageModel(modelId);
43
+ if (!model) {
44
+ return {
45
+ content: [{ type: "text", text: `❌ Unknown OpenRouter image model: ${modelId}` }],
46
+ details: { isError: true, model: modelId },
47
+ };
48
+ }
49
+ const context = {
50
+ input: [
51
+ { type: "text", text: input.prompt },
52
+ ...(input.images ?? []).map((image) => ({
53
+ type: "image",
54
+ data: image.data,
55
+ mimeType: image.mimeType ?? "image/png",
56
+ })),
57
+ ],
58
+ };
59
+ const response = await generateImages(model, context, { ...input, signal });
60
+ if (response.stopReason !== "stop") {
61
+ const message = response.errorMessage ?? "Image generation failed";
62
+ return {
63
+ content: [{ type: "text", text: `❌ ${message}` }],
64
+ details: { isError: true, model: model.id, stopReason: response.stopReason, errorMessage: message },
65
+ };
66
+ }
67
+ const images = response.output.filter((item) => item.type === "image");
68
+ return {
69
+ content: [
70
+ { type: "text", text: resultText(images.length, response.model, response.usage?.cost.total) },
71
+ ...response.output,
72
+ ],
73
+ details: { isError: false, model: response.model, count: images.length, usage: response.usage },
74
+ };
75
+ },
76
+ };
77
+ ext.registerTool(tool);
78
+ process.stderr.write("[image-generation] Registered image_generate tool.\n");
79
+ }
@@ -1,5 +1,95 @@
1
1
  export declare const IMAGE_MODELS: {
2
2
  readonly openrouter: {
3
+ readonly "google/gemini-3.1-flash-lite-image": {
4
+ id: string;
5
+ name: string;
6
+ api: "openrouter-images";
7
+ provider: string;
8
+ baseUrl: string;
9
+ input: ("text" | "image")[];
10
+ output: ("text" | "image")[];
11
+ cost: {
12
+ input: number;
13
+ output: number;
14
+ cacheRead: number;
15
+ cacheWrite: number;
16
+ };
17
+ };
18
+ readonly "google/gemini-3.1-flash-image": {
19
+ id: string;
20
+ name: string;
21
+ api: "openrouter-images";
22
+ provider: string;
23
+ baseUrl: string;
24
+ input: ("text" | "image")[];
25
+ output: ("text" | "image")[];
26
+ cost: {
27
+ input: number;
28
+ output: number;
29
+ cacheRead: number;
30
+ cacheWrite: number;
31
+ };
32
+ };
33
+ readonly "google/gemini-3-pro-image": {
34
+ id: string;
35
+ name: string;
36
+ api: "openrouter-images";
37
+ provider: string;
38
+ baseUrl: string;
39
+ input: ("text" | "image")[];
40
+ output: ("text" | "image")[];
41
+ cost: {
42
+ input: number;
43
+ output: number;
44
+ cacheRead: number;
45
+ cacheWrite: number;
46
+ };
47
+ };
48
+ readonly "openai/gpt-image-1": {
49
+ id: string;
50
+ name: string;
51
+ api: "openrouter-images";
52
+ provider: string;
53
+ baseUrl: string;
54
+ input: ("text" | "image")[];
55
+ output: "image"[];
56
+ cost: {
57
+ input: number;
58
+ output: number;
59
+ cacheRead: number;
60
+ cacheWrite: number;
61
+ };
62
+ };
63
+ readonly "openai/gpt-image-1-mini": {
64
+ id: string;
65
+ name: string;
66
+ api: "openrouter-images";
67
+ provider: string;
68
+ baseUrl: string;
69
+ input: ("text" | "image")[];
70
+ output: "image"[];
71
+ cost: {
72
+ input: number;
73
+ output: number;
74
+ cacheRead: number;
75
+ cacheWrite: number;
76
+ };
77
+ };
78
+ readonly "openai/gpt-image-2": {
79
+ id: string;
80
+ name: string;
81
+ api: "openrouter-images";
82
+ provider: string;
83
+ baseUrl: string;
84
+ input: ("text" | "image")[];
85
+ output: "image"[];
86
+ cost: {
87
+ input: number;
88
+ output: number;
89
+ cacheRead: number;
90
+ cacheWrite: number;
91
+ };
92
+ };
3
93
  readonly "black-forest-labs/flux.2-flex": {
4
94
  id: string;
5
95
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"image-models.generated.d.ts","sourceRoot":"","sources":["../../../src/sdk/ai/image-models.generated.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsbkD,CAAC"}
1
+ {"version":3,"file":"image-models.generated.d.ts","sourceRoot":"","sources":["../../../src/sdk/ai/image-models.generated.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAghBkD,CAAC"}
@@ -2,6 +2,96 @@
2
2
  // Do not edit manually - run 'npm run generate-image-models' to update
3
3
  export const IMAGE_MODELS = {
4
4
  openrouter: {
5
+ "google/gemini-3.1-flash-lite-image": {
6
+ id: "google/gemini-3.1-flash-lite-image",
7
+ name: "Google: Nano Banana 2 Lite (Gemini 3.1 Flash Lite Image)",
8
+ api: "openrouter-images",
9
+ provider: "openrouter",
10
+ baseUrl: "https://openrouter.ai/api/v1",
11
+ input: ["image", "text"],
12
+ output: ["image", "text"],
13
+ cost: {
14
+ input: 0.25,
15
+ output: 1.5,
16
+ cacheRead: 0,
17
+ cacheWrite: 0,
18
+ },
19
+ },
20
+ "google/gemini-3.1-flash-image": {
21
+ id: "google/gemini-3.1-flash-image",
22
+ name: "Google: Nano Banana 2 (Gemini 3.1 Flash Image)",
23
+ api: "openrouter-images",
24
+ provider: "openrouter",
25
+ baseUrl: "https://openrouter.ai/api/v1",
26
+ input: ["image", "text"],
27
+ output: ["image", "text"],
28
+ cost: {
29
+ input: 0.5,
30
+ output: 3,
31
+ cacheRead: 0,
32
+ cacheWrite: 0,
33
+ },
34
+ },
35
+ "google/gemini-3-pro-image": {
36
+ id: "google/gemini-3-pro-image",
37
+ name: "Google: Nano Banana Pro (Gemini 3 Pro Image)",
38
+ api: "openrouter-images",
39
+ provider: "openrouter",
40
+ baseUrl: "https://openrouter.ai/api/v1",
41
+ input: ["image", "text"],
42
+ output: ["image", "text"],
43
+ cost: {
44
+ input: 2,
45
+ output: 12,
46
+ cacheRead: 0.2,
47
+ cacheWrite: 0.375,
48
+ },
49
+ },
50
+ "openai/gpt-image-1": {
51
+ id: "openai/gpt-image-1",
52
+ name: "OpenAI: GPT Image 1",
53
+ api: "openrouter-images",
54
+ provider: "openrouter",
55
+ baseUrl: "https://openrouter.ai/api/v1",
56
+ input: ["text", "image"],
57
+ output: ["image"],
58
+ cost: {
59
+ input: 0,
60
+ output: 0,
61
+ cacheRead: 0,
62
+ cacheWrite: 0,
63
+ },
64
+ },
65
+ "openai/gpt-image-1-mini": {
66
+ id: "openai/gpt-image-1-mini",
67
+ name: "OpenAI: GPT Image 1 Mini",
68
+ api: "openrouter-images",
69
+ provider: "openrouter",
70
+ baseUrl: "https://openrouter.ai/api/v1",
71
+ input: ["text", "image"],
72
+ output: ["image"],
73
+ cost: {
74
+ input: 0,
75
+ output: 0,
76
+ cacheRead: 0,
77
+ cacheWrite: 0,
78
+ },
79
+ },
80
+ "openai/gpt-image-2": {
81
+ id: "openai/gpt-image-2",
82
+ name: "OpenAI: GPT Image 2",
83
+ api: "openrouter-images",
84
+ provider: "openrouter",
85
+ baseUrl: "https://openrouter.ai/api/v1",
86
+ input: ["text", "image"],
87
+ output: ["image"],
88
+ cost: {
89
+ input: 0,
90
+ output: 0,
91
+ cacheRead: 0,
92
+ cacheWrite: 0,
93
+ },
94
+ },
5
95
  "black-forest-labs/flux.2-flex": {
6
96
  id: "black-forest-labs/flux.2-flex",
7
97
  name: "Black Forest Labs: FLUX.2 Flex",
@@ -0,0 +1,3 @@
1
+ import type { AssistantImages, ImagesContext, ImagesModel, ProviderImagesOptions } from "../types.js";
2
+ export declare function generateOpenRouterImages(model: ImagesModel<"openrouter-images">, context: ImagesContext, options?: ProviderImagesOptions): Promise<AssistantImages>;
3
+ //# sourceMappingURL=openrouter-images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter-images.d.ts","sourceRoot":"","sources":["../../../../src/sdk/ai/providers/openrouter-images.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,eAAe,EAEf,aAAa,EACb,WAAW,EACX,qBAAqB,EAGrB,MAAM,aAAa,CAAC;AA6DrB,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,WAAW,CAAC,mBAAmB,CAAC,EACvC,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE,qBAA0B,GACjC,OAAO,CAAC,eAAe,CAAC,CAiF1B"}
@@ -0,0 +1,149 @@
1
+ import { getEnvApiKey } from "../env-api-keys.js";
2
+ const DEFAULT_TIMEOUT_MS = 120_000;
3
+ const PASSTHROUGH_KEYS = [
4
+ "n",
5
+ "resolution",
6
+ "aspect_ratio",
7
+ "size",
8
+ "quality",
9
+ "output_format",
10
+ "background",
11
+ "output_compression",
12
+ "seed",
13
+ "stream",
14
+ "provider",
15
+ ];
16
+ function textFromContext(context) {
17
+ return context.input
18
+ .filter((item) => item.type === "text")
19
+ .map((item) => item.text.trim())
20
+ .filter(Boolean)
21
+ .join("\n\n");
22
+ }
23
+ function referencesFromContext(context) {
24
+ return context.input
25
+ .filter((item) => item.type === "image")
26
+ .map((item) => ({
27
+ type: "image_url",
28
+ image_url: {
29
+ url: item.data.startsWith("data:") ? item.data : `data:${item.mimeType};base64,${item.data}`,
30
+ },
31
+ }));
32
+ }
33
+ function usageFromOpenRouter(raw) {
34
+ const usage = raw?.usage;
35
+ if (!usage)
36
+ return undefined;
37
+ const input = Number(usage.prompt_tokens ?? usage.input_tokens ?? 0) || 0;
38
+ const output = Number(usage.completion_tokens ?? usage.output_tokens ?? 0) || 0;
39
+ const totalTokens = Number(usage.total_tokens ?? input + output) || 0;
40
+ const totalCost = Number(usage.cost ?? 0) || 0;
41
+ return {
42
+ input,
43
+ output,
44
+ cacheRead: Number(usage.cache_read_tokens ?? 0) || 0,
45
+ cacheWrite: Number(usage.cache_write_tokens ?? 0) || 0,
46
+ totalTokens,
47
+ cost: { input: 0, output: totalCost, cacheRead: 0, cacheWrite: 0, total: totalCost },
48
+ };
49
+ }
50
+ function mediaTypeFor(item, outputFormat) {
51
+ if (typeof item?.media_type === "string" && item.media_type)
52
+ return item.media_type;
53
+ if (outputFormat === "jpeg" || outputFormat === "jpg")
54
+ return "image/jpeg";
55
+ if (outputFormat === "webp")
56
+ return "image/webp";
57
+ return "image/png";
58
+ }
59
+ export async function generateOpenRouterImages(model, context, options = {}) {
60
+ const apiKey = options.apiKey ?? getEnvApiKey("openrouter");
61
+ if (!apiKey) {
62
+ throw new Error("Missing OPENROUTER_API_KEY for OpenRouter image generation");
63
+ }
64
+ const prompt = textFromContext(context);
65
+ if (!prompt)
66
+ throw new Error("Image generation prompt is required");
67
+ const references = referencesFromContext(context);
68
+ const body = {
69
+ model: model.id,
70
+ prompt,
71
+ };
72
+ for (const key of PASSTHROUGH_KEYS) {
73
+ if (options[key] !== undefined)
74
+ body[key] = options[key];
75
+ }
76
+ const extraReferences = Array.isArray(options.input_references) ? options.input_references : [];
77
+ const inputReferences = [...references, ...extraReferences];
78
+ if (inputReferences.length > 0)
79
+ body.input_references = inputReferences;
80
+ if (!body.n)
81
+ body.n = 1;
82
+ const controller = new AbortController();
83
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
84
+ if (options.signal) {
85
+ if (options.signal.aborted)
86
+ controller.abort();
87
+ else
88
+ options.signal.addEventListener("abort", () => controller.abort(), { once: true });
89
+ }
90
+ try {
91
+ const response = await fetch(`${model.baseUrl.replace(/\/$/, "")}/images`, {
92
+ method: "POST",
93
+ headers: {
94
+ "Content-Type": "application/json",
95
+ Authorization: `Bearer ${apiKey}`,
96
+ "HTTP-Referer": "https://aexol.ai",
97
+ "X-OpenRouter-Title": "Aexol.ai",
98
+ "X-OpenRouter-Categories": "cli-agent",
99
+ ...(options.headers ?? {}),
100
+ },
101
+ body: JSON.stringify(body),
102
+ signal: controller.signal,
103
+ });
104
+ options.onResponse?.({ status: response.status, headers: Object.fromEntries(response.headers.entries()) }, model);
105
+ const rawText = await response.text();
106
+ let json;
107
+ try {
108
+ json = rawText ? JSON.parse(rawText) : {};
109
+ }
110
+ catch {
111
+ throw new Error(`OpenRouter image response was not JSON: ${rawText.slice(0, 500)}`);
112
+ }
113
+ if (!response.ok) {
114
+ throw new Error(json?.error?.message ?? `OpenRouter image generation failed: HTTP ${response.status}`);
115
+ }
116
+ const output = [];
117
+ for (const item of Array.isArray(json.data) ? json.data : []) {
118
+ if (typeof item?.b64_json === "string") {
119
+ output.push({ type: "image", data: item.b64_json, mimeType: mediaTypeFor(item, body.output_format) });
120
+ }
121
+ if (typeof item?.text === "string" && item.text)
122
+ output.push({ type: "text", text: item.text });
123
+ }
124
+ return {
125
+ api: model.api,
126
+ provider: model.provider,
127
+ model: model.id,
128
+ output,
129
+ usage: usageFromOpenRouter(json),
130
+ stopReason: "stop",
131
+ responseId: typeof json.id === "string" ? json.id : undefined,
132
+ timestamp: Date.now(),
133
+ };
134
+ }
135
+ catch (error) {
136
+ return {
137
+ api: model.api,
138
+ provider: model.provider,
139
+ model: model.id,
140
+ output: [],
141
+ stopReason: controller.signal.aborted ? "aborted" : "error",
142
+ errorMessage: error instanceof Error ? error.message : String(error),
143
+ timestamp: Date.now(),
144
+ };
145
+ }
146
+ finally {
147
+ clearTimeout(timeout);
148
+ }
149
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"register-builtins.d.ts","sourceRoot":"","sources":["../../../../src/sdk/ai/providers/register-builtins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAMX,mBAAmB,EACnB,cAAc,EAEd,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAwGxE,eAAO,MAAM,eAAe,wDAAkC,CAAC;AAC/D,eAAO,MAAM,qBAAqB,2DAAwC,CAAC;AAC3E,eAAO,MAAM,uBAAuB,gEAA0C,CAAC;AAC/E,eAAO,MAAM,6BAA6B,2DAAgD,CAAC;AAE3F;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAWlD;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
1
+ {"version":3,"file":"register-builtins.d.ts","sourceRoot":"","sources":["../../../../src/sdk/ai/providers/register-builtins.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAMX,mBAAmB,EACnB,cAAc,EAEd,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAyGxE,eAAO,MAAM,eAAe,wDAAkC,CAAC;AAC/D,eAAO,MAAM,qBAAqB,2DAAwC,CAAC;AAC3E,eAAO,MAAM,uBAAuB,gEAA0C,CAAC;AAC/E,eAAO,MAAM,6BAA6B,2DAAgD,CAAC;AAE3F;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAelD;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC"}
@@ -1,5 +1,7 @@
1
1
  import { clearApiProviders, registerApiProvider } from "../api-registry.js";
2
+ import { registerImagesApiProvider } from "../images-api-registry.js";
2
3
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
4
+ import { generateOpenRouterImages } from "./openrouter-images.js";
3
5
  function createLazyErrorMessage(model, error) {
4
6
  return {
5
7
  role: "assistant",
@@ -89,6 +91,10 @@ export function registerBuiltInApiProviders() {
89
91
  stream: streamOpenAICompletions,
90
92
  streamSimple: streamSimpleOpenAICompletions,
91
93
  });
94
+ registerImagesApiProvider({
95
+ api: "openrouter-images",
96
+ generateImages: generateOpenRouterImages,
97
+ });
92
98
  }
93
99
  export function resetApiProviders() {
94
100
  clearApiProviders();
@@ -1 +1 @@
1
- {"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAmGtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAElF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAI1G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC,CAUD"}
1
+ {"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EA8GtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAElF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAI1G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC,CAUD"}
@@ -68,6 +68,16 @@ export const NATIVE_EXTENSIONS = [
68
68
  defaultEnabled: false,
69
69
  tags: ["wizard", "skills", "artifacts", "integration"],
70
70
  },
71
+ {
72
+ id: "image-generation",
73
+ label: "Image Generation",
74
+ description: "Generates images through OpenRouter's Images API. Supports text prompts " +
75
+ "and optional reference images for image-to-image workflows.",
76
+ category: "automation",
77
+ entryPath: "src/extensions/image-generation/index.ts",
78
+ defaultEnabled: true,
79
+ tags: ["images", "generation", "openrouter"],
80
+ },
71
81
  {
72
82
  id: "spectral-vision-fallback",
73
83
  label: "Spectral Vision Fallback",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aexol/spectral",
3
- "version": "0.9.73",
3
+ "version": "0.9.74",
4
4
  "description": "AI coding agent for Aexol with relay-based browser access.",
5
5
  "type": "module",
6
6
  "private": false,