@pouchy_ai/world-sdk 0.28.1 → 0.29.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 +27 -0
- package/README.md +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +18 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @pouchy_ai/world-sdk
|
|
2
2
|
|
|
3
|
+
## 0.29.0
|
|
4
|
+
|
|
5
|
+
- **`skippedRoles[].code`** — the machine half of "why this role did not
|
|
6
|
+
speak", as a closed `WorldSkipCode` union, plus `skipSpentNoModelCall(code)`
|
|
7
|
+
for the one derived question every consumer asks of it.
|
|
8
|
+
|
|
9
|
+
`reason` has always been a human sentence and stays one; nothing should key
|
|
10
|
+
off it. This exists because an integrator, given the reason prefixes in a
|
|
11
|
+
letter (the spec published none), built a cost model on
|
|
12
|
+
`reason.startsWith('turn error:')`. Their own words for the exposure: rename
|
|
13
|
+
that prefix and "we would not error — we would quietly file that class as
|
|
14
|
+
costing nothing." The same argument the rejection taxonomy made for
|
|
15
|
+
`rejectedEffects[].code`, applied to the sibling array that missed it.
|
|
16
|
+
|
|
17
|
+
Twelve codes. Eight of them mean no model call was made — `not_focused`,
|
|
18
|
+
`role_cap_reached`, `no_actor_bound`, `deadline_exhausted`, `not_admitted`,
|
|
19
|
+
`actor_unavailable`, `session_busy`, `content_policy`. Two mean a model ran or
|
|
20
|
+
may have: `turn_error` (deliberately does NOT promise a call happened —
|
|
21
|
+
context assembly failing and a provider dying mid-stream both land there) and
|
|
22
|
+
`no_message`. Two are beats where the role DID speak and the line was
|
|
23
|
+
withheld: `effect_refused`, `conflict_undelivered`.
|
|
24
|
+
|
|
25
|
+
Additive and optional: absent from a server predating the taxonomy, which
|
|
26
|
+
reads as unknown, never as a value. `skipSpentNoModelCall` returns false for
|
|
27
|
+
an unknown code and for `turn_error`, on the principle that a cost model
|
|
28
|
+
which under-counts silently is worse than one that over-counts visibly.
|
|
29
|
+
|
|
3
30
|
## 0.28.1
|
|
4
31
|
|
|
5
32
|
- **`WorldApiError.errorId`** — the server's lookup reference (`err_…`) for a
|
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ answers 422 rather than dropping them quietly.
|
|
|
121
121
|
**Focusing a beat on some of the cast.** By default every bound role answers a
|
|
122
122
|
beat (up to the server cap). For an interview or a one-on-one scene, pass
|
|
123
123
|
`focusRoles` and only those roles run — the rest are not billed and are
|
|
124
|
-
recorded in `skippedRoles`
|
|
124
|
+
recorded in `skippedRoles` with `code: 'not_focused'`:
|
|
125
125
|
|
|
126
126
|
```ts
|
|
127
127
|
const beat = await world.runTurn({
|
|
@@ -135,6 +135,31 @@ Shrink-only: the server intersects the focus with the bound story cast, so it
|
|
|
135
135
|
can never widen a beat, and a focus matching no bound role is refused as
|
|
136
136
|
`no selectable role` without spending anything.
|
|
137
137
|
|
|
138
|
+
**Why a role was passed over.** Each `skippedRoles` entry carries a `reason`
|
|
139
|
+
(the human line, which carries the sub-cause and is free to be reworded) and a
|
|
140
|
+
`code` — a closed `WorldSkipCode`. **Key off the code, never the reason.**
|
|
141
|
+
Reading an error string to decide what happened is how a message edit silently
|
|
142
|
+
reclassifies a whole class; this SDK ships the enum precisely so you do not
|
|
143
|
+
have to pattern-match prose.
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { skipSpentNoModelCall } from '@pouchy_ai/world-sdk';
|
|
147
|
+
|
|
148
|
+
for (const s of beat.skippedRoles) {
|
|
149
|
+
if (s.code === undefined) audit.unknown(s.roleId, s.reason); // old server
|
|
150
|
+
else if (skipSpentNoModelCall(s.code)) cost.free(s.roleId, s.code);
|
|
151
|
+
else cost.mayHaveSpent(s.roleId, s.code);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`skipSpentNoModelCall` answers false for `turn_error` even though it often is
|
|
156
|
+
free: context assembly failing and a provider dying mid-stream both land there
|
|
157
|
+
and cannot be told apart afterwards, so a cost model that counted it free would
|
|
158
|
+
under-count silently. It answers false for an unknown code for the same reason.
|
|
159
|
+
|
|
160
|
+
To read a beat, subtract: a role in `selectedRoles` and absent from
|
|
161
|
+
`skippedRoles` chose silence; a role listed here never ran.
|
|
162
|
+
|
|
138
163
|
**Resuming after a crash.** `getTurn` returns the same fields the live result
|
|
139
164
|
did — `nextOptions` included — so a recovered session can offer the audience
|
|
140
165
|
the choices it was about to. To catch up on beats you missed entirely, store
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* a project is running — which is exactly the field you reach for when a
|
|
5
5
|
* customer's integration behaves like an older SDK than they say they have.
|
|
6
6
|
* It sat at '0.1.0' for eight releases before anything compared the two. */
|
|
7
|
-
export declare const WORLD_SDK_VERSION = "0.
|
|
7
|
+
export declare const WORLD_SDK_VERSION = "0.29.0";
|
|
8
8
|
export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1";
|
|
9
9
|
/** One direction a beat could take. The WHOLE of what a deliberation shows a
|
|
10
10
|
* player: no reasoning, no role secrets, no simulated effects, no scores. */
|
|
@@ -176,6 +176,7 @@ export interface WorldTurnResult {
|
|
|
176
176
|
skippedRoles: Array<{
|
|
177
177
|
roleId: string;
|
|
178
178
|
reason: string;
|
|
179
|
+
code?: WorldSkipCode;
|
|
179
180
|
}>;
|
|
180
181
|
nextOptions: Array<{
|
|
181
182
|
branchId: string;
|
|
@@ -381,6 +382,7 @@ export interface WorldTurnReadback {
|
|
|
381
382
|
skippedRoles?: Array<{
|
|
382
383
|
roleId: string;
|
|
383
384
|
reason: string;
|
|
385
|
+
code?: WorldSkipCode;
|
|
384
386
|
}>;
|
|
385
387
|
repairs?: Array<{
|
|
386
388
|
roleId: string;
|
|
@@ -525,6 +527,29 @@ export interface EditorialDraftRow {
|
|
|
525
527
|
* content problem. */
|
|
526
528
|
/** The shared refusal taxonomy (Batch 7). Only `narrative_conflict` is content. */
|
|
527
529
|
export type WorldRejectionCode = 'narrative_conflict' | 'policy_rejection' | 'schema_rejection' | 'canon_rejection' | 'concurrency_rejection' | 'repair_failure';
|
|
530
|
+
/** WHY a role that was in the cast did not speak — the machine half of
|
|
531
|
+
* `skippedRoles[].reason`, added 2026-09-09.
|
|
532
|
+
*
|
|
533
|
+
* `reason` remains the human line and carries the sub-cause (which admission
|
|
534
|
+
* rule, which runtime error); it is free to be reworded, so do not key off it.
|
|
535
|
+
* This exists because an integrator built a cost model on
|
|
536
|
+
* `reason.startsWith('turn error:')` — a rename on the platform side would not
|
|
537
|
+
* have errored, it would have silently reclassified that whole class.
|
|
538
|
+
*
|
|
539
|
+
* No model call was made for the first eight; a model ran, or may have, for
|
|
540
|
+
* `turn_error` and `no_message`; the last two are beats where the role DID
|
|
541
|
+
* speak and the line was withheld. `skipSpentNoModelCall` below is that split,
|
|
542
|
+
* so a consumer does not re-derive it. Absent on turns from a server predating
|
|
543
|
+
* the taxonomy — read that as unknown, never as a value. */
|
|
544
|
+
export type WorldSkipCode = 'not_focused' | 'role_cap_reached' | 'no_actor_bound' | 'deadline_exhausted' | 'not_admitted' | 'actor_unavailable' | 'session_busy' | 'content_policy' | 'turn_error' | 'no_message' | 'effect_refused' | 'conflict_undelivered';
|
|
545
|
+
/** Did this skip happen before any model call — is the role's silence free?
|
|
546
|
+
*
|
|
547
|
+
* `turn_error` is deliberately NOT in the free set even though it often is:
|
|
548
|
+
* context assembly failing and a provider dying mid-stream both land there and
|
|
549
|
+
* cannot be told apart after the fact, so a cost model that counted it free
|
|
550
|
+
* would under-count silently. Returns false for an unknown code, for the same
|
|
551
|
+
* reason. */
|
|
552
|
+
export declare function skipSpentNoModelCall(code: WorldSkipCode | undefined): boolean;
|
|
528
553
|
/** True for every code except `narrative_conflict`. */
|
|
529
554
|
export declare function isDefectRejection(code: WorldRejectionCode | undefined): boolean;
|
|
530
555
|
export interface WorldInstanceMetrics {
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import { createHash, createHmac, randomUUID } from 'node:crypto';
|
|
|
23
23
|
* a project is running — which is exactly the field you reach for when a
|
|
24
24
|
* customer's integration behaves like an older SDK than they say they have.
|
|
25
25
|
* It sat at '0.1.0' for eight releases before anything compared the two. */
|
|
26
|
-
export const WORLD_SDK_VERSION = '0.
|
|
26
|
+
export const WORLD_SDK_VERSION = '0.29.0';
|
|
27
27
|
export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1';
|
|
28
28
|
/** Read the commit turn id out of an envelope, so the signature covers the id
|
|
29
29
|
* the server will commit under. The payload half is base64url JSON; the
|
|
@@ -306,6 +306,23 @@ export function describeTurn(result) {
|
|
|
306
306
|
` delivery ${result.deliveryStatus}`
|
|
307
307
|
};
|
|
308
308
|
}
|
|
309
|
+
/** Did this skip happen before any model call — is the role's silence free?
|
|
310
|
+
*
|
|
311
|
+
* `turn_error` is deliberately NOT in the free set even though it often is:
|
|
312
|
+
* context assembly failing and a provider dying mid-stream both land there and
|
|
313
|
+
* cannot be told apart after the fact, so a cost model that counted it free
|
|
314
|
+
* would under-count silently. Returns false for an unknown code, for the same
|
|
315
|
+
* reason. */
|
|
316
|
+
export function skipSpentNoModelCall(code) {
|
|
317
|
+
return (code === 'not_focused' ||
|
|
318
|
+
code === 'role_cap_reached' ||
|
|
319
|
+
code === 'no_actor_bound' ||
|
|
320
|
+
code === 'deadline_exhausted' ||
|
|
321
|
+
code === 'not_admitted' ||
|
|
322
|
+
code === 'actor_unavailable' ||
|
|
323
|
+
code === 'session_busy' ||
|
|
324
|
+
code === 'content_policy');
|
|
325
|
+
}
|
|
309
326
|
/** True for every code except `narrative_conflict`. */
|
|
310
327
|
export function isDefectRejection(code) {
|
|
311
328
|
return code !== undefined && code !== 'narrative_conflict';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pouchy_ai/world-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Server-side TypeScript client for Pouchy World \u2014 story packages, world definitions, world sessions, coordinated turns, trusted events, replay verification and script drafts. Node only: it holds a project Secret Key and a source signing key, which never belong in a browser or a mobile app.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|