@pouchy_ai/world-sdk 0.10.0 → 0.11.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 CHANGED
@@ -1,5 +1,32 @@
1
1
  # @pouchy_ai/world-sdk
2
2
 
3
+ ## 0.11.0
4
+
5
+ Additive: your backend can tell the world what it already knows. World API 1.8.
6
+
7
+ - `runTurn` and `sendEvent` both accept `proposedPatches` — PROVIDER-authored
8
+ state changes committed with the beat. The server has accepted them on the
9
+ turns door since Batch 5; the SDK never exposed the field, and the event lane
10
+ never carried one at all. So a fact your system holds ("the payment cleared",
11
+ "the shipment arrived", "the player really does have the key") could only WAKE
12
+ the characters and hope one of them proposed the right effect.
13
+ - They ride the coordinator's single commit alongside the roles' settled
14
+ effects, and are validated server-side against the closed StatePatch union and
15
+ the pinned story package — all-or-nothing, so a batch with one bad op commits
16
+ nothing. A provider cannot write a role's private notes.
17
+ - COORDINATED worlds only. An actor world wakes each role separately and has no
18
+ single commit for a deterministic write to ride, so sending patches to one is
19
+ **refused with 422** rather than silently dropped. That refusal is the feature:
20
+ a channel that accepts input and discards it is the failure mode this project
21
+ has recorded three times, and it always reads as success.
22
+ - `agent.event_reply` webhooks from a coordinated world now carry `turnId`,
23
+ `stateRevision` and `sequence` in the `world` block. Until now a consumer got
24
+ the instance and the role and nothing else — it could not join the reply back
25
+ to the ledger turn, could not tell whether the world had moved, and could not
26
+ order two lines of one beat, since webhook delivery is per-message and
27
+ promises no ordering. All three are additive.
28
+ - No existing method changed shape.
29
+
3
30
  ## 0.10.0
4
31
 
5
32
  Additive: an unattended backend can now read its own world. World API 1.7.
package/README.md CHANGED
@@ -78,6 +78,22 @@ the delivery queue ACTIONS stay on `adminToken` on purpose: requeue, rehydrate
78
78
  and resolve-gap each decide what happens to a reader who is missing a beat, and
79
79
  resolve-gap tells them it is never coming.
80
80
 
81
+ **Telling the world a fact you already hold.** Your system knows things the
82
+ model can only guess at. Send them as patches and the world records them,
83
+ instead of hoping a character proposes the right effect:
84
+
85
+ ```ts
86
+ await world.runTurn({
87
+ environmentId, worldInstanceId,
88
+ text: 'I hand over the coin pouch.',
89
+ proposedPatches: [{ op: 'set_flag', key: 'paid', value: true }]
90
+ });
91
+ ```
92
+
93
+ `sendEvent` takes the same field. Coordinated worlds only — an actor world has
94
+ no single commit for a deterministic write to ride, and sending patches to one
95
+ answers 422 rather than dropping them quietly.
96
+
81
97
  **Resuming after a crash.** `getTurn` returns the same fields the live result
82
98
  did — `nextOptions` included — so a recovered session can offer the audience
83
99
  the choices it was about to. To catch up on beats you missed entirely, store
@@ -178,6 +194,8 @@ and exits non-zero on the first structural failure.
178
194
 
179
195
  - `docs/world-quickstart-drama.md` — screenplay → world → new screenplay draft
180
196
  - `docs/world-quickstart-npc.md` — one town, three NPCs, one shared state
197
+ - `docs/world-quickstart-nextjs.md` — a Next.js app: one route handler, one page,
198
+ no browser login anywhere in the deployment
181
199
 
182
200
  ## License
183
201
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const WORLD_SDK_VERSION = "0.10.0";
1
+ export declare const WORLD_SDK_VERSION = "0.11.0";
2
2
  export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1";
3
3
  /** The refusal classes a world call can produce. `unknown` is deliberate: an
4
4
  * unrecognized status is never quietly folded into a neighbour. */
@@ -750,6 +750,19 @@ export declare class PouchyWorldClient {
750
750
  text: string;
751
751
  sourceRoleId?: string;
752
752
  traceId?: string;
753
+ /** PROVIDER-authored state changes, committed with this beat.
754
+ *
755
+ * Your backend already knows things the model can only guess at — the
756
+ * payment cleared, the shipment arrived, the player actually holds the
757
+ * key. Send them as patches and the world HOLDS them, rather than
758
+ * hoping a character proposes the right effect.
759
+ *
760
+ * They ride the coordinator's single commit alongside the roles'
761
+ * settled effects, and are validated server-side against the closed
762
+ * StatePatch union and the pinned story package — all-or-nothing, so a
763
+ * batch with one bad op commits nothing. A provider cannot write a
764
+ * role's private notes. */
765
+ proposedPatches?: readonly Record<string, unknown>[];
753
766
  }): Promise<WorldTurnResult>;
754
767
  /** Send a trusted EVENT into a world. On a `coordinated` world this becomes
755
768
  * one coordinator turn; on an `actor` world it wakes each subscribed role.
@@ -762,6 +775,14 @@ export declare class PouchyWorldClient {
762
775
  data: Record<string, unknown>;
763
776
  schemaVersion?: number;
764
777
  occurredAt?: number;
778
+ /** PROVIDER-authored state changes to commit with the beat this event
779
+ * produces. Same contract as `runTurn`'s.
780
+ *
781
+ * COORDINATED worlds only. An actor world wakes each role separately
782
+ * and has no single commit for a deterministic write to ride, so
783
+ * sending these to one is refused with 422 rather than silently
784
+ * dropped — you will hear about it, which is the point. */
785
+ proposedPatches?: readonly Record<string, unknown>[];
765
786
  }): Promise<Record<string, unknown>>;
766
787
  /** A world READ. Prefers the machine lane when an admin key is present.
767
788
  *
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@
17
17
  // SIGNING a request the way the server verifies it, and choosing turn ids that
18
18
  // make a retry idempotent instead of a second beat.
19
19
  import { createHash, createHmac, randomUUID } from 'node:crypto';
20
- export const WORLD_SDK_VERSION = '0.10.0';
20
+ export const WORLD_SDK_VERSION = '0.11.0';
21
21
  export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1';
22
22
  // ── errors ─────────────────────────────────────────────────────────────────
23
23
  /** The refusal classes a world call can produce. `unknown` is deliberate: an
@@ -508,7 +508,8 @@ export class PouchyWorldClient {
508
508
  trigger: {
509
509
  kind: 'user',
510
510
  text: input.text,
511
- ...(input.sourceRoleId ? { sourceRoleId: input.sourceRoleId } : {})
511
+ ...(input.sourceRoleId ? { sourceRoleId: input.sourceRoleId } : {}),
512
+ ...(input.proposedPatches ? { proposedPatches: input.proposedPatches } : {})
512
513
  },
513
514
  ...(input.traceId ? { traceId: input.traceId } : {})
514
515
  };
@@ -524,7 +525,11 @@ export class PouchyWorldClient {
524
525
  eventId,
525
526
  schemaVersion: input.schemaVersion ?? 1,
526
527
  data: input.data,
527
- world: { environment: input.environment, instance: input.worldInstance },
528
+ world: {
529
+ environment: input.environment,
530
+ instance: input.worldInstance,
531
+ ...(input.proposedPatches ? { proposedPatches: input.proposedPatches } : {})
532
+ },
528
533
  ...(input.occurredAt !== undefined ? { occurredAt: input.occurredAt } : {})
529
534
  };
530
535
  return this.signed(`/projects/${this.projectId}/events`, body, eventId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/world-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.11.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",