@prismer/runtime 2.0.8 → 2.2.55
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 +3430 -0
- package/README.md +34 -12
- package/apc/skills/FIELD-DICTIONARY.md +111 -0
- package/apc/skills/bug-reproduce/SKILL.md +150 -0
- package/apc/skills/bug-reproduce/skill.json +96 -0
- package/apc/skills/code-review/SKILL.md +198 -0
- package/apc/skills/code-review/skill.json +124 -0
- package/apc/skills/design-review/SKILL.md +122 -0
- package/apc/skills/design-review/skill.json +88 -0
- package/apc/skills/doc-sync/SKILL.md +168 -0
- package/apc/skills/doc-sync/skill.json +81 -0
- package/apc/skills/env-doctor/SKILL.md +194 -0
- package/apc/skills/env-doctor/skill.json +209 -0
- package/apc/skills/git-ops/SKILL.md +189 -0
- package/apc/skills/git-ops/skill.json +94 -0
- package/apc/skills/impact-trace/SKILL.md +168 -0
- package/apc/skills/impact-trace/skill.json +104 -0
- package/apc/skills/observability/SKILL.md +195 -0
- package/apc/skills/observability/skill.json +116 -0
- package/apc/skills/release-db-config-sync/SKILL.md +186 -0
- package/apc/skills/release-db-config-sync/skill.json +109 -0
- package/apc/skills/release-ota-promote/SKILL.md +195 -0
- package/apc/skills/release-ota-promote/skill.json +176 -0
- package/apc/skills/release-preflight/SKILL.md +174 -0
- package/apc/skills/release-preflight/skill.json +175 -0
- package/apc/skills/release-rollback/SKILL.md +214 -0
- package/apc/skills/release-rollback/skill.json +230 -0
- package/apc/skills/release-tag/SKILL.md +194 -0
- package/apc/skills/release-tag/skill.json +94 -0
- package/apc/skills/releasing-prod/SKILL.md +49 -0
- package/apc/skills/releasing-test/SKILL.md +135 -0
- package/apc/skills/sdk-release/SKILL.md +200 -0
- package/apc/skills/spec-intake/SKILL.md +169 -0
- package/apc/skills/spec-intake/skill.json +93 -0
- package/apc/skills/test-result-feedback/SKILL.md +239 -0
- package/apc/skills/test-result-feedback/skill.json +193 -0
- package/apc/skills/test-runner/SKILL.md +169 -0
- package/apc/skills/test-runner/skill.json +103 -0
- package/apc/skills/ui-align/SKILL.md +209 -0
- package/apc/skills/ui-align/skill.json +114 -0
- package/apc/skills/ui-canvas/SKILL.md +148 -0
- package/apc/skills/ui-canvas/skill.json +127 -0
- package/built-in-skills/agent-coordination/SKILL.md +59 -37
- package/built-in-skills/agent-meta/SKILL.md +1 -0
- package/built-in-skills/assets/SKILL.md +8 -6
- package/built-in-skills/browser-use/SKILL.md +93 -0
- package/built-in-skills/canvas-design/SKILL.md +1 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
- package/built-in-skills/claude-api/SKILL.md +1 -0
- package/built-in-skills/codebase-design/DEEPENING.md +37 -0
- package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/built-in-skills/codebase-design/LICENSE +21 -0
- package/built-in-skills/codebase-design/SKILL.md +116 -0
- package/built-in-skills/conversation-compaction/SKILL.md +114 -0
- package/built-in-skills/council-creator/SKILL.md +426 -0
- package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
- package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
- package/built-in-skills/document-generation/SKILL.md +105 -0
- package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/built-in-skills/domain-modeling/LICENSE +21 -0
- package/built-in-skills/domain-modeling/SKILL.md +76 -0
- package/built-in-skills/frontend-design/SKILL.md +1 -0
- package/built-in-skills/human-approval/SKILL.md +17 -2
- package/built-in-skills/image-generate/SKILL.md +103 -302
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
- package/built-in-skills/ingest/SKILL.md +13 -45
- package/built-in-skills/internal-comms/SKILL.md +1 -0
- package/built-in-skills/liteparse/SKILL.md +130 -110
- package/built-in-skills/mcp-builder/SKILL.md +1 -0
- package/built-in-skills/memory/SKILL.md +420 -55
- package/built-in-skills/memory-dream/SKILL.md +339 -0
- package/built-in-skills/office-artifacts/SKILL.md +17 -4
- package/built-in-skills/okr/SKILL.md +154 -0
- package/built-in-skills/persona/SKILL.md +81 -0
- package/built-in-skills/persona-generator/SKILL.md +296 -0
- package/built-in-skills/pkf-svg/SKILL.md +253 -0
- package/built-in-skills/pkf-writing/SKILL.md +236 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
- package/built-in-skills/proactivity/SKILL.md +84 -0
- package/built-in-skills/remotion/SKILL.md +431 -0
- package/built-in-skills/role-builder/SKILL.md +203 -0
- package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
- package/built-in-skills/skill-authoring/SKILL.md +110 -100
- package/built-in-skills/skill-authoring/skill.json +3 -3
- package/built-in-skills/skill-builder/SKILL.md +171 -0
- package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
- package/built-in-skills/skill-creator/SKILL.md +165 -423
- package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
- package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
- package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
- package/built-in-skills/tasks/SKILL.md +38 -23
- package/built-in-skills/tdd/LICENSE +21 -0
- package/built-in-skills/tdd/SKILL.md +110 -0
- package/built-in-skills/tdd/mocking.md +59 -0
- package/built-in-skills/tdd/refactoring.md +10 -0
- package/built-in-skills/tdd/tests.md +61 -0
- package/built-in-skills/team/SKILL.md +2 -1
- package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
- package/built-in-skills/webapp-testing/SKILL.md +1 -0
- package/built-in-skills/wechat-pay/SKILL.md +59 -0
- package/dist/cli.cjs +71872 -19960
- package/dist/cli.js +71803 -19846
- package/dist/index.cjs +72010 -19966
- package/dist/index.d.cts +4258 -712
- package/dist/index.d.ts +4258 -712
- package/dist/index.js +72156 -20118
- package/package.json +37 -6
- package/plugins/memory/prismer/__init__.py +1211 -0
- package/plugins/memory/prismer/plugin.yaml +8 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
- package/plugins/tools/prismer-recall/__init__.py +282 -0
- package/plugins/tools/prismer-recall/plugin.yaml +15 -0
- package/built-in-skills/memory-curation/SKILL.md +0 -135
|
@@ -1,327 +1,128 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: image-generate
|
|
3
|
-
|
|
3
|
+
scope: persistence
|
|
4
|
+
description: Generate one new image from a text prompt and deliver it once as the current Prismer reply attachment. Use for draw, generate-image, poster, diagram, illustration, or other text-to-image requests. Do not use for editing or merely describing an existing image.
|
|
4
5
|
applies_to: [hermes, claude-code, openclaw, codex]
|
|
5
6
|
requires:
|
|
6
7
|
- assets
|
|
7
8
|
phaseModel:
|
|
8
9
|
defaultPhase: tool_use
|
|
9
|
-
version:
|
|
10
|
+
version: 2
|
|
11
|
+
config:
|
|
12
|
+
- key: IMAGE_GEN_MODEL
|
|
13
|
+
type: string
|
|
14
|
+
required: false
|
|
15
|
+
default: null
|
|
16
|
+
bindable: [global, role, agent]
|
|
17
|
+
description: Preferred image-generation model id. The helper discovers the deployment model list and falls back by priority.
|
|
18
|
+
prompt:
|
|
19
|
+
zh: "生成图片时希望默认用哪个模型?"
|
|
20
|
+
en: "Which image model should be used by default?"
|
|
10
21
|
---
|
|
11
22
|
|
|
12
23
|
# Image Generate
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
Generate and deliver the requested image through the bundled helper. The helper
|
|
26
|
+
owns model discovery, fallback, byte decoding, hashing, file creation, and the
|
|
27
|
+
single `cloud deliver` call. Do not rebuild those steps in Python, curl, or a
|
|
28
|
+
temporary script.
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
`POST /api/v1/images/generations` (OpenAI-compatible — see §"Hand-off" if
|
|
20
|
-
the endpoint is not yet wired in your deployment).
|
|
21
|
-
2. **Asset store** — `POST /api/im/assets` (multipart) on the cloud, returning
|
|
22
|
-
a stable `assetId` + `contentHash`. Generated bytes flow through the
|
|
23
|
-
content-addressed pipeline like any other asset — same de-dup, same audit
|
|
24
|
-
trail, same URI scheme (`prismer://assets/<assetId>`).
|
|
30
|
+
## Run
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
Raw bytes / `data:` URIs / pre-signed URLs MUST NOT be embedded in prose; doing
|
|
28
|
-
so defeats caching and makes follow-up retrieval impossible (same rule as the
|
|
29
|
-
`assets` skill).
|
|
30
|
-
|
|
31
|
-
## When to use
|
|
32
|
-
|
|
33
|
-
- The user says "draw", "generate an image of …", "make me a picture / poster /
|
|
34
|
-
diagram / illustration".
|
|
35
|
-
- A task description includes a `produce_image:` field or a `kind: image`
|
|
36
|
-
artifact expectation.
|
|
37
|
-
- You need to **fabricate** a visual that does not exist in any source — if
|
|
38
|
-
the visual already exists, use `assets` to read it, not this skill.
|
|
39
|
-
- A downstream skill (`canvas-design`, `slack-gif-creator`,
|
|
40
|
-
`web-artifacts-builder`) requires a generated source image as input.
|
|
41
|
-
|
|
42
|
-
## Not when to use
|
|
43
|
-
|
|
44
|
-
- Editing / variation / inpainting an existing image — that's a separate
|
|
45
|
-
upcoming skill (`image-edit`). Don't fake it by reading + regenerating.
|
|
46
|
-
- Describing what's in an image — use a vision-capable adapter, no generation
|
|
47
|
-
needed.
|
|
48
|
-
- Pure ASCII / SVG / Mermaid graphics that the LLM can emit as text — those
|
|
49
|
-
belong in the chat body, not in an asset.
|
|
50
|
-
- Privacy-sensitive renderings (faces, identifiable individuals) without
|
|
51
|
-
explicit user confirmation. The skill does not gate this; the agent must.
|
|
52
|
-
|
|
53
|
-
## API Reference
|
|
54
|
-
|
|
55
|
-
There is **no `cloud image generate` subcommand** in the runtime CLI today
|
|
56
|
-
(release 201 audit, `sdk/prismer-cloud/runtime/src/cli/commands/`). Call the
|
|
57
|
-
cloud HTTP endpoint directly from a small Python / Node script in the skill
|
|
58
|
-
runtime, then hand the bytes to `cloud asset upload` for the content-addressed
|
|
59
|
-
write. Adding a dedicated CLI verb is tracked as a future release; until then,
|
|
60
|
-
do **not** invent the command — it will exit with "unknown command".
|
|
61
|
-
|
|
62
|
-
HTTP shape:
|
|
63
|
-
|
|
64
|
-
```http
|
|
65
|
-
POST /api/v1/images/generations
|
|
66
|
-
Authorization: Bearer <user JWT or sk-prismer-* key>
|
|
67
|
-
Content-Type: application/json
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
"prompt": "<text prompt, 1..4000 chars>",
|
|
71
|
-
"model": "gpt-image-1", // or "dall-e-3", deployment-dependent
|
|
72
|
-
"size": "1024x1024", // 256x256 | 512x512 | 1024x1024 | 1792x1024 | 1024x1792
|
|
73
|
-
"n": 1, // skill always uses 1 (return single ContentBlock)
|
|
74
|
-
"response_format": "b64_json" // skill requires bytes — never "url"
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
Successful response (OpenAI shape):
|
|
78
|
-
{
|
|
79
|
-
"created": 1716345600,
|
|
80
|
-
"data": [{ "b64_json": "<base64 PNG bytes>" }]
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
After receiving bytes the skill **MUST** upload to the cloud asset store
|
|
85
|
-
(`POST /api/im/assets`, multipart) and use the returned `assetId` in the
|
|
86
|
-
ContentBlock. Bytes never leak into chat.
|
|
87
|
-
|
|
88
|
-
## Workflow
|
|
89
|
-
|
|
90
|
-
1. **Validate inputs.** Prompt 1..4000 chars; size in the allow-list above;
|
|
91
|
-
workspaceId resolved (defaulting to the active workspace if none supplied).
|
|
92
|
-
2. **Generate.** POST to `/api/v1/images/generations` with
|
|
93
|
-
`response_format: 'b64_json'`. Capture `b64_json` (single image).
|
|
94
|
-
3. **Decode + hash.** Base64-decode to bytes, compute SHA-256 client-side, and
|
|
95
|
-
compare against the upload response's `contentHash` field (server validates
|
|
96
|
-
too — use `x-content-sha256` header).
|
|
97
|
-
4. **Upload as asset.** Multipart POST to `/api/im/assets`:
|
|
98
|
-
- `file` — Blob with `image/png` MIME and filename
|
|
99
|
-
`generated-${shortHash}.png`
|
|
100
|
-
- `workspaceId`, `kind=image`, `description=<prompt[0..500]>`
|
|
101
|
-
- `sourceTaskId` / `sourceAgentImUserId` (if available from runtime context)
|
|
102
|
-
- `folderPath=/generated/images/${YYYY-MM}` (auto-organized, optional)
|
|
103
|
-
5. **Emit ContentBlock.** Return — and only return — a ContentBlock pointing
|
|
104
|
-
at the new asset. Shape exactly as v2.0 §4.6 (Anthropic-shape, not OpenAI):
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"kind": "image",
|
|
109
|
-
"assetId": "<returned assetId>",
|
|
110
|
-
"mediaType": "image/png",
|
|
111
|
-
"alt": "<prompt truncated to 100 chars>"
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Operating Rules
|
|
116
|
-
|
|
117
|
-
- **Always `response_format: b64_json`.** Never `url` — the OpenAI URL is
|
|
118
|
-
short-lived, doesn't survive the content-address round-trip, and tempts you
|
|
119
|
-
to leak it into chat (which defeats the asset model).
|
|
120
|
-
- **One image per call.** `n=1` only. If the user wants variants, call the
|
|
121
|
-
skill multiple times — each variant gets its own assetId so the user can
|
|
122
|
-
pick + delete cleanly.
|
|
123
|
-
- **Hash check is non-negotiable.** Server enforces `x-content-sha256`; if the
|
|
124
|
-
hashes disagree, abort and surface the mismatch — the bytes were corrupted
|
|
125
|
-
in flight.
|
|
126
|
-
- **Never inline base64 / `data:<mime>;base64,...` in the reply body.** The
|
|
127
|
-
whole point of the skill is to avoid that anti-pattern. If you find yourself
|
|
128
|
-
about to do so, stop and check that the asset upload actually succeeded.
|
|
129
|
-
- **Default size = 1024x1024** unless the user explicitly asks for portrait
|
|
130
|
-
(1024x1792) or landscape (1792x1024). 256/512 only when budget is tight.
|
|
131
|
-
- **Cost-aware:** image gen is far more expensive than a chat completion.
|
|
132
|
-
Tell the user the model + size you picked before spending more than 1
|
|
133
|
-
credit's worth, and surface the actual cost from the response.
|
|
134
|
-
|
|
135
|
-
## ContentBlock output (v2.0 §4.6 / Gap E-⑤)
|
|
136
|
-
|
|
137
|
-
This skill produces a **single image ContentBlock** per successful generation.
|
|
138
|
-
It MUST NOT also dump the base64 / pre-signed URL into the reply — that
|
|
139
|
-
violates the §4.6 rule (asset-by-reference, not asset-by-value) and breaks the
|
|
140
|
-
chat renderer's preview pipeline.
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{ "kind": "image", "assetId": "<assetId>", "mediaType": "image/png", "alt": "<prompt summary, ≤100 chars>" }
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
The reply envelope from this skill (when invoked via the agent runtime) looks
|
|
147
|
-
like:
|
|
148
|
-
|
|
149
|
-
```json
|
|
150
|
-
{
|
|
151
|
-
"ok": true,
|
|
152
|
-
"result": {
|
|
153
|
-
"assetId": "<assetId>",
|
|
154
|
-
"contentHash": "<sha256 hex>",
|
|
155
|
-
"sizeBytes": 123456,
|
|
156
|
-
"cdnUrl": "<optional, server may include>",
|
|
157
|
-
"model": "gpt-image-1",
|
|
158
|
-
"size": "1024x1024",
|
|
159
|
-
"promptHash": "<sha256 of prompt for de-dup>"
|
|
160
|
-
},
|
|
161
|
-
"contentBlocks": [
|
|
162
|
-
{ "kind": "image", "assetId": "<assetId>", "mediaType": "image/png", "alt": "<prompt[0..100]>" }
|
|
163
|
-
]
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Legacy callers that only know how to parse `result.assetId` keep working
|
|
168
|
-
(field preserved). Multimodal-aware callers prefer `contentBlocks[]` —
|
|
169
|
-
adapters and the chat renderer both check `contentBlocks` first per the §4.6
|
|
170
|
-
prefer-blocks rule.
|
|
171
|
-
|
|
172
|
-
## Failure modes
|
|
173
|
-
|
|
174
|
-
| Status | Where | Cause | What to surface |
|
|
175
|
-
|---|---|---|---|
|
|
176
|
-
| 400 | LLM proxy | prompt too long / disallowed content | Prompt rejected; surface the proxy's error message verbatim. Do NOT retry the same prompt. |
|
|
177
|
-
| 402 | LLM proxy | not enough credits | Tell the user the cost + ask them to top up. Don't burn credits on retries. |
|
|
178
|
-
| 415 | asset upload | server rejected MIME (not in allow-list) | Should not happen — `image/png` is allow-listed. If it does, this is a deployment bug; flag it. |
|
|
179
|
-
| 422 | asset upload | `x-content-sha256` mismatch | Bytes corrupted in flight. Retry once; if it persists, fail the skill and tell the user. |
|
|
180
|
-
| 5xx | either | upstream outage | Retry with exponential backoff up to 2 times, then fail loudly. Do NOT fabricate the assetId. |
|
|
181
|
-
|
|
182
|
-
## Output reporting
|
|
183
|
-
|
|
184
|
-
After successful generation:
|
|
32
|
+
From this skill directory, run:
|
|
185
33
|
|
|
34
|
+
```bash
|
|
35
|
+
node scripts/generate-and-deliver.mjs \
|
|
36
|
+
--prompt '<complete generation prompt>' \
|
|
37
|
+
--size 1024x1024
|
|
186
38
|
```
|
|
187
|
-
[image-generate] generated assetId=<id> model=<model> size=<WxH> sha=<short>
|
|
188
|
-
cost=<credits>c prompt="<first 60 chars>…"
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
Then in chat, return ONLY the ContentBlock (the renderer surfaces the image
|
|
192
|
-
preview). One-line caption may accompany it if useful ("Here's the
|
|
193
|
-
illustration you asked for.").
|
|
194
39
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
40
|
+
Optional flags:
|
|
41
|
+
|
|
42
|
+
- `--model <id>` overrides `IMAGE_GEN_MODEL` for this call.
|
|
43
|
+
- `--output <path>` selects the local PNG/JPEG/WebP filename. Without it, the
|
|
44
|
+
helper writes a content-hashed file under `PRISMER_ARTIFACTS_DIR` (or cwd when
|
|
45
|
+
no dispatch artifacts directory is available).
|
|
46
|
+
- `--size` accepts `256x256`, `512x512`, `1024x1024`, `1792x1024`, or
|
|
47
|
+
`1024x1792`; the selected deployment model must advertise that size.
|
|
48
|
+
|
|
49
|
+
Defaults: square `1024x1024`; portrait `1024x1792` or landscape `1792x1024`
|
|
50
|
+
only when the user asks for that orientation. Generate one image per helper
|
|
51
|
+
invocation.
|
|
52
|
+
|
|
53
|
+
## Delivery contract
|
|
54
|
+
|
|
55
|
+
The helper ends by running `cloud deliver <file> --json` exactly once and
|
|
56
|
+
consumes that machine output internally. Runtime turns the delivered asset into
|
|
57
|
+
the reply's structured attachment and the chat renderer shows the preview.
|
|
58
|
+
|
|
59
|
+
Read the helper's one-line status before replying:
|
|
60
|
+
|
|
61
|
+
- `[image-generate] delivered` means the asset was uploaded for this reply.
|
|
62
|
+
Reply with a short natural-language caption; model and size may be mentioned.
|
|
63
|
+
- `[image-generate] queued` means the bytes are durable locally but the cloud
|
|
64
|
+
upload is pending reconnection. Say it was generated and queued for upload;
|
|
65
|
+
do not claim it is already attached.
|
|
66
|
+
- `[image-generate] uploaded-unattached` means the cloud stored the image under
|
|
67
|
+
the run archive but no active reply dispatch existed. Say it was generated
|
|
68
|
+
and archived; do not claim it is attached.
|
|
69
|
+
- Do not paste the helper's JSON, assetId object, ContentBlock, base64, data URI,
|
|
70
|
+
signed URL, or local path into the message body.
|
|
71
|
+
- Do not run `cloud deliver`, `cloud file send`, `cloud task attach`, an asset
|
|
72
|
+
upload command, or a multipart request again for the same output.
|
|
73
|
+
- Do not manually construct a structured attachment. Runtime owns that wire
|
|
74
|
+
representation.
|
|
75
|
+
|
|
76
|
+
The generated file may also be observed by Runtime's dispatch-final artifact
|
|
77
|
+
scan. That scan and `cloud deliver` share the same run/task scope and
|
|
78
|
+
content-addressed dedup key; agents must not add another upload path.
|
|
79
|
+
|
|
80
|
+
## Prompt handling
|
|
81
|
+
|
|
82
|
+
Use the user's requested subject, composition, style, lighting, camera angle,
|
|
83
|
+
palette, text, and exclusions. Expand a vague request only enough to make those
|
|
84
|
+
visual choices explicit; do not silently change the subject or intent.
|
|
85
|
+
|
|
86
|
+
Do not generate privacy-sensitive depictions of identifiable people without
|
|
87
|
+
the user's explicit request. For editing, variation, or inpainting of an
|
|
88
|
+
existing image, use an image-editing capability instead. For reading an
|
|
89
|
+
existing image, use the asset/vision path.
|
|
90
|
+
|
|
91
|
+
## Helper behavior
|
|
92
|
+
|
|
93
|
+
The bundled script:
|
|
94
|
+
|
|
95
|
+
1. Resolves `PRISMER_CLOUD_BASE` / `PRISMER_BASE_URL` and `PRISMER_API_KEY`,
|
|
96
|
+
falling back to the Prismer runtime config.
|
|
97
|
+
2. Discovers available image models, filters them by the requested size before
|
|
98
|
+
generation, and honors a compatible `--model` or `IMAGE_GEN_MODEL` first.
|
|
99
|
+
3. Retries the next model only for model-not-found, quota/rate-limit, or server
|
|
100
|
+
failures. Prompt rejection and insufficient credits stop immediately.
|
|
101
|
+
4. Accepts either base64 image bytes or a short-lived image URL, validates the
|
|
102
|
+
resulting PNG/JPEG/WebP bytes, and writes one content-hashed file.
|
|
103
|
+
5. Delivers that file once through the daemon-aware CLI path, distinguishing a
|
|
104
|
+
completed upload from a durable offline queue receipt.
|
|
105
|
+
|
|
106
|
+
If it fails, report its status/code/message and stop. Do not fabricate an
|
|
107
|
+
assetId, claim that delivery succeeded, or retry a rejected prompt unchanged.
|
|
215
108
|
|
|
216
109
|
## Examples
|
|
217
110
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```
|
|
221
|
-
User: "Draw an isometric server room with glowing blue racks"
|
|
222
|
-
|
|
223
|
-
Skill flow:
|
|
224
|
-
POST /api/v1/images/generations
|
|
225
|
-
{ prompt: "An isometric...", model: "gpt-image-1",
|
|
226
|
-
size: "1024x1024", n: 1, response_format: "b64_json" }
|
|
227
|
-
← 200 { data: [{ b64_json: "<bytes>" }] }
|
|
228
|
-
|
|
229
|
-
decode + sha256 → "8f4a..."
|
|
230
|
-
|
|
231
|
-
POST /api/im/assets (multipart)
|
|
232
|
-
file=generated-8f4a.png kind=image workspaceId=...
|
|
233
|
-
x-content-sha256: 8f4a...
|
|
234
|
-
← 200 { data: { id: "asset_<...>", contentHash: "8f4a...",
|
|
235
|
-
cdnUrl: "/api/im/assets/asset_<...>" } }
|
|
236
|
-
|
|
237
|
-
Reply envelope:
|
|
238
|
-
{ ok: true,
|
|
239
|
-
result: { assetId: "asset_<...>", contentHash: "8f4a...", ... },
|
|
240
|
-
contentBlocks: [
|
|
241
|
-
{ kind: "image", assetId: "asset_<...>", mediaType: "image/png",
|
|
242
|
-
alt: "An isometric server room with glowing blue racks" }
|
|
243
|
-
] }
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Example 2 — Task-pinned generation for kanban artifact
|
|
111
|
+
Square illustration:
|
|
247
112
|
|
|
113
|
+
```bash
|
|
114
|
+
node scripts/generate-and-deliver.mjs \
|
|
115
|
+
--prompt 'Isometric server room, glowing blue racks, cinematic lighting' \
|
|
116
|
+
--size 1024x1024
|
|
248
117
|
```
|
|
249
|
-
Task input: { produce_image: { prompt: "Logo: minimalist owl, monochrome",
|
|
250
|
-
size: "1024x1024" } }
|
|
251
|
-
|
|
252
|
-
Skill call: POST /api/v1/images/generations with the prompt, then
|
|
253
|
-
`cloud asset upload generated.png --task-id "$PRISMER_TASK_ID"` so the
|
|
254
|
-
kanban task review board surfaces the image inline (chat renderer reads
|
|
255
|
-
contentBlocks from the asset attachment).
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Example 3 — Failure: prompt rejected
|
|
259
|
-
|
|
260
|
-
```
|
|
261
|
-
User: "<disallowed content>"
|
|
262
|
-
LLM proxy: 400 { error: { code: "content_policy_violation", ... } }
|
|
263
|
-
|
|
264
|
-
Skill response:
|
|
265
|
-
{ ok: false,
|
|
266
|
-
error: { code: "content_policy_violation",
|
|
267
|
-
message: "<proxy's verbatim message>" } }
|
|
268
|
-
|
|
269
|
-
Do NOT retry. Do NOT fabricate an assetId.
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Anti-patterns
|
|
273
|
-
|
|
274
|
-
- ❌ Returning the raw base64 in `result.image_b64` for chat to render. The
|
|
275
|
-
chat renderer expects ContentBlock referencing an asset; raw bytes bypass
|
|
276
|
-
caching.
|
|
277
|
-
- ❌ Using `response_format: 'url'` and pasting the OpenAI URL into the
|
|
278
|
-
reply. URL expires; user clicks later → 404.
|
|
279
|
-
- ❌ Skipping the asset upload "to save time" when the generated image is
|
|
280
|
-
tiny. Tiny images still need stable IDs for follow-up retrieval and audit
|
|
281
|
-
trail.
|
|
282
|
-
- ❌ Calling the skill in a loop to "generate variants" — call once per
|
|
283
|
-
variant with explicit prompt deltas. The de-dup hash will catch identical
|
|
284
|
-
prompts.
|
|
285
|
-
- ❌ Setting `n > 1`. The ContentBlock output shape is single-image; multi
|
|
286
|
-
would force you to fabricate which one to attach.
|
|
287
|
-
|
|
288
|
-
## Hand-off — endpoint provisioning
|
|
289
|
-
|
|
290
|
-
**Cloud-side endpoint wired in Wave 6 G1.** `POST /api/v1/images/generations`
|
|
291
|
-
is now provisioned at `src/app/api/images/generations/route.ts` and uses
|
|
292
|
-
the same `proxyToNewAPI` helper that backs `/api/chat/completions` +
|
|
293
|
-
`/api/embeddings`. Image-specific billing lives in
|
|
294
|
-
`src/lib/llm-pricing.ts::calculateImageCredits` (per-image USD pricing,
|
|
295
|
-
no token semantics). Setting `MOCK_LLM_IMAGES=true` returns a fixture PNG
|
|
296
|
-
without hitting NewAPI — used by F6 integration tests.
|
|
297
|
-
|
|
298
|
-
Historical handler template (matches the landed implementation):
|
|
299
118
|
|
|
300
|
-
|
|
301
|
-
// src/app/api/images/generations/route.ts (NEW)
|
|
302
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
303
|
-
import { apiGuard } from '@/lib/api-guard';
|
|
304
|
-
import { checkRateLimit, rateLimitResponse } from '@/lib/rate-limit';
|
|
305
|
-
import { FEATURE_FLAGS } from '@/lib/feature-flags';
|
|
306
|
-
import { proxyToNewAPI } from '@/lib/llm-proxy';
|
|
307
|
-
import { ensureNacosConfig } from '@/lib/nacos-config';
|
|
119
|
+
Portrait poster with an explicit model preference:
|
|
308
120
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
const guard = await apiGuard(request, { tier: 'tracked' });
|
|
316
|
-
if (!guard.ok) return guard.response;
|
|
317
|
-
const rl = checkRateLimit(guard.auth.userId, 'llm');
|
|
318
|
-
if (!rl.allowed) return rateLimitResponse(rl);
|
|
319
|
-
return proxyToNewAPI(request, guard, '/v1/images/generations');
|
|
320
|
-
}
|
|
121
|
+
```bash
|
|
122
|
+
node scripts/generate-and-deliver.mjs \
|
|
123
|
+
--prompt 'Minimalist monochrome owl poster, centered subject, clean negative space' \
|
|
124
|
+
--size 1024x1792 \
|
|
125
|
+
--model "$IMAGE_GEN_MODEL"
|
|
321
126
|
```
|
|
322
127
|
|
|
323
|
-
|
|
324
|
-
`scripts/test-image-generate-skill.ts` which proves the
|
|
325
|
-
generate→upload→ContentBlock chain by stubbing the LLM bytes (a 1x1 PNG) and
|
|
326
|
-
hitting the real `/api/im/assets` upload, so the asset half of the contract
|
|
327
|
-
is fully validated against production code paths.
|
|
128
|
+
Successful chat reply example: `图已生成并附在这条消息中。`
|