@warlock.js/ai 4.13.0 → 4.15.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.
- package/CHANGELOG.md +22 -0
- package/cjs/index.cjs +6 -38
- package/cjs/index.cjs.map +1 -1
- package/esm/contracts/index.d.mts +1 -1
- package/esm/contracts/team/team-config.type.d.mts +9 -6
- package/esm/contracts/team/team-config.type.d.mts.map +1 -1
- package/esm/contracts/tool.contract.d.mts +35 -3
- package/esm/contracts/tool.contract.d.mts.map +1 -1
- package/esm/index.d.mts +3 -3
- package/esm/mock/index.d.mts +1 -1
- package/esm/mock/mock-config.type.d.mts +33 -4
- package/esm/mock/mock-config.type.d.mts.map +1 -1
- package/esm/mock/mock-model.d.mts +2 -1
- package/esm/mock/mock-model.d.mts.map +1 -1
- package/esm/mock/mock-model.mjs +5 -4
- package/esm/mock/mock-model.mjs.map +1 -1
- package/esm/mock/mock-sdk.d.mts +11 -3
- package/esm/mock/mock-sdk.d.mts.map +1 -1
- package/esm/mock/mock-sdk.mjs.map +1 -1
- package/esm/planner/plan-schema.d.mts +12 -1
- package/esm/planner/plan-schema.d.mts.map +1 -1
- package/esm/planner/plan-schema.mjs +0 -19
- package/esm/planner/plan-schema.mjs.map +1 -1
- package/esm/supervisor/execution.d.mts +0 -12
- package/esm/supervisor/execution.d.mts.map +1 -1
- package/esm/supervisor/execution.mjs +1 -15
- package/esm/supervisor/execution.mjs.map +1 -1
- package/llms-full.txt +15 -6
- package/llms.txt +1 -1
- package/package.json +24 -4
- package/skills/README.md +1 -1
- package/skills/generate-images/SKILL.md +13 -4
- package/skills/generate-speech/SKILL.md +1 -1
- package/skills/transcribe-audio/SKILL.md +1 -1
package/llms-full.txt
CHANGED
|
@@ -1545,7 +1545,7 @@ if (report.regression && !report.regression.passed) process.exit(1);
|
|
|
1545
1545
|
|
|
1546
1546
|
---
|
|
1547
1547
|
name: generate-images
|
|
1548
|
-
description: 'Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter''s image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google imagen-* (per-image). Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; ''generate an image'', ''text to image'', ''gpt-image'', ''dall-e'', ''imagen'', ''product thumbnail'', ''image output''; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.'
|
|
1548
|
+
description: 'Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter''s image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google gemini-* (generateContent + responseModalities IMAGE, usage passed through) / imagen-* and every other id (per-image, generateImages — deprecated by Google); the id picks the transport and is never validated locally. Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; ''generate an image'', ''text to image'', ''gpt-image'', ''dall-e'', ''imagen'', ''product thumbnail'', ''image output''; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.'
|
|
1549
1549
|
---
|
|
1550
1550
|
|
|
1551
1551
|
# Generate images — the image-output verb (`ai.image`)
|
|
@@ -1626,20 +1626,29 @@ const gpt = openai.image({ name: "gpt-image-1", pricing: { input: 5, output: 40
|
|
|
1626
1626
|
const dalle = openai.image({ name: "dall-e-3", pricing: { perImage: 0.04 } });
|
|
1627
1627
|
```
|
|
1628
1628
|
|
|
1629
|
-
|
|
1629
|
+
The model id is **not validated locally**. `openai.image({ name })` forwards the id to `client.images.generate` exactly as given, so a non-image id (`openai.image({ name: "gpt-4o" })`) constructs fine and fails at OpenAI — as a typed provider error on `result.error`, never as a local throw at construction.
|
|
1630
1630
|
|
|
1631
|
-
## Google — Imagen (per-image)
|
|
1631
|
+
## Google — Imagen (per-image) and Gemini (per-token)
|
|
1632
1632
|
|
|
1633
1633
|
```ts
|
|
1634
1634
|
import { GoogleSDK } from "@warlock.js/ai-google";
|
|
1635
1635
|
|
|
1636
1636
|
const google = new GoogleSDK({ apiKey: process.env.GEMINI_API_KEY! });
|
|
1637
|
+
|
|
1638
|
+
// Imagen — per-image-metered, via ai.models.generateImages:
|
|
1637
1639
|
const imagen = google.image({ name: "imagen-4.0-generate-001", pricing: { perImage: 0.04 } });
|
|
1638
1640
|
|
|
1641
|
+
// Gemini image model — token-metered, via ai.models.generateContent:
|
|
1642
|
+
const gemini = google.image({ name: "gemini-3.1-flash-lite-image", pricing: { input: 0.3, output: 30 } });
|
|
1643
|
+
|
|
1639
1644
|
const { data } = await ai.image({ model: imagen, prompt: "a watercolor lighthouse at dawn", aspectRatio: "3:4" });
|
|
1640
1645
|
```
|
|
1641
1646
|
|
|
1642
|
-
Imagen
|
|
1647
|
+
The **id picks the transport**: a `gemini-` id goes to `generateContent` (token `usage` is passed through as Google reports it — price with `{ input, output }`), anything else to `generateImages` (Imagen — always zero usage, price with `{ perImage }`). Both surface images in the same `GeneratedImage` shape (base64 bytes, no hosted URL). When Google filters the request, `ai.image` surfaces a typed `ContentFilterError` on `result.error`; a Gemini response that answered with text instead of an image surfaces a `ProviderError` quoting that text.
|
|
1648
|
+
|
|
1649
|
+
⚠ **No test calls the live API**, so the Gemini path rests on two tiers of evidence. Measured here: a `gemini-*` id reached `generateContent` and returned a quota error (429) where `generateImages` returned 404 — the endpoint accepts the id. Reported by the maintainer: with billing enabled, an image comes back end-to-end. Still unknown is whether these models report token usage — no `usageMetadata` from a successful image call has been seen. Google has also **deprecated `generateImages`** ("will be removed in the next major release (not before Jan. 1 2027)"), so the Imagen path is on a clock.
|
|
1650
|
+
|
|
1651
|
+
Like every adapter, Google does **not** guard the model id — the id selects a route, it is never refused locally, so an id Google does not serve fails as a typed provider error on `result.error`, not with a local throw at construction.
|
|
1643
1652
|
|
|
1644
1653
|
## Cost-truth — one rollup, two metering models
|
|
1645
1654
|
|
|
@@ -1713,7 +1722,7 @@ if (error) {
|
|
|
1713
1722
|
}
|
|
1714
1723
|
```
|
|
1715
1724
|
|
|
1716
|
-
`SpeechModelContract` mirrors `EmbedderContract` / `ImageModelContract` — a peer primitive produced by the adapter's optional `speech?()` factory. An adapter without a TTS API simply doesn't define `speech()`, so calling it is a **compile-time** error, not a silent runtime failure.
|
|
1725
|
+
`SpeechModelContract` mirrors `EmbedderContract` / `ImageModelContract` — a peer primitive produced by the adapter's optional `speech?()` factory. An adapter without a TTS API simply doesn't define `speech()`, so calling it is a **compile-time** error, not a silent runtime failure. The model id itself is **not validated locally** — a non-TTS id (`openai.speech({ name: "gpt-4o" })`) constructs fine and is forwarded to the provider as given, so it fails as a typed provider error on `result.error`, never as a local throw at construction.
|
|
1717
1726
|
|
|
1718
1727
|
## The result envelope
|
|
1719
1728
|
|
|
@@ -5150,7 +5159,7 @@ if (error) console.warn(error.code); // typed AIError
|
|
|
5150
5159
|
else console.log(data.text); // the transcript
|
|
5151
5160
|
```
|
|
5152
5161
|
|
|
5153
|
-
`TranscriptionModelContract` mirrors `SpeechModelContract` — a peer primitive produced by the adapter's optional `transcribe?()` factory.
|
|
5162
|
+
`TranscriptionModelContract` mirrors `SpeechModelContract` — a peer primitive produced by the adapter's optional `transcribe?()` factory. The model id is **not validated locally** — a non-STT id (`openai.transcribe({ name: "gpt-4o" })`) constructs fine and is forwarded to the provider as given, so it fails as a typed provider error on `result.error`, never as a local throw at construction.
|
|
5154
5163
|
|
|
5155
5164
|
## The `AudioInput` shape + the two builders
|
|
5156
5165
|
|
package/llms.txt
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
- [embed-text](@warlock.js/ai/embed-text/SKILL.md): Text-to-vector via sdk.embedder({...}) — embed(string) for single, embedMany(string[]) for batch. Peer primitive on the SDK adapter, not wired into agents. Compose into RAG tools, workflow run steps, or ai.middleware.semanticCache. Triggers: `sdk.embedder`, `EmbedderContract`, `embedder.embed`, `embedder.embedMany`, `EmbeddingResult`, `EmbeddingBatchResult`, `dimensions`; 'embed text', 'build RAG tool', 'populate vector store', 'embedding batch'; typical import `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: cache similarity — `@warlock.js/cache/use-cache-similarity/SKILL.md`; pgvector queries — `@warlock.js/cascade/search-by-vector/SKILL.md`; competing libs `langchain` embeddings, raw `openai.embeddings.create`.
|
|
18
18
|
- [escalate-block-to-human](@warlock.js/ai/escalate-block-to-human/SKILL.md): Route a hard guardrail block to a human-review surface with @warlock.js/ai-guard — the `escalation.onBlock` seam and an `escalate: true` verdict. Triggers: `escalation`, `onBlock`, `GuardrailEscalation`, `GuardrailBlockEvent`, `escalate: true`, `{ type: "block", escalate: true }`, 'escalate a block to a human', 'human review queue for guardrail', 'page an operator on a guardrail block', 'human-in-the-loop guardrail', 'compose a block with a review surface', 'custom detector that escalates'; typical import `import "@warlock.js/ai-guard"` then `ai.guardrail({ escalation: { onBlock } })`. Skip: composing the guard / phases / verdict model — `@warlock.js/ai-guard/guard-input-output/SKILL.md`; PII/moderation detectors — `@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md`; durable suspend/resume human-step machinery (deferred) — not in this package.
|
|
19
19
|
- [eval-datasets-and-ci](@warlock.js/ai/eval-datasets-and-ci/SKILL.md): Datasets + regression-gated eval CI with ai.dataset({...}) feeding agent.eval({cases,baseline,tolerance}). Covers the immutable filterable/shardable dataset (cases / fromFile JSONL), DatasetEntry tags, EvalReport.regression (regressed/added/removed/passed) against a baseline, and the ai.eval reporters toJUnit / toJSON / fromJSON for CI artifacts + committed baselines. Triggers: `ai.dataset`, `DatasetContract`, `DatasetEntry`, `DatasetOptions`, `dataset.filter`, `dataset.shard`, `fromFile`, `agent.eval`, `EvalOptions`, `EvalReport`, `EvalCaseResult`, `EvalRegression`, `baseline`, `tolerance`, `ai.eval.toJUnit`, `ai.eval.toJSON`, `ai.eval.fromJSON`, `diff`, JSONL; 'eval dataset from a JSONL file', 'shard an eval suite across CI jobs', 'fail CI on an eval regression', 'emit a JUnit report', 'snapshot an eval baseline'; typical import `import { ai } from "@warlock.js/ai"`. Skip: the scorers + LLM-as-judge + Vitest matchers themselves — `@warlock.js/ai/ai-dx-helpers/SKILL.md` (registerAiMatchers / ai.eval.exact|contains|predicate|judge); record/replay of model calls for deterministic tests — `@warlock.js/ai/record-replay-llm/SKILL.md`; competing libs `promptfoo`, `braintrust`.
|
|
20
|
-
- [generate-images](@warlock.js/ai/generate-images/SKILL.md): Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter's image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google imagen-* (per-image). Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; 'generate an image', 'text to image', 'gpt-image', 'dall-e', 'imagen', 'product thumbnail', 'image output'; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.
|
|
20
|
+
- [generate-images](@warlock.js/ai/generate-images/SKILL.md): Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter's image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google gemini-* (generateContent + responseModalities IMAGE, usage passed through) / imagen-* and every other id (per-image, generateImages — deprecated by Google); the id picks the transport and is never validated locally. Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; 'generate an image', 'text to image', 'gpt-image', 'dall-e', 'imagen', 'product thumbnail', 'image output'; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.
|
|
21
21
|
- [generate-speech](@warlock.js/ai/generate-speech/SKILL.md): Text-to-speech via ai.speech({ model: sdk.speech({ name }), text }) — the audio-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter's speech() factory: OpenAI tts-1 / tts-1-hd (per-character) or gpt-4o-mini-tts (per-token). Synthesized audio is a discriminated GeneratedAudio = { type: "base64"; base64; mediaType }. Options: voice / format / speed / instructions / signal. Triggers: `ai.speech`, `sdk.speech`, `openai.speech`, `SpeechModelContract`, `GeneratedAudio`, `SpeechModelPricing`, `SpeechOptions`, `MockSpeechModel`; 'text to speech', 'TTS', 'synthesize voice', 'read this aloud', 'tts-1', 'gpt-4o-mini-tts', 'voice narration', 'audio output', 'speak this text'; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: speech-to-text / transcribing a voice note — [[transcribe-audio]]; image OUTPUT — [[generate-images]]; competing libs raw `openai.audio.speech.create`, `elevenlabs` SDK.
|
|
22
22
|
- [guard-input-output](@warlock.js/ai/guard-input-output/SKILL.md): Build the composed guardrail middleware with @warlock.js/ai-guard and wire it into an agent — `ai.guardrail({ input, output, tool, toolNames, escalation })`. Triggers: `ai.guardrail`, `guard`, `GuardOptions`, `GuardrailVerdict`, `GuardrailDetector`, `GuardrailPhase`, `GuardrailMatch`, `GuardrailViolationError`, `ai.guardrail.topic`, `ai.guardrail.injection`, `topicFilter`, `injectionDetector`, `toolNames`, `forTool`; 'add a guardrail to my agent', 'block prompt injection', 'filter banned topics', 'guard agent input and output', 'stop the model leaking data into a tool call', 'scope a detector to one tool'; typical import `import "@warlock.js/ai-guard"` (registers `ai.guardrail`) or `import { guard } from "@warlock.js/ai-guard"`. Skip: PII detection/redaction specifically — `@warlock.js/ai-guard/detect-and-redact-pii/SKILL.md`; routing a block to a human — `@warlock.js/ai-guard/escalate-block-to-human/SKILL.md`; the core middleware pipeline / hook contract — `@warlock.js/ai/run-ai-agent/SKILL.md`.
|
|
23
23
|
- [handle-ai-errors](@warlock.js/ai/handle-ai-errors/SKILL.md): Typed AIError hierarchy with stable code strings + coarse category for retry-policy dispatch. execute() never throws — errors surface via result.error (the sole exception: OrchestratorConfigError throws at construction). Triggers: `AIError`, `ProviderRateLimitError`, `ProviderAuthError`, `ContextLengthExceededError`, `ContentFilterError`, `SchemaValidationError`, `ToolExecutionError`, `WorkflowDriftError`, `SupervisorDriftError`, `SupervisorFailedError`, `SupervisorRoutingError`, `OrchestratorFailedError`, `OrchestratorDriftError`, `OrchestratorConfigError`, `OrchestratorCancelledError`, `PlannerFailedError`, `PlannerPlanInvalidError`, `PlannerCancelledError`, `BudgetExceededError`, `GuardrailViolationError`, `error.code`, `error.category`; 'handle ai error', 'retry on rate limit', 'branch on error code', 'ORCHESTRATOR_DRIFT', 'PLANNER_PLAN_INVALID', 'build fallback ladder'; typical import `import { AIError } from "@warlock.js/ai"`. Skip: log surfacing — `@warlock.js/ai/log-ai-calls/SKILL.md`; native `try / catch` on raw `openai`.
|
package/package.json
CHANGED
|
@@ -15,16 +15,36 @@
|
|
|
15
15
|
"@standard-schema/spec": "^1.0.0"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@warlock.js/ai-openai": "4.
|
|
19
|
-
"@warlock.js/cache": "4.
|
|
20
|
-
"@warlock.js/logger": "4.
|
|
18
|
+
"@warlock.js/ai-openai": "4.15.0",
|
|
19
|
+
"@warlock.js/cache": "4.15.0",
|
|
20
|
+
"@warlock.js/logger": "4.15.0",
|
|
21
21
|
"langfuse": "*",
|
|
22
22
|
"openai": "*",
|
|
23
23
|
"pdf-parse": "*",
|
|
24
24
|
"pg": "*",
|
|
25
25
|
"redis": "*"
|
|
26
26
|
},
|
|
27
|
-
"
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@warlock.js/ai-openai": {
|
|
29
|
+
"optional": true
|
|
30
|
+
},
|
|
31
|
+
"langfuse": {
|
|
32
|
+
"optional": true
|
|
33
|
+
},
|
|
34
|
+
"openai": {
|
|
35
|
+
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"pdf-parse": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"pg": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"redis": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"version": "4.15.0",
|
|
28
48
|
"main": "./cjs/index.cjs",
|
|
29
49
|
"module": "./esm/index.mjs",
|
|
30
50
|
"types": "./esm/index.d.mts",
|
package/skills/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Datasets + regression-gated eval CI with ai.dataset({...}) feeding agent.eval({c
|
|
|
38
38
|
|
|
39
39
|
### [`generate-images/`](./generate-images/SKILL.md)
|
|
40
40
|
|
|
41
|
-
Text-to-image with ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws {data, error, usage, report} envelope with cost-truth + panoptic observation. Models come from an adapter's image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google imagen-* (per-image). Result images are a discriminated GeneratedImage = {type:"base64"} | {type:"url"}. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`, `perImage`; 'generate an image', 'text to image', 'gpt-image', 'dall-e', 'imagen', 'product thumbnail', 'image output'; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.
|
|
41
|
+
Text-to-image with ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws {data, error, usage, report} envelope with cost-truth + panoptic observation. Models come from an adapter's image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google gemini-* (token-metered, routed to generateContent with responseModalities IMAGE) / imagen-* and every other id (per-image, routed to the older generateImages) — the id picks the transport, and no model id is validated locally. Result images are a discriminated GeneratedImage = {type:"base64"} | {type:"url"}. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`, `perImage`; 'generate an image', 'text to image', 'gpt-image', 'dall-e', 'imagen', 'gemini image', 'product thumbnail', 'image output'; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.
|
|
42
42
|
|
|
43
43
|
### [`handle-ai-errors/`](./handle-ai-errors/SKILL.md)
|
|
44
44
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generate-images
|
|
3
|
-
description: 'Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter''s image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google imagen-* (per-image). Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; ''generate an image'', ''text to image'', ''gpt-image'', ''dall-e'', ''imagen'', ''product thumbnail'', ''image output''; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.'
|
|
3
|
+
description: 'Text-to-image via ai.image({ model: sdk.image({ name }), prompt }) — the image-OUTPUT verb (Theme I), returning the uniform never-throws { data, error, usage, report } envelope with cost-truth + panoptic observation. Models come from an adapter''s image() factory: OpenAI gpt-image-* (token-metered) / dall-e-* (per-image), Google gemini-* (generateContent + responseModalities IMAGE, usage passed through) / imagen-* and every other id (per-image, generateImages — deprecated by Google); the id picks the transport and is never validated locally. Result images are a discriminated GeneratedImage = { type: "base64" } | { type: "url" }. Triggers: `ai.image`, `sdk.image`, `openai.image`, `google.image`, `ImageModelContract`, `GeneratedImage`, `ImageModelPricing`; ''generate an image'', ''text to image'', ''gpt-image'', ''dall-e'', ''imagen'', ''product thumbnail'', ''image output''; typical import `import { ai } from "@warlock.js/ai"` + `import { OpenAISDK } from "@warlock.js/ai-openai"`. Skip: image INPUT / vision attachments to a chat agent — `@warlock.js/ai/run-ai-agent/SKILL.md`; embeddings — `@warlock.js/ai/embed-text/SKILL.md`; competing libs raw `openai.images.generate`, `langchain` image tools.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Generate images — the image-output verb (`ai.image`)
|
|
@@ -81,20 +81,29 @@ const gpt = openai.image({ name: "gpt-image-1", pricing: { input: 5, output: 40
|
|
|
81
81
|
const dalle = openai.image({ name: "dall-e-3", pricing: { perImage: 0.04 } });
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
The model id is **not validated locally**. `openai.image({ name })` forwards the id to `client.images.generate` exactly as given, so a non-image id (`openai.image({ name: "gpt-4o" })`) constructs fine and fails at OpenAI — as a typed provider error on `result.error`, never as a local throw at construction.
|
|
85
85
|
|
|
86
|
-
## Google — Imagen (per-image)
|
|
86
|
+
## Google — Imagen (per-image) and Gemini (per-token)
|
|
87
87
|
|
|
88
88
|
```ts
|
|
89
89
|
import { GoogleSDK } from "@warlock.js/ai-google";
|
|
90
90
|
|
|
91
91
|
const google = new GoogleSDK({ apiKey: process.env.GEMINI_API_KEY! });
|
|
92
|
+
|
|
93
|
+
// Imagen — per-image-metered, via ai.models.generateImages:
|
|
92
94
|
const imagen = google.image({ name: "imagen-4.0-generate-001", pricing: { perImage: 0.04 } });
|
|
93
95
|
|
|
96
|
+
// Gemini image model — token-metered, via ai.models.generateContent:
|
|
97
|
+
const gemini = google.image({ name: "gemini-3.1-flash-lite-image", pricing: { input: 0.3, output: 30 } });
|
|
98
|
+
|
|
94
99
|
const { data } = await ai.image({ model: imagen, prompt: "a watercolor lighthouse at dawn", aspectRatio: "3:4" });
|
|
95
100
|
```
|
|
96
101
|
|
|
97
|
-
Imagen
|
|
102
|
+
The **id picks the transport**: a `gemini-` id goes to `generateContent` (token `usage` is passed through as Google reports it — price with `{ input, output }`), anything else to `generateImages` (Imagen — always zero usage, price with `{ perImage }`). Both surface images in the same `GeneratedImage` shape (base64 bytes, no hosted URL). When Google filters the request, `ai.image` surfaces a typed `ContentFilterError` on `result.error`; a Gemini response that answered with text instead of an image surfaces a `ProviderError` quoting that text.
|
|
103
|
+
|
|
104
|
+
⚠ **No test calls the live API**, so the Gemini path rests on two tiers of evidence. Measured here: a `gemini-*` id reached `generateContent` and returned a quota error (429) where `generateImages` returned 404 — the endpoint accepts the id. Reported by the maintainer: with billing enabled, an image comes back end-to-end. Still unknown is whether these models report token usage — no `usageMetadata` from a successful image call has been seen. Google has also **deprecated `generateImages`** ("will be removed in the next major release (not before Jan. 1 2027)"), so the Imagen path is on a clock.
|
|
105
|
+
|
|
106
|
+
Like every adapter, Google does **not** guard the model id — the id selects a route, it is never refused locally, so an id Google does not serve fails as a typed provider error on `result.error`, not with a local throw at construction.
|
|
98
107
|
|
|
99
108
|
## Cost-truth — one rollup, two metering models
|
|
100
109
|
|
|
@@ -26,7 +26,7 @@ if (error) {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`SpeechModelContract` mirrors `EmbedderContract` / `ImageModelContract` — a peer primitive produced by the adapter's optional `speech?()` factory. An adapter without a TTS API simply doesn't define `speech()`, so calling it is a **compile-time** error, not a silent runtime failure.
|
|
29
|
+
`SpeechModelContract` mirrors `EmbedderContract` / `ImageModelContract` — a peer primitive produced by the adapter's optional `speech?()` factory. An adapter without a TTS API simply doesn't define `speech()`, so calling it is a **compile-time** error, not a silent runtime failure. The model id itself is **not validated locally** — a non-TTS id (`openai.speech({ name: "gpt-4o" })`) constructs fine and is forwarded to the provider as given, so it fails as a typed provider error on `result.error`, never as a local throw at construction.
|
|
30
30
|
|
|
31
31
|
## The result envelope
|
|
32
32
|
|
|
@@ -33,7 +33,7 @@ if (error) console.warn(error.code); // typed AIError
|
|
|
33
33
|
else console.log(data.text); // the transcript
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
`TranscriptionModelContract` mirrors `SpeechModelContract` — a peer primitive produced by the adapter's optional `transcribe?()` factory.
|
|
36
|
+
`TranscriptionModelContract` mirrors `SpeechModelContract` — a peer primitive produced by the adapter's optional `transcribe?()` factory. The model id is **not validated locally** — a non-STT id (`openai.transcribe({ name: "gpt-4o" })`) constructs fine and is forwarded to the provider as given, so it fails as a typed provider error on `result.error`, never as a local throw at construction.
|
|
37
37
|
|
|
38
38
|
## The `AudioInput` shape + the two builders
|
|
39
39
|
|