@agent-play/sdk 3.2.2 → 3.3.3

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/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { W as WorldInteractionRole, L as LangChainAgentRegistration, R as RemotePlayWorldInitAudioOptions, A as AgentPlaySnapshot, P as PlayerChainNodeResponse, a as AddAgentInput, b as RegisteredPlayer, c as AddPlayerInput, d as RecordInteractionInput, J as Journey } from './browser-CD0Fu-zr.js';
2
- export { e as AgentPlayWorldMap, f as AgentPlayWorldMapAgentOccupant, g as AgentPlayWorldMapBounds, h as AgentPlayWorldMapMcpOccupant, i as AssistToolFieldType, j as AssistToolParameterSpec, k as AssistToolSpec, D as DestinationJourneyStep, l as JourneyStep, M as MINIMUM_PLAY_WORLD_BOUNDS, O as OriginJourneyStep, m as P2aEnableFlag, n as PLAYER_CHAIN_GENESIS_STABLE_KEY, o as PLAYER_CHAIN_HEADER_STABLE_KEY, p as PlatformAgentInformation, q as PlayAgentInformation, r as PlayerChainFanoutNotify, s as PlayerChainGenesisNode, t as PlayerChainHeaderNode, u as PlayerChainNotifyNodeRef, v as PlayerChainOccupantPresentNode, w as PlayerChainOccupantRemovedNode, x as PositionedStep, y as RealtimeWebrtcClientSecret, z as RegisteredAgentSummary, B as RemotePlayWorldOpenAiAudioOptions, S as StructureJourneyStep, C as WorldBounds, E as WorldJourneyUpdate, Y as YieldEventInfo, Z as ZoneEventInfo, F as boundsContain, G as clampWorldPosition, H as expandBoundsToMinimumPlayArea, I as mergeSnapshotWithPlayerChainNode, K as parsePlayerChainFanoutNotify, N as parsePlayerChainFanoutNotifyFromSsePayload, Q as parsePlayerChainNodeRpcBody, T as sortNodeRefsForSerializedFetch } from './browser-CD0Fu-zr.js';
1
+ import { W as WorldInteractionRole, L as LangChainAgentRegistration, R as RemotePlayWorldInitAudioOptions, A as AgentPlaySnapshot, P as PlayerChainNodeResponse, a as AddAgentInput, b as RegisteredPlayer, c as AddPlayerInput, d as RecordInteractionInput, J as Journey } from './browser-Dpx-0L8A.js';
2
+ export { e as AgentPlayWorldLayout, f as AgentPlayWorldLayoutZone, g as AgentPlayWorldMap, h as AgentPlayWorldMapAgentOccupant, i as AgentPlayWorldMapBounds, j as AgentPlayWorldMapMcpOccupant, k as AssistToolFieldType, l as AssistToolParameterSpec, m as AssistToolSpec, C as CONTINUOUS_RENDER_OFFSET, n as CarWashCar, o as CarWashCarSchema, D as DEFAULT_AGENT_SPAWN_MIN_DISTANCE, p as DEFAULT_PLAYER_WALLET_BALANCE_USD, q as DestinationJourneyStep, r as JourneyStep, M as MINIMUM_PLAY_WORLD_BOUNDS, O as OCCUPANCY_POINT_MULTIPLIER, s as OccupancyGridPoint, t as OccupantGroup, u as OriginJourneyStep, v as P2aEnableFlag, w as PLAYER_CHAIN_GENESIS_STABLE_KEY, x as PLAYER_CHAIN_HEADER_STABLE_KEY, y as PlatformAgentInformation, z as PlayAgentInformation, B as PlayerChainFanoutNotify, E as PlayerChainGenesisNode, F as PlayerChainHeaderNode, G as PlayerChainNotifyNodeRef, H as PlayerChainOccupantPresentNode, I as PlayerChainOccupantRemovedNode, K as PlayerWallet, N as PlayerWalletSchema, Q as PositionedStep, S as PurchaseRecord, T as PurchaseRecordSchema, U as RealtimeWebrtcClientSecret, V as RegisteredAgentSummary, X as RemotePlayWorldOpenAiAudioOptions, Y as SPATIAL_ZONE_INDEX_AGENTS, Z as SPATIAL_ZONE_INDEX_SPACES, _ as STREET_NAME_POOL, $ as SaleState, a0 as SaleStateSchema, a1 as ShopItem, a2 as ShopItemSchema, a3 as SpaceContentItem, a4 as Street, a5 as StreetPoolEntry, a6 as StructureJourneyStep, a7 as SupermarketItem, a8 as SupermarketItemSchema, a9 as WorldBounds, aa as WorldJourneyUpdate, ab as WorldLayout, ac as WorldLayoutBoundsField, ad as YieldEventInfo, ae as Zone, af as ZoneEventInfo, ag as applyBoundsFieldUpdateToLayout, ah as availableCellsForZone, ai as boundingWorldRectForOccupancyPoints, aj as boundsContain, ak as buildRankedOccupancyPoints, al as buildRankedOccupancyPointsForSpatialZone, am as buildRankedOccupancyPointsForZone, an as buildRankedOccupancyPointsInRect, ao as cellsForZone, ap as centerOfZone, aq as clampWorldPosition, ar as createInitialPlayerWallet, as as createVerticalStripSeedLayout, at as desaturateColor, au as enumerateIntegerCellsInRect, av as expandBoundsToMinimumPlayArea, aw as getStreetPoolEntryById, ax as isAgentSpawnOccupancyPointAvailable, ay as isAgentSpawnOccupancyPointAvailableInRect, az as isAgentSpawnOccupancyPointAvailableInZone, aA as isItemAvailableForPurchase, aB as isSpaceAnchorOccupancyPointAvailable, aC as isSpaceAnchorOccupancyPointAvailableInRect, aD as isSpaceAnchorOccupancyPointAvailableInZone, aE as listAllowedOccupancyPoints, aF as listOccupancyPointsForSpatialZone, aG as listOccupancyPointsForZone, aH as listOccupancyPointsInRect, aI as mergeSnapshotWithPlayerChainNode, aJ as migrateWorldLayoutBounds, aK as nextStreetFromPool, aL as occupancyKeyForPosition, aM as occupancyPointsGroupedBySpatialZone, aN as occupancyPointsGroupedByZones, aO as parsePlayerChainFanoutNotify, aP as parsePlayerChainFanoutNotifyFromSsePayload, aQ as parsePlayerChainNodeRpcBody, aR as pickZoneForGroup, aS as pointCellInRect, aT as pointCellInSpatialZone, aU as pointCellInZone, aV as primaryZoneForGroup, aW as sortNodeRefsForSerializedFetch, aX as spatialZoneBounds, aY as spatialZoneCenter, aZ as streetFromPoolEntry, a_ as zonesForGroup } from './browser-Dpx-0L8A.js';
3
3
  import { WorldIntercomEventPayload, IntercomResponsePayload } from '@agent-play/intercom';
4
- export { AgentPlayAgentNodeEntry, AgentPlayCredentialsFile, loadAgentPlayCredentialsFileFromPath, loadAgentPlayCredentialsFileFromPathSync, loadRootKey, nodeCredentialsMaterialFromHumanPassphrase, parseAgentPlayCredentialsJson, resolveAgentPlayCredentialsPath } from '@agent-play/node-tools';
4
+ export { AgentPlayAgentNodeEntry, AgentPlayCredentialsFile, NodeCredentialMaterial, createNodeCredentialMaterial, loadAgentPlayCredentialsFileFromPath, loadAgentPlayCredentialsFileFromPathSync, loadRootKey, nodeCredentialFromHumanPhrase, nodeCredentialFromPasswHash, nodeCredentialsMaterialFromHumanPassphrase, parseAgentPlayCredentialsJson, resolveAgentPlayCredentialsPath, verifyStoredNodeCredential } from '@agent-play/node-tools';
5
+ import 'zod';
5
6
 
6
7
  /**
7
8
  * String constants and payload shapes for SSE and in-process world events.
@@ -111,8 +112,9 @@ declare function langchainRegistration(agent: unknown): LangChainAgentRegistrati
111
112
 
112
113
  /**
113
114
  * Root key (from `.root`) plus **human** passphrase as stored in **`~/.agent-play/credentials.json`**
114
- * after **`agent-play create-main-node`**. Material for node id and wire auth is
115
- * **`nodeCredentialsMaterialFromHumanPassphrase(passw)`** (SHA-256 hex; same as CLI **`hashNodePassword`**).
115
+ * after **`agent-play create-main-node`**. The SDK hashes the phrase once locally via
116
+ * **`nodeCredentialFromHumanPhrase`** and sends the resulting **`passwHash`** as the
117
+ * `x-node-passw` header and as the `passwHash` field in repository-backed requests.
116
118
  */
117
119
  type RemotePlayWorldNodeCredentials = {
118
120
  rootKey: string;
@@ -135,8 +137,8 @@ type RemotePlayWorldOptions = {
135
137
  /** Options for {@link RemotePlayWorld.connect}. */
136
138
  type RemotePlayWorldConnectOptions = {
137
139
  /**
138
- * Parent **main** node id. When set, `connect` runs `POST /api/nodes/validate` first, then `GET /api/agent-play/session`.
139
- * When omitted, only `GET /api/agent-play/session` runs.
140
+ * Main node id used for `POST /api/nodes/validate` as **`nodeId`** (not the derived credential id) and remembered for {@link RemotePlayWorld.addAgent} (`mainNodeId` on validate and register).
141
+ * When omitted, connect skips validate and addAgent uses the derived node id for main-parent fields.
140
142
  */
141
143
  mainNodeId?: string;
142
144
  };
@@ -180,11 +182,12 @@ declare class RemotePlayWorld {
180
182
  private readonly rootKey;
181
183
  /** Node id derived from hashed passphrase material + root (main or agent node id). */
182
184
  private readonly derivedNodeId;
183
- /** Hex password material (`hashNodePassword` on normalized human phrase); sent as `password` for repository addAgent. */
184
- private readonly password;
185
+ /** Hex SHA-256 of the normalized human phrase; sent as `x-node-passw` and as `passwHash`. */
186
+ private readonly passwHash;
185
187
  private readonly onSessionEvent;
186
188
  private readonly transportLog;
187
189
  private sid;
190
+ private configuredMainNodeId;
188
191
  private closed;
189
192
  private readonly closeListeners;
190
193
  private readonly playerConnectionInfo;
@@ -201,7 +204,7 @@ declare class RemotePlayWorld {
201
204
  private validateNodeIdentity;
202
205
  /**
203
206
  * Establishes the HTTP session via `GET /api/agent-play/session`. With {@link RemotePlayWorldConnectOptions.mainNodeId},
204
- * validates node identity with `POST /api/nodes/validate` first.
207
+ * validates that node with `POST /api/nodes/validate` using **`nodeId: mainNodeId`** first.
205
208
  */
206
209
  connect(options?: RemotePlayWorldConnectOptions): Promise<void>;
207
210
  close(): Promise<void>;
@@ -232,6 +235,8 @@ declare class RemotePlayWorld {
232
235
  /**
233
236
  * Registers an automation agent using **agent node id** (`nodeId`), sent to the server as `agentId`.
234
237
  *
238
+ * Runs `POST /api/nodes/validate` with **`nodeId`** / **`mainNodeId`** from {@link AddAgentInput} before registering.
239
+ *
235
240
  * If {@link initAudio} was called and **`enableP2a`** is **`"on"`**, this call mints a per-agent
236
241
  * OpenAI Realtime client secret and forwards it as `realtimeWebrtc`.
237
242
  */
package/dist/index.js CHANGED
@@ -1,19 +1,73 @@
1
1
  import {
2
+ CONTINUOUS_RENDER_OFFSET,
3
+ CarWashCarSchema,
4
+ DEFAULT_AGENT_SPAWN_MIN_DISTANCE,
5
+ DEFAULT_PLAYER_WALLET_BALANCE_USD,
2
6
  MINIMUM_PLAY_WORLD_BOUNDS,
7
+ OCCUPANCY_POINT_MULTIPLIER,
3
8
  PLAYER_CHAIN_GENESIS_STABLE_KEY,
4
9
  PLAYER_CHAIN_HEADER_STABLE_KEY,
10
+ PlayerWalletSchema,
11
+ PurchaseRecordSchema,
12
+ SPATIAL_ZONE_INDEX_AGENTS,
13
+ SPATIAL_ZONE_INDEX_SPACES,
14
+ STREET_NAME_POOL,
15
+ SaleStateSchema,
16
+ ShopItemSchema,
17
+ SupermarketItemSchema,
18
+ applyBoundsFieldUpdateToLayout,
19
+ availableCellsForZone,
20
+ boundingWorldRectForOccupancyPoints,
5
21
  boundsContain,
22
+ buildRankedOccupancyPoints,
23
+ buildRankedOccupancyPointsForSpatialZone,
24
+ buildRankedOccupancyPointsForZone,
25
+ buildRankedOccupancyPointsInRect,
26
+ cellsForZone,
27
+ centerOfZone,
6
28
  clampWorldPosition,
29
+ createInitialPlayerWallet,
30
+ createVerticalStripSeedLayout,
31
+ desaturateColor,
32
+ enumerateIntegerCellsInRect,
7
33
  expandBoundsToMinimumPlayArea,
34
+ getStreetPoolEntryById,
35
+ isAgentSpawnOccupancyPointAvailable,
36
+ isAgentSpawnOccupancyPointAvailableInRect,
37
+ isAgentSpawnOccupancyPointAvailableInZone,
38
+ isItemAvailableForPurchase,
39
+ isSpaceAnchorOccupancyPointAvailable,
40
+ isSpaceAnchorOccupancyPointAvailableInRect,
41
+ isSpaceAnchorOccupancyPointAvailableInZone,
42
+ listAllowedOccupancyPoints,
43
+ listOccupancyPointsForSpatialZone,
44
+ listOccupancyPointsForZone,
45
+ listOccupancyPointsInRect,
8
46
  mergeSnapshotWithPlayerChainNode,
47
+ migrateWorldLayoutBounds,
48
+ nextStreetFromPool,
49
+ occupancyKeyForPosition,
50
+ occupancyPointsGroupedBySpatialZone,
51
+ occupancyPointsGroupedByZones,
9
52
  parseAgentOccupantRow,
10
53
  parseHumanOccupantRow,
11
54
  parseMcpOccupantRow,
12
55
  parsePlayerChainFanoutNotify,
13
56
  parsePlayerChainFanoutNotifyFromSsePayload,
14
57
  parsePlayerChainNodeRpcBody,
15
- sortNodeRefsForSerializedFetch
16
- } from "./chunk-U2M7HNYN.js";
58
+ parseSpaceCatalogEntry,
59
+ parseStructureOccupantRow,
60
+ pickZoneForGroup,
61
+ pointCellInRect,
62
+ pointCellInSpatialZone,
63
+ pointCellInZone,
64
+ primaryZoneForGroup,
65
+ sortNodeRefsForSerializedFetch,
66
+ spatialZoneBounds,
67
+ spatialZoneCenter,
68
+ streetFromPoolEntry,
69
+ zonesForGroup
70
+ } from "./chunk-VWC7EE2F.js";
17
71
 
18
72
  // src/world-events.ts
19
73
  var SESSION_CONNECTED_EVENT = "session:connected";
@@ -90,17 +144,20 @@ function unwrapZodCell(cell) {
90
144
  if (current === null || typeof current !== "object") {
91
145
  return current;
92
146
  }
93
- const def = current._def;
94
- if (!def || typeof def.typeName !== "string") {
147
+ const def = current._def ?? current.def;
148
+ if (!def) {
95
149
  return current;
96
150
  }
97
- const { typeName } = def;
98
- if (typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault") {
151
+ const typeName = typeof def.typeName === "string" ? def.typeName : typeof def.type === "string" ? def.type : void 0;
152
+ if (typeName === void 0) {
153
+ return current;
154
+ }
155
+ if (typeName === "ZodOptional" || typeName === "ZodNullable" || typeName === "ZodDefault" || typeName === "optional" || typeName === "nullable" || typeName === "default") {
99
156
  const inner = def.innerType;
100
157
  current = inner !== null && typeof inner === "object" ? inner : void 0;
101
158
  continue;
102
159
  }
103
- if (typeName === "ZodEffects") {
160
+ if (typeName === "ZodEffects" || typeName === "effects") {
104
161
  current = def.schema;
105
162
  continue;
106
163
  }
@@ -113,14 +170,18 @@ function fieldTypeFromZodCell(cell) {
113
170
  if (base === null || typeof base !== "object") {
114
171
  return "string";
115
172
  }
116
- const typeName = base._def?.typeName;
117
- if (typeName === "ZodNumber") {
173
+ const def = base._def ?? base.def;
174
+ const typeName = def?.typeName;
175
+ const fallbackType = def?.type;
176
+ const ctorName = base.constructor?.name ?? "";
177
+ const kind = typeName ?? fallbackType ?? ctorName;
178
+ if (kind === "ZodNumber" || kind === "number") {
118
179
  return "number";
119
180
  }
120
- if (typeName === "ZodBoolean") {
181
+ if (kind === "ZodBoolean" || kind === "boolean") {
121
182
  return "boolean";
122
183
  }
123
- if (typeName === "ZodString") {
184
+ if (kind === "ZodString" || kind === "string") {
124
185
  return "string";
125
186
  }
126
187
  return "string";
@@ -130,10 +191,11 @@ function parametersFromSchema(schema) {
130
191
  return {};
131
192
  }
132
193
  const z = schema;
133
- if (typeof z._def?.shape !== "function") {
194
+ const shapeRaw = z._def?.shape;
195
+ const shape = typeof shapeRaw === "function" ? shapeRaw() : shapeRaw !== void 0 && typeof shapeRaw === "object" ? shapeRaw : null;
196
+ if (shape === null) {
134
197
  return { _note: "Pass a Zod object schema on each tool for parameter hints in the watch UI." };
135
198
  }
136
- const shape = z._def.shape();
137
199
  const out = {};
138
200
  for (const key of Object.keys(shape)) {
139
201
  out[key] = {
@@ -188,10 +250,9 @@ function langchainRegistration(agent) {
188
250
  // src/lib/remote-play-world.ts
189
251
  import { randomUUID } from "crypto";
190
252
  import {
191
- deriveNodeIdFromPassword,
192
253
  loadAgentPlayCredentialsFileFromPathSync,
193
254
  loadRootKey,
194
- nodeCredentialsMaterialFromHumanPassphrase,
255
+ nodeCredentialFromHumanPhrase,
195
256
  resolveAgentPlayCredentialsPath
196
257
  } from "@agent-play/node-tools";
197
258
  import { HumanMessage } from "@langchain/core/messages";
@@ -255,6 +316,10 @@ function resolveRealtimeInstructions(options) {
255
316
  if (explicit !== void 0 && explicit.length > 0) {
256
317
  return explicit;
257
318
  }
319
+ const perAgent = options.perAgentInstructions?.trim();
320
+ if (perAgent !== void 0 && perAgent.length > 0) {
321
+ return perAgent;
322
+ }
258
323
  const template = options.openai.instructionsTemplate?.trim();
259
324
  if (template !== void 0 && template.length > 0) {
260
325
  return template.replaceAll("{{agentName}}", options.agentName);
@@ -357,9 +422,9 @@ function parseWorldMap(raw) {
357
422
  const occupants = [];
358
423
  const coordKeys = /* @__PURE__ */ new Set();
359
424
  for (const row of occ) {
360
- if (!isRecord(row) || row.kind !== "human" && row.kind !== "agent" && row.kind !== "mcp") {
425
+ if (!isRecord(row) || row.kind !== "human" && row.kind !== "agent" && row.kind !== "mcp" && row.kind !== "structure") {
361
426
  throw new Error(
362
- "getWorldSnapshot: each occupant must have kind human, agent, or mcp"
427
+ "getWorldSnapshot: each occupant must have kind human, agent, mcp, or structure"
363
428
  );
364
429
  }
365
430
  const xy = typeof row.x === "number" && typeof row.y === "number" ? `${row.x},${row.y}` : "";
@@ -374,8 +439,10 @@ function parseWorldMap(raw) {
374
439
  occupants.push(parseHumanOccupantRow(row));
375
440
  } else if (row.kind === "agent") {
376
441
  occupants.push(parseAgentOccupantRow(row));
377
- } else {
442
+ } else if (row.kind === "mcp") {
378
443
  occupants.push(parseMcpOccupantRow(row));
444
+ } else {
445
+ occupants.push(parseStructureOccupantRow(row));
379
446
  }
380
447
  }
381
448
  return { bounds, occupants };
@@ -386,6 +453,12 @@ function parseAgentPlaySnapshot(snapshot) {
386
453
  }
387
454
  const worldMap = parseWorldMap(snapshot.worldMap);
388
455
  const out = { sid: snapshot.sid, worldMap };
456
+ if ("worldLayout" in snapshot && isRecord(snapshot.worldLayout)) {
457
+ const wl = snapshot.worldLayout;
458
+ if (typeof wl.rev === "number" && isRecord(wl.bounds) && Array.isArray(wl.zones) && Array.isArray(wl.streets)) {
459
+ out.worldLayout = wl;
460
+ }
461
+ }
389
462
  if ("mcpServers" in snapshot && Array.isArray(snapshot.mcpServers)) {
390
463
  const servers = [];
391
464
  for (const m of snapshot.mcpServers) {
@@ -401,6 +474,18 @@ function parseAgentPlaySnapshot(snapshot) {
401
474
  }
402
475
  if (servers.length > 0) out.mcpServers = servers;
403
476
  }
477
+ if ("spaces" in snapshot && Array.isArray(snapshot.spaces)) {
478
+ const catalog = [];
479
+ for (const row of snapshot.spaces) {
480
+ if (!isRecord(row)) {
481
+ continue;
482
+ }
483
+ catalog.push(parseSpaceCatalogEntry(row));
484
+ }
485
+ if (catalog.length > 0) {
486
+ out.spaces = catalog.sort((a, b) => a.id.localeCompare(b.id));
487
+ }
488
+ }
404
489
  return out;
405
490
  }
406
491
  function parseRegisteredAgentSummary(raw) {
@@ -510,11 +595,12 @@ var RemotePlayWorld = class {
510
595
  rootKey;
511
596
  /** Node id derived from hashed passphrase material + root (main or agent node id). */
512
597
  derivedNodeId;
513
- /** Hex password material (`hashNodePassword` on normalized human phrase); sent as `password` for repository addAgent. */
514
- password;
598
+ /** Hex SHA-256 of the normalized human phrase; sent as `x-node-passw` and as `passwHash`. */
599
+ passwHash;
515
600
  onSessionEvent;
516
601
  transportLog;
517
602
  sid = null;
603
+ configuredMainNodeId = null;
518
604
  closed = false;
519
605
  closeListeners = /* @__PURE__ */ new Set();
520
606
  playerConnectionInfo = /* @__PURE__ */ new Map();
@@ -533,12 +619,12 @@ var RemotePlayWorld = class {
533
619
  const nc = options.nodeCredentials ?? (creds === null ? void 0 : { rootKey: loadRootKey(), passw: creds.passw });
534
620
  if (nc !== void 0 && typeof nc.rootKey === "string" && nc.rootKey.trim().length > 0 && typeof nc.passw === "string" && nc.passw.length > 0) {
535
621
  this.rootKey = nc.rootKey.trim().toLowerCase();
536
- const material = nodeCredentialsMaterialFromHumanPassphrase(nc.passw);
537
- this.password = material;
538
- this.derivedNodeId = deriveNodeIdFromPassword({
539
- password: material,
622
+ const credential = nodeCredentialFromHumanPhrase({
623
+ phrase: nc.passw,
540
624
  rootKey: this.rootKey
541
625
  });
626
+ this.passwHash = credential.passwHash;
627
+ this.derivedNodeId = credential.nodeId;
542
628
  return;
543
629
  }
544
630
  throw new Error(formatMissingCredentialsError());
@@ -581,7 +667,7 @@ var RemotePlayWorld = class {
581
667
  authHeaders() {
582
668
  return {
583
669
  "x-node-id": this.derivedNodeId,
584
- "x-node-passw": this.password
670
+ "x-node-passw": this.passwHash
585
671
  };
586
672
  }
587
673
  jsonHeaders() {
@@ -630,18 +716,21 @@ var RemotePlayWorld = class {
630
716
  }
631
717
  /**
632
718
  * Establishes the HTTP session via `GET /api/agent-play/session`. With {@link RemotePlayWorldConnectOptions.mainNodeId},
633
- * validates node identity with `POST /api/nodes/validate` first.
719
+ * validates that node with `POST /api/nodes/validate` using **`nodeId: mainNodeId`** first.
634
720
  */
635
721
  async connect(options) {
636
722
  const mainNodeIdOpt = options?.mainNodeId?.trim();
637
723
  if (mainNodeIdOpt !== void 0 && mainNodeIdOpt.length > 0) {
724
+ this.configuredMainNodeId = mainNodeIdOpt;
638
725
  const validation = await this.validateNodeIdentity({
639
- nodeId: this.derivedNodeId,
640
- mainNodeId: mainNodeIdOpt
726
+ nodeId: mainNodeIdOpt,
727
+ mainNodeId: void 0
641
728
  });
642
729
  console.info(
643
730
  `[agent-play] Node identity validated (${validation.nodeKind ?? "unknown"}).`
644
731
  );
732
+ } else {
733
+ this.configuredMainNodeId = null;
645
734
  }
646
735
  const res = await fetch(`${this.apiBase}/api/agent-play/session`, {
647
736
  headers: this.authHeaders()
@@ -854,15 +943,16 @@ var RemotePlayWorld = class {
854
943
  /**
855
944
  * Registers an automation agent using **agent node id** (`nodeId`), sent to the server as `agentId`.
856
945
  *
946
+ * Runs `POST /api/nodes/validate` with **`nodeId`** / **`mainNodeId`** from {@link AddAgentInput} before registering.
947
+ *
857
948
  * If {@link initAudio} was called and **`enableP2a`** is **`"on"`**, this call mints a per-agent
858
949
  * OpenAI Realtime client secret and forwards it as `realtimeWebrtc`.
859
950
  */
860
951
  async addAgent(input) {
861
952
  const sid = this.getSessionId();
862
- const effectiveMainNodeId = this.derivedNodeId;
863
953
  const validation = await this.validateNodeIdentity({
864
954
  nodeId: input.nodeId,
865
- mainNodeId: effectiveMainNodeId
955
+ mainNodeId: input.mainNodeId
866
956
  });
867
957
  console.info(
868
958
  [
@@ -870,44 +960,42 @@ var RemotePlayWorld = class {
870
960
  ` status : validated`,
871
961
  ` nodeId : ${input.nodeId}`,
872
962
  ` nodeKind : ${validation.nodeKind ?? "unknown"}`,
873
- ` mainNode : ${effectiveMainNodeId}`
963
+ ` mainNode : ${input.mainNodeId ?? "n/a"}`
874
964
  ].join("\n")
875
965
  );
876
966
  const url = `${this.apiBase}/api/agent-play/players?sid=${encodeURIComponent(sid)}`;
877
967
  const connectionId = randomUUID();
878
968
  const leaseTtlSeconds = 45;
879
969
  let realtimeWebrtcFromInit;
880
- let realtimeInstructionsFromInit;
970
+ let resolvedRealtimeInstructions;
881
971
  if (input.enableP2a === "on" && this.audioInitOptions !== null) {
882
- console.log("resolving realtime instructions for agent", input.name);
883
- realtimeInstructionsFromInit = resolveRealtimeInstructions({
972
+ const resolveOpts = {
884
973
  openai: this.audioInitOptions,
885
- agentName: input.name
886
- });
887
- realtimeWebrtcFromInit = await mintOpenAiRealtimeClientSecretForSdk({
888
- openai: this.audioInitOptions,
889
- agentName: input.name
890
- });
974
+ agentName: input.name,
975
+ perAgentInstructions: input.realtimeInstructions ?? ""
976
+ };
977
+ resolvedRealtimeInstructions = resolveRealtimeInstructions(resolveOpts);
978
+ realtimeWebrtcFromInit = await mintOpenAiRealtimeClientSecretForSdk(resolveOpts);
891
979
  this.logTransport("addAgent:p2a_enabled", {
892
980
  agentName: input.name,
893
981
  model: this.audioInitOptions.model,
894
982
  voice: this.audioInitOptions.voice
895
983
  });
896
984
  }
897
- console.log("realtimeWebrtcFromInit", realtimeWebrtcFromInit);
898
- console.log("realtimeInstructionsFromInit", realtimeInstructionsFromInit);
985
+ const callerRealtimeInstructions = typeof input.realtimeInstructions === "string" && input.realtimeInstructions.trim().length > 0 ? input.realtimeInstructions : void 0;
986
+ const forwardedRealtimeInstructions = resolvedRealtimeInstructions ?? callerRealtimeInstructions;
899
987
  const requestPayload = {
900
988
  name: input.name,
901
989
  type: input.type,
902
990
  agent: input.agent,
903
- mainNodeId: effectiveMainNodeId,
904
- password: this.password,
991
+ mainNodeId: input.mainNodeId,
992
+ passwHash: this.passwHash,
905
993
  agentId: input.nodeId,
906
994
  connectionId,
907
995
  leaseTtlSeconds,
908
996
  ...input.enableP2a !== void 0 ? { enableP2a: input.enableP2a } : {},
909
997
  ...realtimeWebrtcFromInit !== void 0 ? { realtimeWebrtc: realtimeWebrtcFromInit } : {},
910
- ...realtimeInstructionsFromInit !== void 0 ? { realtimeInstructions: realtimeInstructionsFromInit } : {}
998
+ ...forwardedRealtimeInstructions !== void 0 ? { realtimeInstructions: forwardedRealtimeInstructions } : {}
911
999
  };
912
1000
  this.logTransport("addAgent:request_payload", {
913
1001
  url,
@@ -1009,6 +1097,9 @@ var RemotePlayWorld = class {
1009
1097
  if (input.mainNodeId !== void 0) {
1010
1098
  payload.mainNodeId = input.mainNodeId;
1011
1099
  }
1100
+ if (input.realtimeInstructions !== void 0) {
1101
+ payload.realtimeInstructions = input.realtimeInstructions;
1102
+ }
1012
1103
  return this.addAgent(payload);
1013
1104
  }
1014
1105
  async recordInteraction(input) {
@@ -1363,46 +1454,106 @@ var RemotePlayWorld = class {
1363
1454
 
1364
1455
  // src/index.ts
1365
1456
  import {
1457
+ createNodeCredentialMaterial,
1366
1458
  loadAgentPlayCredentialsFileFromPath,
1367
1459
  loadAgentPlayCredentialsFileFromPathSync as loadAgentPlayCredentialsFileFromPathSync2,
1368
1460
  loadRootKey as loadRootKey2,
1369
- nodeCredentialsMaterialFromHumanPassphrase as nodeCredentialsMaterialFromHumanPassphrase2,
1461
+ nodeCredentialFromHumanPhrase as nodeCredentialFromHumanPhrase2,
1462
+ nodeCredentialFromPasswHash,
1463
+ nodeCredentialsMaterialFromHumanPassphrase,
1370
1464
  parseAgentPlayCredentialsJson,
1371
- resolveAgentPlayCredentialsPath as resolveAgentPlayCredentialsPath2
1465
+ resolveAgentPlayCredentialsPath as resolveAgentPlayCredentialsPath2,
1466
+ verifyStoredNodeCredential
1372
1467
  } from "@agent-play/node-tools";
1373
1468
  export {
1469
+ CONTINUOUS_RENDER_OFFSET,
1470
+ CarWashCarSchema,
1471
+ DEFAULT_AGENT_SPAWN_MIN_DISTANCE,
1472
+ DEFAULT_PLAYER_WALLET_BALANCE_USD,
1374
1473
  MINIMUM_PLAY_WORLD_BOUNDS,
1474
+ OCCUPANCY_POINT_MULTIPLIER,
1375
1475
  PLAYER_ADDED_EVENT,
1376
1476
  PLAYER_CHAIN_GENESIS_STABLE_KEY,
1377
1477
  PLAYER_CHAIN_HEADER_STABLE_KEY,
1478
+ PlayerWalletSchema,
1479
+ PurchaseRecordSchema,
1378
1480
  RemotePlayWorld,
1379
1481
  SESSION_CLOSED_EVENT,
1380
1482
  SESSION_CONNECTED_EVENT,
1381
1483
  SESSION_INVALID_EVENT,
1382
1484
  SESSION_SSE_ERROR_EVENT,
1383
1485
  SESSION_SSE_OPEN_EVENT,
1486
+ SPATIAL_ZONE_INDEX_AGENTS,
1487
+ SPATIAL_ZONE_INDEX_SPACES,
1488
+ STREET_NAME_POOL,
1489
+ SaleStateSchema,
1490
+ ShopItemSchema,
1491
+ SupermarketItemSchema,
1384
1492
  WORLD_AGENT_SIGNAL_EVENT,
1385
1493
  WORLD_INTERACTION_EVENT,
1386
1494
  WORLD_JOURNEY_EVENT,
1387
1495
  agentPlayDebug,
1496
+ applyBoundsFieldUpdateToLayout,
1497
+ availableCellsForZone,
1498
+ boundingWorldRectForOccupancyPoints,
1388
1499
  boundsContain,
1500
+ buildRankedOccupancyPoints,
1501
+ buildRankedOccupancyPointsForSpatialZone,
1502
+ buildRankedOccupancyPointsForZone,
1503
+ buildRankedOccupancyPointsInRect,
1504
+ cellsForZone,
1505
+ centerOfZone,
1389
1506
  clampWorldPosition,
1390
1507
  configureAgentPlayDebug,
1508
+ createInitialPlayerWallet,
1509
+ createNodeCredentialMaterial,
1510
+ createVerticalStripSeedLayout,
1511
+ desaturateColor,
1512
+ enumerateIntegerCellsInRect,
1391
1513
  expandBoundsToMinimumPlayArea,
1514
+ getStreetPoolEntryById,
1392
1515
  intercomResultRecordFromLangChainInvokeOutput,
1393
1516
  isAgentPlayDebugEnabled,
1517
+ isAgentSpawnOccupancyPointAvailable,
1518
+ isAgentSpawnOccupancyPointAvailableInRect,
1519
+ isAgentSpawnOccupancyPointAvailableInZone,
1520
+ isItemAvailableForPurchase,
1521
+ isSpaceAnchorOccupancyPointAvailable,
1522
+ isSpaceAnchorOccupancyPointAvailableInRect,
1523
+ isSpaceAnchorOccupancyPointAvailableInZone,
1394
1524
  langchainRegistration,
1525
+ listAllowedOccupancyPoints,
1526
+ listOccupancyPointsForSpatialZone,
1527
+ listOccupancyPointsForZone,
1528
+ listOccupancyPointsInRect,
1395
1529
  loadAgentPlayCredentialsFileFromPath,
1396
1530
  loadAgentPlayCredentialsFileFromPathSync2 as loadAgentPlayCredentialsFileFromPathSync,
1397
1531
  loadRootKey2 as loadRootKey,
1398
1532
  mergeSnapshotWithPlayerChainNode,
1399
- nodeCredentialsMaterialFromHumanPassphrase2 as nodeCredentialsMaterialFromHumanPassphrase,
1533
+ migrateWorldLayoutBounds,
1534
+ nextStreetFromPool,
1535
+ nodeCredentialFromHumanPhrase2 as nodeCredentialFromHumanPhrase,
1536
+ nodeCredentialFromPasswHash,
1537
+ nodeCredentialsMaterialFromHumanPassphrase,
1538
+ occupancyKeyForPosition,
1539
+ occupancyPointsGroupedBySpatialZone,
1540
+ occupancyPointsGroupedByZones,
1400
1541
  parseAgentPlayCredentialsJson,
1401
1542
  parsePlayerChainFanoutNotify,
1402
1543
  parsePlayerChainFanoutNotifyFromSsePayload,
1403
1544
  parsePlayerChainNodeRpcBody,
1545
+ pickZoneForGroup,
1546
+ pointCellInRect,
1547
+ pointCellInSpatialZone,
1548
+ pointCellInZone,
1549
+ primaryZoneForGroup,
1404
1550
  resetAgentPlayDebug,
1405
1551
  resolveAgentPlayCredentialsPath2 as resolveAgentPlayCredentialsPath,
1406
- sortNodeRefsForSerializedFetch
1552
+ sortNodeRefsForSerializedFetch,
1553
+ spatialZoneBounds,
1554
+ spatialZoneCenter,
1555
+ streetFromPoolEntry,
1556
+ verifyStoredNodeCredential,
1557
+ zonesForGroup
1407
1558
  };
1408
1559
  //# sourceMappingURL=index.js.map