@whitesands/agent-player 1.1.0 → 1.3.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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.0
4
+
5
+ - `start()` takes `memory`, `maxActions`, `subgoals` and `ownInstructions`.
6
+ - With `memory: true` the platform keeps the character's memory and relationships. `handle.observe(text, about)` adds an event without a turn, `handle.relationships()` reads how it feels about people, and `memory` and `relationship` events are emitted.
7
+ - `TurnResult.steps` lists every action when a turn played more than one.
8
+ - `World`: describe places, things and characters once; it builds each character's view and standard actions, carries speech, and decides when a character gets a turn. Port of `WSI.World` from the Luau SDK.
9
+ - `examples/town`: Sandy Shores as a browser game on `World`.
10
+ - A refused `start_session` now rejects `start()` with the platform's reason instead of timing out.
11
+ - A reconnect that fails part-way can no longer end the process with an unhandled "Timed out waiting for session resume".
12
+
13
+ ## 1.2.0
14
+
15
+ ### Minor Changes
16
+
17
+ - Register a tool from a name, description, Zod schema, and callback with `bindDynamic`.
18
+ - `start()` requires `playerId`, the character UUID from the web app. One platform key serves the game, and each session names the character to play.
19
+
3
20
  ## 1.1.0
4
21
 
5
22
  ### Minor Changes
package/README.md CHANGED
@@ -40,7 +40,7 @@ Use the same Zod 3 the SDK depends on when you declare argument schemas. Zod 4 o
40
40
 
41
41
  ## Usage
42
42
 
43
- Set the platform key, then start one agent per character. `turn()` grants that character one chance to act and resolves with what they did.
43
+ Set the platform key, then start one agent per character. The key belongs to the game. `playerId` is the character id from the Players page, and every `start()` sends it. `turn()` grants that character one chance to act and resolves with what they did.
44
44
 
45
45
  ```sh
46
46
  export WSI_PLATFORM_KEY=pk_...
@@ -53,6 +53,7 @@ import { AgentServer } from "@whitesands/agent-player";
53
53
 
54
54
  const agents = new AgentServer();
55
55
  const ada = await agents.start(new Villager(world, "Ada"), {
56
+ playerId: "3f6c2d1e-8b7a-4c5d-9e0f-1a2b3c4d5e6f",
56
57
  name: "Ada",
57
58
  goal: "Stand on the tree and chop it",
58
59
  });
@@ -127,6 +128,28 @@ class Villager {
127
128
  }
128
129
  ```
129
130
 
131
+ ### Tools from data
132
+
133
+ `bindDynamic` registers one tool when the action is data rather than a method. Call it on the player before `start()`. `see` is allowed, including when the player has no `see()` method. `wait`, an empty name, a name starting with `_`, and a missing callback are rejected. An empty description becomes `Action: <name>`. Registering the same name again replaces that tool, including a reflected method of the same name.
134
+
135
+ Arguments use the same Zod shape as `static agent`. A schema failure throws before the callback runs and uses the one retry. Extra keys are ignored.
136
+
137
+ ```ts
138
+ import { AgentServer, bindDynamic } from "@whitesands/agent-player";
139
+ import { z } from "zod";
140
+
141
+ const scout = { n: 1 };
142
+ const playerId = "3f6c2d1e-8b7a-4c5d-9e0f-1a2b3c4d5e6f";
143
+ bindDynamic(scout, "see", "", undefined, () => ({ n: scout.n }));
144
+ bindDynamic(scout, "add", "Add dx", { dx: z.number().int() }, (args) => {
145
+ scout.n += args.dx as number;
146
+ return { n: scout.n };
147
+ });
148
+
149
+ const agents = new AgentServer();
150
+ const agent = await agents.start(scout, { playerId });
151
+ ```
152
+
130
153
  ### Turns
131
154
 
132
155
  `turn()` does not choose the action. It unblocks that session's `wait`. The platform reads `see()`, calls one action, and reports back.
@@ -176,11 +199,19 @@ try {
176
199
 
177
200
  ### Several characters
178
201
 
179
- One `AgentServer` hosts every character. Each `start()` is its own session.
202
+ One `AgentServer` and one platform key host every character in the game. Each `start()` is its own session and names that character with `playerId`. The id is a UUID, and it stays the same when the character is renamed. A missing id, a value that is not a UUID, or an id from another game is rejected and no session is created.
180
203
 
181
204
  ```ts
182
- const ada = await agents.start(new Villager(world, "Ada"), { name: "Ada", goal: "Chop the tree" });
183
- const bea = await agents.start(new Villager(world, "Bea"), { name: "Bea", goal: "Carry wood home" });
205
+ const ada = await agents.start(new Villager(world, "Ada"), {
206
+ playerId: "3f6c2d1e-8b7a-4c5d-9e0f-1a2b3c4d5e6f",
207
+ name: "Ada",
208
+ goal: "Chop the tree",
209
+ });
210
+ const bea = await agents.start(new Villager(world, "Bea"), {
211
+ playerId: "6b1e2a30-0c1d-4e5f-8a9b-0c1d2e3f4a5b",
212
+ name: "Bea",
213
+ goal: "Carry wood home",
214
+ });
184
215
 
185
216
  await ada.turn();
186
217
  await bea.turn();
@@ -234,6 +265,7 @@ const agents = new AgentServer({
234
265
 
235
266
  ```ts
236
267
  await agents.start(ferry, {
268
+ playerId: "3f6c2d1e-8b7a-4c5d-9e0f-1a2b3c4d5e6f",
237
269
  name: "Ferryman",
238
270
  goal: "Get the wolf, the goat, and the cabbage onto the far bank.",
239
271
  });
@@ -241,7 +273,7 @@ await agents.start(ferry, {
241
273
 
242
274
  ### Testing without a platform
243
275
 
244
- `@whitesands/agent-player/testing` runs the same wait, act, and retry loop in memory. The script is the list of tool calls, in order. No key and no socket.
276
+ `@whitesands/agent-player/testing` runs the same wait, act, and retry loop in memory. The script is the list of tool calls, in order. No key and no socket. `start()` still requires `playerId`.
245
277
 
246
278
  ```ts
247
279
  import { AgentServer } from "@whitesands/agent-player";
@@ -309,3 +341,26 @@ PLATFORM_KEY=pk_... npm run forest -- --remote
309
341
  ```
310
342
 
311
343
  Releases are recorded in [CHANGELOG.md](CHANGELOG.md).
344
+
345
+ ## World
346
+
347
+ `World` builds a living world on top of the agent player, so a game does not write a view or actions per character. The game provides the engine: places, things with activities, and a body per character (`getPosition`, `moveTo`, `stop`, `say`). `World` serves each character's tools over MCP (`say`, `go_to`, `approach`, `use`, `give`, `emote`, `idle`), carries speech between characters and players, and decides when a character needs a turn. Who each character is comes from its role and story on the platform.
348
+
349
+ ```ts
350
+ import { AgentServer, World } from "@whitesands/agent-player";
351
+
352
+ const world = new World(new AgentServer(), { name: "Sandy Shores", about: "A small beach town." });
353
+ world.addPlace("cafe", { description: "Mia's cafe", position: { x: 60, y: 0 } });
354
+ world.addThing("espresso_machine", {
355
+ place: "cafe",
356
+ position: { x: 64, y: -4 },
357
+ activities: { make_coffee: { description: "Make a coffee", seconds: 6, gives: "coffee" } },
358
+ });
359
+ await world.addCharacter({ id: miaCharacterId, name: "Mia", body: miaBody, home: "cafe" });
360
+ world.addPerson({ name: "Alex", getPosition: () => alexPosition });
361
+ world.on((event) => { /* speech, relationship, status, give, thinking, turn */ });
362
+ world.start();
363
+ world.say("Alex", "Hi Mia!");
364
+ ```
365
+
366
+ `examples/town` is a complete browser game built this way: `npm run build && WSI_PLATFORM_KEY=pk_... npm run town`, then open `http://localhost:8080`.