@genex-ai/cli-demo 1.38.0-dev.1083 → 1.38.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/dist/{blender-mcp-WSURPZET.js → blender-mcp-QVEGHE5L.js} +2 -2
- package/dist/{blender-serve-EH2MOW3U.js → blender-serve-66OHC4ML.js} +1 -1
- package/dist/{chunk-EABIVAGT.js → chunk-4BBTPRJW.js} +2 -2
- package/dist/{chunk-K4EHXOZK.js → chunk-QI7FIYBY.js} +1 -1
- package/dist/index.js +266 -771
- package/package.json +1 -1
- package/templates/skills/genex-game-director/SKILL.md +1 -1
- package/templates/skills/genex-getting-started/SKILL.md +2 -2
- package/templates/skills/genex-llm-in-games/SKILL.md +72 -209
- package/templates/skills/genex-llm-in-games/references/pricing.md +85 -126
- package/templates/skills/genex-monetization/SKILL.md +11 -2
- package/templates/skills/genex-threejs-embed-auth/SKILL.md +1 -4
- package/templates/skills/genex-threejs-embed-auth/references/shells.md +0 -104
- package/templates/skills/genex-tool-llm/SKILL.md +9 -11
- package/templates/skills/genex-tool-publish/SKILL.md +0 -7
- package/templates/skills/genex-updates/SKILL.md +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/cli-demo",
|
|
3
|
-
"version": "1.38.0
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Set up your project's agent workspace (.claude/.codex/.cursor in the game folder), authorize, create a game project, generate AI assets, and publish (genex CLI).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -158,7 +158,7 @@ vendored code from memory of another engine.
|
|
|
158
158
|
| requested UI/HUD/menu/interface work, a visible UI problem, or an interface you decided this game wants built with generated art | `$genex-threejs-game-ui` |
|
|
159
159
|
| selling anything for Nex (Genex's currency, bought with real money) or for real money with no currency named: a shop, an item catalog, boosts, cosmetics, "make it earn"; a fixed Nex price is a store item. Coins, gold or gems are the game's own earned currency, not this row. Also any request for a loot box, gacha, wager, casino mechanic or donation prompt, which that skill refuses and replaces | `$genex-monetization` |
|
|
160
160
|
| an item for the Genex store — sell a sword, a skin or a pet for Nex with its picture and description, "other games can use it too" — or another creator's shared item added to this game (`npx genex items add <id>`). Build the item first, list it with `npx genex shop add … --json` without asking; the person puts it on sale | `$genex-items` (with `$genex-monetization`) |
|
|
161
|
-
| the game calls a language model AT RUNTIME on the player's
|
|
161
|
+
| the game calls a language model AT RUNTIME on the player's money: NPCs that answer in their own words, dialogue or quests written per save, a judge reading what the player typed — one-time calls, or a standing budget the player approves once. Check the lane with `npx genex llm models` before designing it in | `$genex-llm-in-games` |
|
|
162
162
|
| cinematic menu/title/pause/victory/defeat/lobby/credits video treatment | `$genex-ai-menu` |
|
|
163
163
|
| drawn HUD chrome the game's style wants—one element or a matched set of frames, masks, and icons | `$genex-ai-hud` |
|
|
164
164
|
| the game works but feels flat, floaty, or unresponsive: input response, camera, impacts, cooldowns, difficulty, fail/retry | `$genex-threejs-game-feel` |
|
|
@@ -161,7 +161,7 @@ downloads the game too, binary assets and all:
|
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
163
|
mkdir my-game && cd my-game
|
|
164
|
-
npx @genex-ai/cli-demo@
|
|
164
|
+
npx @genex-ai/cli-demo@latest link <slug> # slug = the name in the play URL
|
|
165
165
|
npm install
|
|
166
166
|
```
|
|
167
167
|
|
|
@@ -225,7 +225,7 @@ Safe to run any time — genex-owned skills are refreshed to the latest version,
|
|
|
225
225
|
and your own files are never touched:
|
|
226
226
|
|
|
227
227
|
```bash
|
|
228
|
-
npx @genex-ai/cli-demo@
|
|
228
|
+
npx @genex-ai/cli-demo@latest init
|
|
229
229
|
```
|
|
230
230
|
|
|
231
231
|
Use `--force` only if you intentionally want your own existing files overwritten
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: genex-llm-in-games
|
|
3
|
-
description: Call a language model from inside a running game — an NPC that answers in its own words, a quest written for this save, a judge that reads what the player typed. The PLAYER pays and approves, on a Genex surface the game cannot forge. Covers the two modes (a popup per call, or one standing budget then many silent calls), benchmarking the
|
|
3
|
+
description: Call a language model from inside a running game — an NPC that answers in its own words, a quest written for this save, a judge that reads what the player typed. The PLAYER pays and approves, on a Genex surface the game cannot forge. Covers the two modes (a popup per call, or one standing budget then many silent calls), benchmarking the price before declaring it, the receiver pattern, and honest handling of every refusal.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Genex LLM in Games
|
|
@@ -8,11 +8,10 @@ description: Call a language model from inside a running game — an NPC that an
|
|
|
8
8
|
A Genex game can call a language model **while the player is playing** and get
|
|
9
9
|
back text or JSON. Nothing else: no images, no code execution, no tools.
|
|
10
10
|
|
|
11
|
-
**The player pays, and the player approves.** Funding is their Genex
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
never talks to a model vendor.
|
|
11
|
+
**The player pays, and the player approves.** Funding is coin from their Genex
|
|
12
|
+
wallet or their own Claude / ChatGPT plan, chosen on a Genex-drawn surface your
|
|
13
|
+
game cannot render, skin or bypass. The game holds no provider key, sees no
|
|
14
|
+
credential, and never talks to a model vendor.
|
|
16
15
|
|
|
17
16
|
Two modes. Picking the wrong one is the most expensive mistake on this lane:
|
|
18
17
|
|
|
@@ -26,23 +25,6 @@ Two modes. Picking the wrong one is the most expensive mistake on this lane:
|
|
|
26
25
|
A popup per NPC turn is not a feature, it is an interruption. More than a call
|
|
27
26
|
or two per session means a grant.
|
|
28
27
|
|
|
29
|
-
**Deciding, not writing? Use the judge.** When the game needs to KNOW something
|
|
30
|
-
— is this NPC lying, which of five moods is the player in, how threatening is
|
|
31
|
-
the scene on a scale — and not to produce words, ask the grant's classifier with
|
|
32
|
-
`judge()` instead of asking `generate()` for a label. It answers typed questions
|
|
33
|
-
(`choice`, `score`, `noul`) with calibrated probabilities in about a third of a
|
|
34
|
-
second, writes no prose and cannot drift out of your options. It is grant-only
|
|
35
|
-
and billed as used: each call is a small fraction of a credit and accrues on the
|
|
36
|
-
budget, so a check every turn is affordable where a generate every turn is not.
|
|
37
|
-
`generate()` for words, `judge()` for decisions; a feature often wants both —
|
|
38
|
-
the judge picks the branch, generate writes the line.
|
|
39
|
-
|
|
40
|
-
**Words the player watches appear? Stream them.** Dialogue, narration, an NPC's
|
|
41
|
-
reply in a speech bubble: under a grant, `generateStream()` is the same call as
|
|
42
|
-
`generate({ grantId })`, but the text arrives while the model writes it instead
|
|
43
|
-
of all at once after it. Keep `generate()` for answers the game only uses whole
|
|
44
|
-
(a quest object, a list of decisions) — nobody watches those being written.
|
|
45
|
-
|
|
46
28
|
## Step 0 — is the lane live on this stand?
|
|
47
29
|
|
|
48
30
|
```bash
|
|
@@ -79,33 +61,15 @@ identity must be resolved first — `$genex-threejs-embed-auth`.
|
|
|
79
61
|
rest only if the player asks. Each row carries `label`, `vendor`,
|
|
80
62
|
`contextLength`, `personalPlan` and `structuredOutputs`; render `label`
|
|
81
63
|
verbatim, so the name on screen is the model that gets billed.
|
|
82
|
-
- `generate({ modelId, prompt, outputFormat, schema?,
|
|
64
|
+
- `generate({ modelId, prompt, outputFormat, schema?, estimateCoins,
|
|
83
65
|
allowExternal?, idempotencyKey?, grantId?, timeoutMs? })` →
|
|
84
66
|
`{ status, generationId, output, source, error }` plus billing fields
|
|
85
|
-
(`billingStatus`, `
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
maxConcurrent?, maxCallsPerMinute?, allowExternal?, judge?: { enabled,
|
|
90
|
-
estimatedCallsPerPeriod }, idempotencyKey? })` →
|
|
67
|
+
(`billingStatus`, `reservedCoins`, `chargedCoins`, their display-USD twins).
|
|
68
|
+
- `requestSpendGrant({ models, perCallMaxCoins, perCallEstimateCoins,
|
|
69
|
+
disclosure: { periodLabel, estimatedCallsPerPeriod, estimatedCoinsPerPeriod },
|
|
70
|
+
maxConcurrent?, maxCallsPerMinute?, allowExternal?, idempotencyKey? })` →
|
|
91
71
|
`{ status, grantId, … the limits the player approved }`; status is `active` |
|
|
92
|
-
`canceled` | `expired` | `failed` | `pending`.
|
|
93
|
-
honest per-call figure the disclosure is built on; left out, it is the
|
|
94
|
-
ceiling.
|
|
95
|
-
- `judge({ grantId, state, questions, idempotencyKey?, timeoutMs? })` →
|
|
96
|
-
`{ status, generationId, answers, error, billing }` — the grant's classifier,
|
|
97
|
-
answered in the same response. `questions` is 1–64 named `choice`
|
|
98
|
-
(`{ instructions, criteria: { option: description } }`), `score`
|
|
99
|
-
(`{ instructions, criteria: [levels, lowest first] }`) or `noul`
|
|
100
|
-
(`{ instructions }`); each answer has its question's type, and `noul` is a
|
|
101
|
-
probability — pick your own threshold. Needs a budget requested with `judge`.
|
|
102
|
-
- `generateStream({ …the generate() options, grantId, onDelta?(text, soFar),
|
|
103
|
-
onPartialField?(name, partialText), signal? })` → the same result as
|
|
104
|
-
`generate()`. Grant-only. `onDelta` hands over each piece and all the text so
|
|
105
|
-
far; for `outputFormat: 'json'`, `onPartialField` reports the schema's FIRST
|
|
106
|
-
top-level string property as far as it is written — put the spoken line first
|
|
107
|
-
in the schema. `signal` stops the reading, never the call (it still finishes
|
|
108
|
-
and is charged).
|
|
72
|
+
`canceled` | `expired` | `failed` | `pending`.
|
|
109
73
|
- `getSpendGrant(grantId)` — live state and counters; the ONE source for an
|
|
110
74
|
in-game budget readout.
|
|
111
75
|
- `stopSpendGrant(grantId)` — the game's own stop door. Prospective: no further
|
|
@@ -113,22 +77,13 @@ identity must be resolved first — `$genex-threejs-embed-auth`.
|
|
|
113
77
|
- `waitForGeneration(id)` / `getGeneration(id)` — re-attach to a call already
|
|
114
78
|
started, including after a reload.
|
|
115
79
|
- `generationErrorMessage(code)` — one player-facing sentence for an error code.
|
|
116
|
-
- `requestWorkflow(…)` — a registered workflow's own door, unchanged: keep
|
|
117
|
-
sending what that workflow's offerings ask for.
|
|
118
|
-
|
|
119
|
-
The credit names arrived in `@genex-ai/embed-sdk` 0.27.0. On `generate()`,
|
|
120
|
-
`generateStream()` and `requestSpendGrant()` the coin spellings —
|
|
121
|
-
`estimateCoins`, `perCallMaxCoins`, `perCallEstimateCoins` and
|
|
122
|
-
`disclosure.estimatedCoinsPerPeriod` — are deprecated: still accepted, and read
|
|
123
|
-
as the same numbers in credits. Write the credit names in anything new, and
|
|
124
|
-
rename them when you touch old code.
|
|
125
80
|
|
|
126
81
|
```ts
|
|
127
82
|
askButton.addEventListener('click', async () => { // a real click
|
|
128
83
|
const res = await generate({ // FIRST statement, no await before it
|
|
129
84
|
modelId, outputFormat: 'json', schema: ANSWER_SCHEMA,
|
|
130
85
|
prompt: askPrompt(npc, playerLine),
|
|
131
|
-
|
|
86
|
+
estimateCoins: NPC_CALL_PRICE, // benchmarked — see below
|
|
132
87
|
idempotencyKey: `npc:${npc.id}:${turnId}`,
|
|
133
88
|
});
|
|
134
89
|
applyGeneration(res); // the one writer — see below
|
|
@@ -148,55 +103,40 @@ test mode it is `local_test_unsupported`. Neither is a fault in the game. When
|
|
|
148
103
|
point out and play the authored fallback; never show it as an error. Which
|
|
149
104
|
shell draws what is in `$genex-threejs-embed-auth` (`references/shells.md`).
|
|
150
105
|
|
|
151
|
-
## `
|
|
106
|
+
## `estimateCoins` is a price, not an estimate
|
|
152
107
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
canceled attempt is billed the work the model did; one with no model work at
|
|
158
|
-
all costs nothing.
|
|
159
|
-
|
|
160
|
-
So the game declares no price. It declares a per-call **ceiling** — `maxCredits`
|
|
161
|
-
on `generate()`, `perCallMaxCredits` on a budget — and no call is ever billed
|
|
162
|
-
past it. The ceiling has a second job: **it also decides how long the answer
|
|
163
|
-
may be**, because each call's room to answer is funded from it. A number picked
|
|
164
|
-
by feel either cuts answers off or asks the player to approve far more than a
|
|
165
|
-
call ever costs.
|
|
108
|
+
You declare it; the platform charges it. Declare 5 and 5 is charged — on a
|
|
109
|
+
success, a failure, a cancel, and when the model stops at its budget. Only an
|
|
110
|
+
attempt with no model work at all costs nothing. A number picked by feel is
|
|
111
|
+
money taken from your players for nothing, or a call that cannot fund itself.
|
|
166
112
|
|
|
167
113
|
**Benchmark, then declare:**
|
|
168
114
|
|
|
169
115
|
```bash
|
|
170
116
|
npx genex llm bench "<the real prompt, with a real example filled in>" \
|
|
171
|
-
--schema ./answer.schema.json --samples 3 --max-
|
|
117
|
+
--schema ./answer.schema.json --samples 3 --max-coins <n> --user-approved
|
|
172
118
|
```
|
|
173
119
|
|
|
174
|
-
It runs on **your own
|
|
175
|
-
sample
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
A sample cut off at your `--max-credits` is not a sample: re-run with a higher
|
|
195
|
-
one. When the bench says the answer is longer than one call on this stand may
|
|
196
|
-
produce, ask for a shorter answer. `--max-coins` is the old name of
|
|
197
|
-
`--max-credits` and still works, with a line saying so.
|
|
198
|
-
|
|
199
|
-
Only samples that **succeeded and settled** are measured. A sample the
|
|
120
|
+
It runs on **your own coins**, on the development lane, and prints what each
|
|
121
|
+
sample actually charged plus the recommendation to declare: p95 of the charged
|
|
122
|
+
coins with the server's own recommended headroom already applied. Declare that
|
|
123
|
+
printed number. Never guess it, never work it out from a vendor's price list,
|
|
124
|
+
never add a margin of your own. For a standing budget the run prints a second
|
|
125
|
+
line, `Grant perCallMaxCoins`, and that one is `perCallMaxCoins` — declare it
|
|
126
|
+
verbatim as well rather than deriving a ceiling from `max`, which lands under
|
|
127
|
+
the price and makes `requestSpendGrant()` refuse before it reaches the network. Full procedure — reading p50/p95, turning the
|
|
128
|
+
loop into disclosure numbers, re-benchmarking after a prompt change — is in
|
|
129
|
+
[references/pricing.md](references/pricing.md).
|
|
130
|
+
|
|
131
|
+
**The declared price also decides how long the answer may be.** Each call's
|
|
132
|
+
room to answer is funded from the price it declares, so a price that covers
|
|
133
|
+
what an answer cost can still cut it off. The bench's recommendation already
|
|
134
|
+
leaves that room — always declare what it prints, never the bare charged
|
|
135
|
+
number. A sample cut off at your `--max-coins` is not a sample: re-run with a
|
|
136
|
+
higher one. When the bench says the answer is longer than one call on this
|
|
137
|
+
stand may produce, ask for a shorter answer.
|
|
138
|
+
|
|
139
|
+
Only samples that **succeeded and settled** are priced from. A sample the
|
|
200
140
|
provider refused at its door (`provider_http_<status>`) ran no inference and
|
|
201
141
|
cost nothing; the bench prints the code, the provider's own message and, for a
|
|
202
142
|
401 or 403, that this is the stand's provider configuration refusing the model
|
|
@@ -236,12 +176,12 @@ same object — a schema that passed the bench passes the game.
|
|
|
236
176
|
```ts
|
|
237
177
|
const grant = await requestSpendGrant({ // inside the click handler
|
|
238
178
|
models: [modelId],
|
|
239
|
-
|
|
240
|
-
|
|
179
|
+
perCallMaxCoins: NPC_CALL_CEILING,
|
|
180
|
+
perCallEstimateCoins: NPC_CALL_PRICE,
|
|
241
181
|
disclosure: {
|
|
242
182
|
periodLabel: 'minute',
|
|
243
183
|
estimatedCallsPerPeriod: 10, // 5 NPCs, one decision each per 30s
|
|
244
|
-
|
|
184
|
+
estimatedCoinsPerPeriod: 10 * NPC_CALL_PRICE,
|
|
245
185
|
},
|
|
246
186
|
maxConcurrent: 2,
|
|
247
187
|
maxCallsPerMinute: 30,
|
|
@@ -253,45 +193,8 @@ await savePlayerState({ ...state, grantId: grant.grantId });
|
|
|
253
193
|
**The disclosure is computed from this game's own loop, never wished for.** Five
|
|
254
194
|
NPCs deciding once every thirty seconds is ten calls a minute — write that
|
|
255
195
|
arithmetic into `DESIGN.md` beside the feature. The player sees your estimate
|
|
256
|
-
attributed to the game, beside the platform's own worst case
|
|
257
|
-
|
|
258
|
-
mid-session. Each call under the budget still declares its own `maxCredits`,
|
|
259
|
-
and it may not be above the budget's `perCallMaxCredits`:
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
perCallEstimateCredits ≤ perCallMaxCredits ≤ the limit the player approves
|
|
263
|
-
maxCredits on each call ≤ perCallMaxCredits
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**Using the judge too?** Add `judge: { enabled: true, estimatedCallsPerPeriod }`
|
|
267
|
-
to the same request — the checks you really expect per `periodLabel`, from the
|
|
268
|
-
same loop arithmetic. The sheet tells the player the game also uses a fast
|
|
269
|
-
classifier billed as used, with the platform's own worst case beside your count.
|
|
270
|
-
A judge-only feature passes `models: []`. A budget with the judge is paid from
|
|
271
|
-
the player's credits only, and judge calls share the budget's `maxConcurrent` and
|
|
272
|
-
`maxCallsPerMinute`: batch questions into one call (up to 64) rather than one
|
|
273
|
-
call per question.
|
|
274
|
-
|
|
275
|
-
**Streaming a reply under the budget:**
|
|
276
|
-
|
|
277
|
-
```ts
|
|
278
|
-
const res = await generateStream({
|
|
279
|
-
grantId, modelId, outputFormat: 'json', schema: LINE_SCHEMA, // `line` is its first property
|
|
280
|
-
prompt: npcPrompt(npc, playerLine), maxCredits: NPC_CALL_MAX,
|
|
281
|
-
idempotencyKey: `npc:${npc.id}:${turnId}`,
|
|
282
|
-
onPartialField: (_name, soFar) => npc.bubble.show(soFar), // provisional
|
|
283
|
-
});
|
|
284
|
-
applyGeneration(res); // the answer is THIS
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
The pieces are provisional: a call can still fail after text has shown (the
|
|
288
|
-
model broke off, the JSON missed the schema), so the bubble shows them and
|
|
289
|
-
`applyGeneration` decides what the game keeps — the same one writer as always.
|
|
290
|
-
Ceiling, benchmark and receipt are `generate()`'s: a started stream is billed the
|
|
291
|
-
work it did even when the player walks away mid-sentence. A stream holds one
|
|
292
|
-
of the budget's `maxConcurrent` slots until it has settled. Sometimes the reply
|
|
293
|
-
arrives whole — a busy stand, a retried call, a budget on the player's own plan —
|
|
294
|
-
and `onDelta` then gets the whole text once; the game needs no second path.
|
|
196
|
+
attributed to the game, beside the platform's own worst case; an estimate that
|
|
197
|
+
is transparently low is a grant that dies mid-session.
|
|
295
198
|
|
|
296
199
|
**Then keep the burn low, because you wrote the loop:** batch those five NPCs
|
|
297
200
|
into ONE call returning five decisions, cache a decision until the situation
|
|
@@ -306,10 +209,10 @@ Grant endings are ordinary game states with in-fiction copy, never an error toas
|
|
|
306
209
|
| `grant_stopped` | the player pressed Stop | accept silently, keep playing |
|
|
307
210
|
| `grant_expired` | 24h passed, or the session ended | as stopped; re-request on the next deliberate click |
|
|
308
211
|
| `waiting_for_plan` | their own plan is rate-limited | wait out the stated time — not a failure, and there is no paid fallback |
|
|
309
|
-
| `grant_insufficient_funds` | the
|
|
212
|
+
| `grant_insufficient_funds` | the wallet cannot fund the next call | pause the thinking NPCs, say it once, stay playable |
|
|
310
213
|
|
|
311
|
-
Draw the readout from `getSpendGrant(grantId)` — calls made,
|
|
312
|
-
|
|
214
|
+
Draw the readout from `getSpendGrant(grantId)` — calls made, coins settled, what
|
|
215
|
+
remains — never from a counter the game keeps itself. A finished grant may be
|
|
313
216
|
re-requested, but only from a **fresh deliberate click**: a silent auto-renew is
|
|
314
217
|
the exact shape a standing approval exists to prevent.
|
|
315
218
|
|
|
@@ -337,18 +240,18 @@ function applyGeneration(res) { // THE only place output becomes game state
|
|
|
337
240
|
`modelProvenance: 'unverified'` because it is user-supplied — check it exactly
|
|
338
241
|
as you would check typed player input.
|
|
339
242
|
|
|
340
|
-
## Errors land on the player's
|
|
243
|
+
## Errors land on the player's wallet
|
|
341
244
|
|
|
342
245
|
There is no compensation lane, so this is all work you do before the call:
|
|
343
246
|
|
|
344
|
-
- **Validate inputs first** — a malformed prompt is still
|
|
247
|
+
- **Validate inputs first** — a malformed prompt is still charged.
|
|
345
248
|
- **Always set `schema` for `outputFormat: 'json'`** — unschema'd JSON is the
|
|
346
249
|
commonest way a call is charged and the result is unusable. Write it in the
|
|
347
250
|
accepted dialect above; a refused schema is `invalid_schema` and costs
|
|
348
251
|
nothing, but it is a feature that never runs.
|
|
349
|
-
- **Keep prompts short.** Long context is
|
|
252
|
+
- **Keep prompts short.** Long context is the price.
|
|
350
253
|
- **Never loop `generate()` without a grant**, and never retry in a loop — each
|
|
351
|
-
attempt is a separate charge
|
|
254
|
+
attempt is a separate charge.
|
|
352
255
|
- **Map every code through `generationErrorMessage(code)`** into in-fiction
|
|
353
256
|
copy. A player should never read a raw error code inside your game.
|
|
354
257
|
- **`status: 'unknown'` is not a failure.** It means the charge is not known
|
|
@@ -357,12 +260,12 @@ There is no compensation lane, so this is all work you do before the call:
|
|
|
357
260
|
|
|
358
261
|
## What the Genex side already does — do not rebuild it
|
|
359
262
|
|
|
360
|
-
The approval sheet shows the model, the prompt, the
|
|
263
|
+
The approval sheet shows the model, the prompt, the price and the terms; the
|
|
361
264
|
game renders no price sheet. **Subscription funding is chosen only there** —
|
|
362
265
|
never add a "Your plan" row to the game's model picker, because a game cannot
|
|
363
266
|
offer a funding source. When the player's own watcher is online the personal-plan
|
|
364
267
|
answer arrives by itself and the game just waits, exactly as it waits for a
|
|
365
|
-
|
|
268
|
+
coin-funded call. The Genex dashboard header shows progress, active grants with
|
|
366
269
|
their spend, and a Stop; a Stop pressed there reaches the game as `grant_stopped`.
|
|
367
270
|
|
|
368
271
|
## Never
|
|
@@ -373,8 +276,7 @@ their spend, and a Stop; a Stop pressed there reaches the game as `grant_stopped
|
|
|
373
276
|
on your machine, never something a shipped build does.
|
|
374
277
|
- **Never hand-roll fetch to the runtime API** — the SDK owns the approval
|
|
375
278
|
handshake, and a hand-rolled call cannot obtain one.
|
|
376
|
-
- **Never hardcode a
|
|
377
|
-
or a margin.**
|
|
279
|
+
- **Never hardcode a price, a model id, a stand URL, or a margin.**
|
|
378
280
|
- **Never let the model be an authority over money, items or rewards**
|
|
379
281
|
(`$genex-monetization` owns what may move a wallet).
|
|
380
282
|
|
|
@@ -386,15 +288,12 @@ These are source contracts, not a claim that every stand runs this lane —
|
|
|
386
288
|
- [ ] `npx genex llm models` was run and its verdict is in the handoff
|
|
387
289
|
- [ ] Model ids come from `getGenerationModels()`, never from source
|
|
388
290
|
- [ ] The picker offers the featured set, labelled with the server's own `label`
|
|
389
|
-
- [ ] `
|
|
390
|
-
- [ ] No coin spelling (`estimateCoins`, `perCallMaxCoins`, `estimatedCoinsPerPeriod`) in new code
|
|
291
|
+
- [ ] `estimateCoins` is the figure `npx genex llm bench` printed, verbatim — never the bare charged number
|
|
391
292
|
- [ ] The schema uses only the accepted dialect (no `$ref`, `pattern`, `format`, `anyOf`, `default`)
|
|
392
293
|
- [ ] A bench refused as `generation_limit` was answered with `npx genex llm status`, never a retry
|
|
393
294
|
- [ ] `generate()` / `requestSpendGrant()` is the first statement of a click handler
|
|
394
295
|
- [ ] A repeated-call feature uses a grant; a one-off uses `generate()`
|
|
395
|
-
- [ ]
|
|
396
|
-
- [ ] Dialogue the player watches appear uses `generateStream()` under the grant; the resolved result, not the pieces, goes to `applyGeneration()`
|
|
397
|
-
- [ ] Disclosure numbers derive from the real loop and the bench's measured average, and are written in `DESIGN.md`
|
|
296
|
+
- [ ] Disclosure numbers derive from the real loop and are written in `DESIGN.md`
|
|
398
297
|
- [ ] Calls are batched and cached; nothing fires on an invisible timer
|
|
399
298
|
- [ ] Every grant-ending code has in-fiction copy and a playable fallback
|
|
400
299
|
- [ ] In the Genex app (`getShell() === "app"`) the feature's entry point is left out and the authored fallback plays
|
|
@@ -413,50 +312,18 @@ Nothing to fix in the game: ship the fallback and say so.
|
|
|
413
312
|
**Nothing opens when the player clicks** — an `await` ran before `generate()`
|
|
414
313
|
and the gesture was lost. Move the call to the first line of the handler.
|
|
415
314
|
|
|
416
|
-
**`player_wallet_required`** — ONE code for the two early dead ends:
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
above the budget's `perCallMaxCredits` (or a judge call's worst case is above
|
|
429
|
-
it). Declare the bench's `Declare maxCredits` on each call and its
|
|
430
|
-
`Grant perCallMaxCredits` on the budget — the second is never below the first.
|
|
431
|
-
|
|
432
|
-
**`insufficient_credits`** — the player's credits cannot cover this one-time
|
|
433
|
-
call's ceiling. Say it once in-fiction, keep the authored fallback, and never
|
|
434
|
-
retry in a loop; the Genex sheet already offers them a top-up. From
|
|
435
|
-
`npx genex llm bench` it is YOUR balance: the bench prints what it can spend.
|
|
436
|
-
|
|
437
|
-
**`credits_unverified`** — the player's Genex email is not verified, and credits
|
|
438
|
-
pay only for a verified account. Show the feature as verify-to-use rather than
|
|
439
|
-
hiding it; nothing was charged.
|
|
440
|
-
|
|
441
|
-
**`generation_paused`** — the platform has paused paid generation for now. Not
|
|
442
|
-
the game's fault and not the player's: keep the authored fallback, try again
|
|
443
|
-
on a later deliberate click, never in a loop.
|
|
444
|
-
|
|
445
|
-
**`judge_not_enabled`** — the budget was approved without the judge. Request a
|
|
446
|
-
new one with `judge` from the next deliberate click; never auto-renew.
|
|
447
|
-
**`judge_requires_grant`** — the judge's model was sent to `generate()` with no
|
|
448
|
-
budget; the judge is grant-only and is called with `judge()`.
|
|
449
|
-
**`judge_requires_credits`** — a judge call under a budget that is not paid
|
|
450
|
-
from the player's credits (their own plan cannot pay the judge). Request the
|
|
451
|
-
budget with `judge` and let it be credit-funded; keep the authored branch.
|
|
452
|
-
**`judge_period_limit`** — the checks reached the ceiling the player approved for
|
|
453
|
-
the period (your own `estimatedCallsPerPeriod` at the largest size): wait, and
|
|
454
|
-
if it keeps happening your declared rate is too low — fix the loop or the
|
|
455
|
-
estimate, never retry in a tight loop.
|
|
456
|
-
|
|
457
|
-
**`stream_requires_grant`** — `generateStream()` was called without a
|
|
458
|
-
`grantId`. Streaming is grant-only: a one-time call waits on the player's
|
|
459
|
-
approval popup, so use `generate()` for it.
|
|
315
|
+
**`player_wallet_required`** — ONE code for the two early dead ends: the lane
|
|
316
|
+
refuses a guest and a PREVIEW build on the same line. `waitForPlayer()` tells
|
|
317
|
+
them apart. `guest: true` — guests play but hold no wallet, so show the feature
|
|
318
|
+
as sign-in-to-use rather than hiding it (`$genex-threejs-embed-auth`). Signed
|
|
319
|
+
in and still refused — this is a `genex preview` draft, which never spends:
|
|
320
|
+
check the layout there, and the call itself only after `genex promote`. The
|
|
321
|
+
SDK's stock sentence for this code is "Sign in to Genex to use this", which is
|
|
322
|
+
right for the guest and wrong on a draft, so write the in-fiction line per
|
|
323
|
+
cause rather than showing it for both.
|
|
324
|
+
|
|
325
|
+
**`grant_price_unreasonable`** — the declared per-call price is far above what
|
|
326
|
+
that prompt can cost on that model. Re-benchmark and declare what it prints.
|
|
460
327
|
|
|
461
328
|
**`generation_limit`** — three ad-hoc calls are already in flight for this
|
|
462
329
|
account, or recently stopped with their bill still pending; a pending call
|
|
@@ -473,9 +340,9 @@ stand's provider configuration refusing the model — tell the operator, and
|
|
|
473
340
|
build nothing around it in the game.
|
|
474
341
|
|
|
475
342
|
**`provider_token_limit`** — the answer was cut off: the model ran out of room
|
|
476
|
-
before it finished, and the attempt is still
|
|
477
|
-
|
|
478
|
-
|
|
343
|
+
before it finished, and the attempt is still charged. The declared price is too
|
|
344
|
+
low for the answer's length — re-benchmark and declare what the bench prints,
|
|
345
|
+
never the bare charged number — or the answer is longer than one call on this
|
|
479
346
|
stand may produce, and the fix is a shorter answer (fewer fields, shorter
|
|
480
347
|
strings, a length the prompt states).
|
|
481
348
|
|
|
@@ -487,17 +354,13 @@ the subset above; `description` and `title` are allowed.
|
|
|
487
354
|
**`grant_concurrency` / `grant_rate_limited`** — the game calls faster than the
|
|
488
355
|
grant's own limits. Batch and cache; do not raise the limits to hide it.
|
|
489
356
|
|
|
490
|
-
**`payer_busy`** — the player's account was busy on Genex for a moment and
|
|
491
|
-
nothing was charged or started. Retry once after a short pause, from the same
|
|
492
|
-
action; it is not a refusal.
|
|
493
|
-
|
|
494
357
|
**`grant_not_active`** — the saved `grantId` is finished. Clear the stored id
|
|
495
358
|
and re-request from a fresh click.
|
|
496
359
|
|
|
497
360
|
**`external_request_active`** — that player already has one personal-plan
|
|
498
|
-
request running. Wait for it; never fall back to charging
|
|
361
|
+
request running. Wait for it; never fall back to charging coin instead.
|
|
499
362
|
|
|
500
|
-
**The call is
|
|
363
|
+
**The call is charged but the result is unusable** — `outputFormat: 'json'`
|
|
501
364
|
without a `schema`. Add one; the charge already happened.
|
|
502
365
|
|
|
503
366
|
**A reload lost the answer** — `generationId` was not saved before the await, or
|