@voicethere/agent 0.7.13 → 0.8.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.
Files changed (58) hide show
  1. package/README.md +14 -3
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/runtime.d.ts.map +1 -1
  7. package/dist/runtime.js +11 -2
  8. package/dist/runtime.js.map +1 -1
  9. package/dist/templates/echo/agent.js +1 -1
  10. package/dist/templates/echo-dc/agent.js +1 -1
  11. package/dist/templates/game-sync/agent.js +162 -125
  12. package/dist/templates/registry.d.ts +1 -1
  13. package/dist/templates/registry.d.ts.map +1 -1
  14. package/dist/templates/registry.js +42 -26
  15. package/dist/templates/registry.js.map +1 -1
  16. package/dist/templates/voice-starter/agent.js +1 -1
  17. package/dist/templates/webhooks/agent.js +2 -2
  18. package/dist/templates/webhooks-redis/agent.js +11 -4
  19. package/dist/templates/world-sync/agent.js +829 -0
  20. package/dist/templates/world-sync-binary/agent.js +1031 -0
  21. package/package.json +3 -2
  22. package/templates/README.md +41 -69
  23. package/templates/crash/README.md +13 -0
  24. package/templates/echo/README.md +13 -0
  25. package/templates/{echo.ts → echo/agent.ts} +1 -1
  26. package/templates/echo-dc/README.md +13 -0
  27. package/templates/{echo-dc.ts → echo-dc/agent.ts} +1 -1
  28. package/templates/echo-smoke/README.md +13 -0
  29. package/templates/game-sync/README.md +21 -0
  30. package/templates/{game-sync.ts → game-sync/agent.ts} +126 -94
  31. package/templates/{game-sync-redis.ts → game-sync/redis.ts} +4 -13
  32. package/templates/{game-sync-sim.ts → game-sync/sim.ts} +14 -7
  33. package/templates/{game-sync-world-layout.ts → game-sync/world-layout.ts} +72 -30
  34. package/templates/game-sync-smoke/README.md +13 -0
  35. package/templates/mix-smoke/README.md +13 -0
  36. package/templates/positional-tts/README.md +13 -0
  37. package/templates/recording-consent/README.md +13 -0
  38. package/templates/redis-sync/README.md +23 -0
  39. package/templates/redis-sync/agent.ts +72 -95
  40. package/templates/redis-sync/world-layout.ts +103 -26
  41. package/templates/spatial-showcase/README.md +13 -0
  42. package/templates/voice-showcase/README.md +13 -0
  43. package/templates/voice-starter/README.md +13 -0
  44. package/templates/webhooks/README.md +13 -0
  45. package/templates/{webhooks.ts → webhooks/agent.ts} +1 -1
  46. package/templates/webhooks-redis/README.md +13 -0
  47. package/templates/{webhooks-redis.ts → webhooks-redis/agent.ts} +9 -9
  48. package/templates/world-sync/README.md +20 -0
  49. package/templates/world-sync/agent.ts +62 -0
  50. package/templates/world-sync-binary/README.md +21 -0
  51. package/templates/world-sync-binary/agent.ts +107 -0
  52. package/templates/world-sync-binary/protocol.ts +281 -0
  53. /package/templates/{crash.ts → crash/agent.ts} +0 -0
  54. /package/templates/{echo-smoke.ts → echo-smoke/agent.ts} +0 -0
  55. /package/templates/{game-sync-protocol.ts → game-sync/protocol.ts} +0 -0
  56. /package/templates/{game-sync-smoke.ts → game-sync-smoke/agent.ts} +0 -0
  57. /package/templates/{mix-smoke.ts → mix-smoke/agent.ts} +0 -0
  58. /package/templates/{agent.ts → voice-starter/agent.ts} +0 -0
@@ -10753,7 +10753,7 @@ var require_built3 = __commonJS({
10753
10753
  }
10754
10754
  });
10755
10755
 
10756
- // templates/game-sync.ts
10756
+ // templates/game-sync/agent.ts
10757
10757
  var import_ioredis = __toESM(require_built3(), 1);
10758
10758
 
10759
10759
  // dist/runtime.js
@@ -11477,14 +11477,19 @@ function buildIdleEnv(sessionId) {
11477
11477
  function sendToClient(sessionId, payload) {
11478
11478
  sendParentMessage({ type: "send_to_client", sessionId, payload });
11479
11479
  }
11480
- function sendBinaryToClient(sessionId, data, channel = "sync") {
11481
- const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
11482
- sendParentMessage({
11483
- type: "send_binary_to_client",
11484
- sessionId,
11485
- data: buffer,
11486
- channel
11487
- });
11480
+ function asOutboundBuffer(data) {
11481
+ return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
11482
+ }
11483
+ function broadCastBinaryToClients(data, sessionIds, channel = "sync") {
11484
+ const buffer = asOutboundBuffer(data);
11485
+ for (const sessionId of sessionIds) {
11486
+ sendParentMessage({
11487
+ type: "send_binary_to_client",
11488
+ sessionId,
11489
+ data: buffer,
11490
+ channel
11491
+ });
11492
+ }
11488
11493
  }
11489
11494
  var AGENT_LOG_MESSAGE_MAX_CHARS = 2048;
11490
11495
  var AGENT_LOG_FIELDS_MAX_CHARS = 8192;
@@ -11542,7 +11547,7 @@ function agentLog(level, message, fieldsOrSessionId, sessionId) {
11542
11547
  sendParentMessage(buildAgentLogPayload(level, message, fields, resolvedSessionId));
11543
11548
  }
11544
11549
 
11545
- // templates/game-sync-protocol.ts
11550
+ // templates/game-sync/protocol.ts
11546
11551
  var MAX_LIVE_OBJECTS = 25;
11547
11552
  var REGISTER_NACK_REASON_WORLD_FULL = "world_full";
11548
11553
  var UNREGISTER_NACK_REASON_NOT_FOUND = "not_found";
@@ -11586,7 +11591,7 @@ function parseChatCommand(message) {
11586
11591
  return { text };
11587
11592
  }
11588
11593
 
11589
- // templates/game-sync-world-layout.ts
11594
+ // templates/game-sync/world-layout.ts
11590
11595
  var OBJECT_STRIDE = 9;
11591
11596
  var WORLD_FLOAT_COUNT = MAX_LIVE_OBJECTS * OBJECT_STRIDE;
11592
11597
  var WORLD_BYTE_LENGTH = WORLD_FLOAT_COUNT * 4;
@@ -11629,6 +11634,12 @@ function markSlotFree(world, slot) {
11629
11634
  world[start + i] = 0;
11630
11635
  }
11631
11636
  }
11637
+ var OBJECT_SLOT_SCRATCH = new Float32Array(OBJECT_STRIDE);
11638
+ var OBJECT_SLOT_SCRATCH_BUF = Buffer.from(
11639
+ OBJECT_SLOT_SCRATCH.buffer,
11640
+ OBJECT_SLOT_SCRATCH.byteOffset,
11641
+ OBJECT_SLOT_BYTE_LENGTH
11642
+ );
11632
11643
  function writeObjectSlot(world, slot, objectId, posX, posY, posZ, posW, dirX, dirY, dirZ, dirW) {
11633
11644
  const start = slot * OBJECT_STRIDE;
11634
11645
  world[start] = objectId;
@@ -11651,6 +11662,18 @@ function collectActiveObjectIds(world) {
11651
11662
  }
11652
11663
  return ids;
11653
11664
  }
11665
+ function collectActiveObjectIdsInto(world, dest) {
11666
+ let count = 0;
11667
+ const limit = Math.min(MAX_LIVE_OBJECTS, dest.length);
11668
+ for (let slot = 0; slot < MAX_LIVE_OBJECTS && count < limit; slot += 1) {
11669
+ const objectId = readSlotObjectId(world, slot);
11670
+ if (objectId !== 0) {
11671
+ dest[count] = objectId;
11672
+ count += 1;
11673
+ }
11674
+ }
11675
+ return count;
11676
+ }
11654
11677
  function liveWorldSnapshot(world, owners) {
11655
11678
  const ids = collectActiveObjectIds(world);
11656
11679
  ids.sort((a, b) => a - b);
@@ -11677,39 +11700,37 @@ function clampSimulationDtSec(elapsedMs, fallbackHz) {
11677
11700
  const elapsedSec = elapsedMs / 1e3;
11678
11701
  return Math.min(maxDt, Math.max(minDt, elapsedSec));
11679
11702
  }
11680
- function normalizeWorldBuffer(raw) {
11703
+ function normalizeWorldBuffer(raw, dest = createEmptyWorldBuffer()) {
11704
+ const destBytes = new Uint8Array(
11705
+ dest.buffer,
11706
+ dest.byteOffset,
11707
+ dest.byteLength
11708
+ );
11681
11709
  if (!raw || raw.byteLength === 0) {
11682
- return createEmptyWorldBuffer();
11710
+ destBytes.fill(0);
11711
+ return dest;
11683
11712
  }
11684
- const bytes = Math.floor(raw.byteLength / 4) * 4;
11685
- if (bytes === 0) {
11686
- return createEmptyWorldBuffer();
11713
+ const byteCount = Math.min(
11714
+ Math.floor(raw.byteLength / 4) * 4,
11715
+ destBytes.byteLength
11716
+ );
11717
+ if (byteCount > 0) {
11718
+ destBytes.set(raw.subarray(0, byteCount));
11687
11719
  }
11688
- const aligned = raw.buffer.slice(raw.byteOffset, raw.byteOffset + bytes);
11689
- const decoded = new Float32Array(aligned);
11690
- if (decoded.length === WORLD_FLOAT_COUNT) {
11691
- return decoded;
11720
+ if (byteCount < destBytes.byteLength) {
11721
+ destBytes.fill(0, byteCount);
11692
11722
  }
11693
- const normalized = createEmptyWorldBuffer();
11694
- normalized.set(
11695
- decoded.subarray(0, Math.min(decoded.length, WORLD_FLOAT_COUNT))
11696
- );
11697
- return normalized;
11698
- }
11699
- function objectIdHeaderBytes(objectId) {
11700
- const header = new Float32Array([objectId]);
11701
- return Buffer.from(header.buffer, header.byteOffset, 4);
11723
+ return dest;
11702
11724
  }
11703
-
11704
- // templates/game-sync-redis.ts
11705
- function buildObjectIdHeadersBlob() {
11706
- const parts = [];
11725
+ var OBJECT_ID_HEADERS_BLOB = (() => {
11726
+ const blob = Buffer.alloc(MAX_LIVE_OBJECTS * 4);
11707
11727
  for (let objectId = 1; objectId <= MAX_LIVE_OBJECTS; objectId += 1) {
11708
- parts.push(objectIdHeaderBytes(objectId));
11728
+ blob.writeFloatLE(objectId, (objectId - 1) * 4);
11709
11729
  }
11710
- return Buffer.concat(parts);
11711
- }
11712
- var OBJECT_ID_HEADERS_BLOB = buildObjectIdHeadersBlob();
11730
+ return blob;
11731
+ })();
11732
+
11733
+ // templates/game-sync/redis.ts
11713
11734
  var LUA_ALLOCATE_OBJECT = `
11714
11735
  local key = KEYS[1]
11715
11736
  local size = tonumber(ARGV[1])
@@ -11797,14 +11818,15 @@ var REDIS_EVAL_KEYS = {
11797
11818
  headers: OBJECT_ID_HEADERS_BLOB
11798
11819
  };
11799
11820
 
11800
- // templates/game-sync-sim.ts
11821
+ // templates/game-sync/sim.ts
11801
11822
  var BOARD_WIDTH = 1280;
11802
11823
  var BOARD_HEIGHT = 720;
11803
11824
  var OBJECT_RADIUS = 25;
11804
11825
  var COLLISION_RESTITUTION = 1;
11805
11826
  var OBJECT_STRIDE2 = 9;
11806
- function simulateWorldStep(worldState2, dtSec, activeObjectIds) {
11807
- for (const objectId of activeObjectIds) {
11827
+ function simulateWorldStep(worldState2, dtSec, activeObjectIds2, count = activeObjectIds2.length) {
11828
+ for (let i = 0; i < count; i += 1) {
11829
+ const objectId = activeObjectIds2[i] ?? 0;
11808
11830
  const slot = objectIdToSlot(objectId);
11809
11831
  const start = slot * OBJECT_STRIDE2;
11810
11832
  if (start < 0 || start + OBJECT_STRIDE2 > worldState2.length) continue;
@@ -11827,13 +11849,13 @@ function simulateWorldStep(worldState2, dtSec, activeObjectIds) {
11827
11849
  worldState2[start + 5] = vx;
11828
11850
  worldState2[start + 6] = vy;
11829
11851
  }
11830
- for (let i = 0; i < activeObjectIds.length; i += 1) {
11831
- const aId = activeObjectIds[i];
11852
+ for (let i = 0; i < count; i += 1) {
11853
+ const aId = activeObjectIds2[i] ?? 0;
11832
11854
  const aSlot = objectIdToSlot(aId);
11833
11855
  const aStart = aSlot * OBJECT_STRIDE2;
11834
11856
  if (aStart < 0 || aStart + OBJECT_STRIDE2 > worldState2.length) continue;
11835
- for (let j = i + 1; j < activeObjectIds.length; j += 1) {
11836
- const bId = activeObjectIds[j];
11857
+ for (let j = i + 1; j < count; j += 1) {
11858
+ const bId = activeObjectIds2[j] ?? 0;
11837
11859
  const bSlot = objectIdToSlot(bId);
11838
11860
  const bStart = bSlot * OBJECT_STRIDE2;
11839
11861
  if (bStart < 0 || bStart + OBJECT_STRIDE2 > worldState2.length) continue;
@@ -11900,7 +11922,7 @@ function simulateWorldStep(worldState2, dtSec, activeObjectIds) {
11900
11922
  }
11901
11923
  }
11902
11924
 
11903
- // templates/game-sync.ts
11925
+ // templates/game-sync/agent.ts
11904
11926
  var BROADCAST_HZ = 60;
11905
11927
  var BROADCAST_INTERVAL_MS = Math.floor(1e3 / BROADCAST_HZ);
11906
11928
  var SIM_LOCK_TTL_MS = BROADCAST_INTERVAL_MS * 2;
@@ -11908,10 +11930,16 @@ var SIM_LOCK_RETRY_MS = 5;
11908
11930
  var MIN_SPEED = 90;
11909
11931
  var MAX_SPEED = 180;
11910
11932
  var connectedSessions = /* @__PURE__ */ new Set();
11933
+ var connectedSessionList = [];
11911
11934
  var objectOwners = /* @__PURE__ */ new Map();
11912
11935
  var sessionObjects = /* @__PURE__ */ new Map();
11913
11936
  var freeSlots = [];
11914
11937
  var worldState = createEmptyWorldBuffer();
11938
+ var worldStateBytes = Buffer.from(
11939
+ worldState.buffer,
11940
+ worldState.byteOffset,
11941
+ worldState.byteLength
11942
+ );
11915
11943
  var redis = null;
11916
11944
  var broadcastTimer = null;
11917
11945
  var worldMutationChain = Promise.resolve();
@@ -11961,18 +11989,22 @@ function rand(min, max) {
11961
11989
  function randomVelocity() {
11962
11990
  return (Math.random() < 0.5 ? -1 : 1) * rand(MIN_SPEED, MAX_SPEED);
11963
11991
  }
11992
+ var INITIAL_TAIL = new Float32Array(8);
11993
+ var INITIAL_TAIL_BUF = Buffer.from(
11994
+ INITIAL_TAIL.buffer,
11995
+ INITIAL_TAIL.byteOffset,
11996
+ INITIAL_TAIL.byteLength
11997
+ );
11964
11998
  function randomInitialTail() {
11965
- const floats = new Float32Array([
11966
- rand(OBJECT_RADIUS, BOARD_WIDTH - OBJECT_RADIUS),
11967
- rand(OBJECT_RADIUS, BOARD_HEIGHT - OBJECT_RADIUS),
11968
- 0,
11969
- 1,
11970
- randomVelocity(),
11971
- randomVelocity(),
11972
- 0,
11973
- 0
11974
- ]);
11975
- return Buffer.from(floats.buffer, floats.byteOffset, floats.byteLength);
11999
+ INITIAL_TAIL[0] = rand(OBJECT_RADIUS, BOARD_WIDTH - OBJECT_RADIUS);
12000
+ INITIAL_TAIL[1] = rand(OBJECT_RADIUS, BOARD_HEIGHT - OBJECT_RADIUS);
12001
+ INITIAL_TAIL[2] = 0;
12002
+ INITIAL_TAIL[3] = 1;
12003
+ INITIAL_TAIL[4] = randomVelocity();
12004
+ INITIAL_TAIL[5] = randomVelocity();
12005
+ INITIAL_TAIL[6] = 0;
12006
+ INITIAL_TAIL[7] = 0;
12007
+ return INITIAL_TAIL_BUF;
11976
12008
  }
11977
12009
  function attachObjectToSession(sessionId, objectId) {
11978
12010
  let owned = sessionObjects.get(sessionId);
@@ -12054,7 +12086,7 @@ async function registerObjectInRedis(sessionId) {
12054
12086
  return null;
12055
12087
  }
12056
12088
  attachObjectToSession(sessionId, objectId);
12057
- worldState = await loadWorldFromRedis();
12089
+ await loadWorldFromRedis();
12058
12090
  return objectId;
12059
12091
  }
12060
12092
  async function releaseObjectInRedis(objectId) {
@@ -12074,7 +12106,7 @@ async function releaseObjectInRedis(objectId) {
12074
12106
  REDIS_EVAL_KEYS.headers
12075
12107
  );
12076
12108
  if (Number(released) === 1) {
12077
- worldState = await loadWorldFromRedis();
12109
+ await loadWorldFromRedis();
12078
12110
  }
12079
12111
  return Number(released) === 1;
12080
12112
  }
@@ -12126,83 +12158,84 @@ function notifyObjectReleased(objectId, ownerSessionId) {
12126
12158
  });
12127
12159
  }
12128
12160
  }
12129
- function copyWorldBuffer(world) {
12130
- return Buffer.from(world.buffer, world.byteOffset, world.byteLength);
12131
- }
12132
- function broadcastWorldBuffer(world) {
12133
- if (connectedSessions.size === 0) return;
12134
- const payload = copyWorldBuffer(world);
12135
- for (const sessionId of connectedSessions) {
12136
- sendBinaryToClient(sessionId, payload, "sync");
12137
- }
12161
+ function broadcastWorldBuffer() {
12162
+ if (connectedSessionList.length === 0) return;
12163
+ broadCastBinaryToClients(worldStateBytes, connectedSessionList, "sync");
12138
12164
  }
12139
12165
  async function loadWorldFromRedis() {
12140
- if (!redis) {
12141
- return new Float32Array(worldState);
12142
- }
12166
+ if (!redis) return;
12143
12167
  const raw = await redis.getBuffer(REDIS_WORLD_KEY);
12144
- return normalizeWorldBuffer(raw);
12168
+ normalizeWorldBuffer(raw, worldState);
12145
12169
  }
12146
- async function saveWorldToRedis(world) {
12170
+ async function saveWorldToRedis() {
12147
12171
  if (!redis) return;
12148
- await redis.set(REDIS_WORLD_KEY, copyWorldBuffer(world));
12172
+ await redis.set(REDIS_WORLD_KEY, worldStateBytes);
12149
12173
  }
12150
- async function runSimulationTick() {
12174
+ var activeObjectIds = new Int32Array(MAX_LIVE_OBJECTS);
12175
+ var SIM_LOCK_TRY_ONCE = { retryUntilAcquired: false };
12176
+ var SIM_TICK_PLAN_INPUT = { lockAcquired: false, connectedSessions };
12177
+ function takeTickDtSec() {
12151
12178
  const now = Date.now();
12152
12179
  const dt = clampSimulationDtSec(
12153
12180
  lastTickTimeMs === 0 ? 0 : now - lastTickTimeMs,
12154
12181
  BROADCAST_HZ
12155
12182
  );
12156
12183
  lastTickTimeMs = now;
12184
+ return dt;
12185
+ }
12186
+ function stepWorldInPlace() {
12187
+ const dt = takeTickDtSec();
12188
+ const count = collectActiveObjectIdsInto(worldState, activeObjectIds);
12189
+ simulateWorldStep(worldState, dt, activeObjectIds, count);
12190
+ }
12191
+ async function stepWorldInMemory() {
12192
+ stepWorldInPlace();
12193
+ }
12194
+ async function stepWorldWithRedis() {
12195
+ await loadWorldFromRedis();
12196
+ stepWorldInPlace();
12197
+ await saveWorldToRedis();
12198
+ broadcastWorldBuffer();
12199
+ return true;
12200
+ }
12201
+ async function runRedisTick() {
12202
+ const lockResult = await withRedisSimLock(
12203
+ stepWorldWithRedis,
12204
+ SIM_LOCK_TRY_ONCE
12205
+ );
12206
+ if (lockResult !== null) return;
12207
+ takeTickDtSec();
12208
+ if (planRedisSimTick(SIM_TICK_PLAN_INPUT) === "relay") {
12209
+ await loadWorldFromRedis();
12210
+ broadcastWorldBuffer();
12211
+ }
12212
+ }
12213
+ async function runSimulationTick() {
12157
12214
  if (!redis) {
12158
- await withWorldMutation(async () => {
12159
- simulateWorldStep(worldState, dt, collectActiveObjectIds(worldState));
12160
- });
12161
- broadcastWorldBuffer(worldState);
12215
+ await withWorldMutation(stepWorldInMemory);
12216
+ broadcastWorldBuffer();
12162
12217
  return;
12163
12218
  }
12164
- await withWorldMutation(async () => {
12165
- const lockResult = await withRedisSimLock(
12166
- async () => {
12167
- const world = await loadWorldFromRedis();
12168
- const activeObjectIds = collectActiveObjectIds(world);
12169
- simulateWorldStep(world, dt, activeObjectIds);
12170
- await saveWorldToRedis(world);
12171
- worldState = world;
12172
- broadcastWorldBuffer(world);
12173
- return true;
12174
- },
12175
- { retryUntilAcquired: false }
12176
- );
12177
- if (lockResult === null) {
12178
- const plan = planRedisSimTick({
12179
- lockAcquired: false,
12180
- connectedSessions
12181
- });
12182
- if (plan === "relay") {
12183
- const world = await loadWorldFromRedis();
12184
- worldState = world;
12185
- broadcastWorldBuffer(world);
12186
- }
12219
+ await withWorldMutation(runRedisTick);
12220
+ }
12221
+ function logTickError(error) {
12222
+ const detail = error instanceof Error ? error.message : String(error);
12223
+ agentLog("error", `world tick failed: ${detail}`);
12224
+ }
12225
+ function onBroadcastTick() {
12226
+ if (!redis && connectedSessions.size < 1) {
12227
+ if (broadcastTimer) {
12228
+ clearInterval(broadcastTimer);
12229
+ broadcastTimer = null;
12187
12230
  }
12188
- });
12231
+ return;
12232
+ }
12233
+ void runSimulationTick().catch(logTickError);
12189
12234
  }
12190
12235
  function startBroadcastLoopIfNeeded() {
12191
12236
  if (broadcastTimer) return;
12192
12237
  if (!redis && connectedSessions.size < 1) return;
12193
- broadcastTimer = setInterval(() => {
12194
- if (!redis && connectedSessions.size < 1) {
12195
- if (broadcastTimer) {
12196
- clearInterval(broadcastTimer);
12197
- broadcastTimer = null;
12198
- }
12199
- return;
12200
- }
12201
- void runSimulationTick().catch((error) => {
12202
- const detail = error instanceof Error ? error.message : String(error);
12203
- agentLog("error", `world tick failed: ${detail}`);
12204
- });
12205
- }, BROADCAST_INTERVAL_MS);
12238
+ broadcastTimer = setInterval(onBroadcastTick, BROADCAST_INTERVAL_MS);
12206
12239
  agentLog("info", `world loop started (${BROADCAST_HZ}Hz)`);
12207
12240
  }
12208
12241
  function stopBroadcastLoopIfNeeded() {
@@ -12217,8 +12250,7 @@ async function ensureRedisWorldInitialized() {
12217
12250
  if (!redis) return;
12218
12251
  const existing = await redis.getBuffer(REDIS_WORLD_KEY);
12219
12252
  if (!existing || existing.byteLength === 0) {
12220
- const empty = createEmptyWorldBuffer();
12221
- await redis.set(REDIS_WORLD_KEY, copyWorldBuffer(empty));
12253
+ await redis.set(REDIS_WORLD_KEY, worldStateBytes);
12222
12254
  }
12223
12255
  }
12224
12256
  defineAgent({
@@ -12229,25 +12261,25 @@ defineAgent({
12229
12261
  "warn",
12230
12262
  "AGENT_REDIS_URL unset \u2014 game-sync uses per-worker in-memory world only"
12231
12263
  );
12232
- worldState = createEmptyWorldBuffer();
12233
12264
  return;
12234
12265
  }
12235
- redis = new import_ioredis.default(redisUrl, {
12266
+ redis = new import_ioredis.Redis(redisUrl, {
12236
12267
  maxRetriesPerRequest: 3,
12237
12268
  lazyConnect: true
12238
12269
  });
12239
12270
  await redis.connect();
12240
12271
  await ensureRedisWorldInitialized();
12241
- worldState = await loadWorldFromRedis();
12272
+ await loadWorldFromRedis();
12242
12273
  startBroadcastLoopIfNeeded();
12243
12274
  agentLog("info", "game-sync agent connected to project Redis world buffer");
12244
12275
  },
12245
12276
  async onClientJoin({ sessionId }) {
12246
- connectedSessions.add(sessionId);
12247
- startBroadcastLoopIfNeeded();
12248
- if (redis) {
12249
- worldState = await loadWorldFromRedis();
12277
+ if (!connectedSessions.has(sessionId)) {
12278
+ connectedSessions.add(sessionId);
12279
+ connectedSessionList.push(sessionId);
12250
12280
  }
12281
+ startBroadcastLoopIfNeeded();
12282
+ await loadWorldFromRedis();
12251
12283
  sendToClient(sessionId, {
12252
12284
  type: "world_snapshot",
12253
12285
  objects: liveWorldSnapshot(worldState, objectOwners)
@@ -12255,7 +12287,12 @@ defineAgent({
12255
12287
  agentLog("info", `join ${sessionId} connected=${connectedSessions.size}`);
12256
12288
  },
12257
12289
  async onClientLeave({ sessionId }) {
12258
- connectedSessions.delete(sessionId);
12290
+ if (connectedSessions.delete(sessionId)) {
12291
+ const index = connectedSessionList.indexOf(sessionId);
12292
+ if (index !== -1) {
12293
+ connectedSessionList.splice(index, 1);
12294
+ }
12295
+ }
12259
12296
  for (const [objectId, ownerSessionId] of objectOwners) {
12260
12297
  if (ownerSessionId === sessionId) {
12261
12298
  objectOwners.delete(objectId);
@@ -1,7 +1,7 @@
1
1
  export type TemplateKind = "product" | "e2e";
2
2
  export interface AgentTemplateDefinition {
3
3
  id: string;
4
- /** Path relative to `templates/` (e.g. `echo.ts`, `redis-sync/agent.ts`). */
4
+ /** Path relative to `templates/` (e.g. `echo/agent.ts`, `redis-sync/agent.ts`). */
5
5
  entry: string;
6
6
  kind: TemplateKind;
7
7
  /** When true, a prebuilt bundle is published at `dist/templates/<id>/agent.js`. */
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/templates/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,mFAAmF;IACnF,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,uBAAuB,EAmKpD,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAMrE,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,eAAe,CAEnE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,CAMnE;AAED,wBAAgB,yBAAyB,IAAI,uBAAuB,EAAE,CAErE"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/templates/registry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,mFAAmF;IACnF,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,uBAAuB,EAqLpD,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAMrE,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,eAAe,CAEnE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,CAMnE;AAED,wBAAgB,yBAAyB,IAAI,uBAAuB,EAAE,CAErE"}
@@ -1,40 +1,56 @@
1
1
  export const AGENT_TEMPLATES = [
2
2
  {
3
3
  id: "echo",
4
- entry: "echo.ts",
4
+ entry: "echo/agent.ts",
5
5
  kind: "product",
6
6
  seedOnCreate: true,
7
7
  description: "Full echo debug agent — voice finals and DataChannel chat with TTS playback.",
8
- sourceFiles: ["echo.ts"],
8
+ sourceFiles: ["echo/agent.ts"],
9
9
  },
10
10
  {
11
11
  id: "echo-dc",
12
- entry: "echo-dc.ts",
12
+ entry: "echo-dc/agent.ts",
13
13
  kind: "product",
14
14
  seedOnCreate: true,
15
15
  description: "Data-channel-only echo — relays speech events and chat without TTS.",
16
- sourceFiles: ["echo-dc.ts"],
16
+ sourceFiles: ["echo-dc/agent.ts"],
17
17
  },
18
18
  {
19
19
  id: "voice-starter",
20
- entry: "agent.ts",
20
+ entry: "voice-starter/agent.ts",
21
21
  kind: "product",
22
22
  seedOnCreate: true,
23
23
  description: "Voice starter covering every speech event — customize onUserSpeechFinal for your LLM.",
24
- sourceFiles: ["agent.ts"],
24
+ sourceFiles: ["voice-starter/agent.ts"],
25
+ },
26
+ {
27
+ id: "world-sync",
28
+ entry: "world-sync/agent.ts",
29
+ kind: "product",
30
+ seedOnCreate: true,
31
+ description: "Single-agent JSON world sync — onDataChannelMessage pose updates, in-memory, no Redis.",
32
+ sourceFiles: ["world-sync/agent.ts"],
33
+ },
34
+ {
35
+ id: "world-sync-binary",
36
+ entry: "world-sync-binary/agent.ts",
37
+ kind: "product",
38
+ seedOnCreate: true,
39
+ description: "Single-agent binary world sync — onDataChannelBinary + sendBinaryToClient ArrayBuffer poses, no Redis.",
40
+ sourceFiles: ["world-sync-binary/agent.ts", "world-sync-binary/protocol.ts"],
25
41
  },
26
42
  {
27
43
  id: "game-sync",
28
- entry: "game-sync.ts",
44
+ entry: "game-sync/agent.ts",
29
45
  kind: "product",
30
46
  seedOnCreate: true,
31
- description: "Authoritative multi-object sync sample for real-time games and simulations.",
47
+ description: "Authoritative multi-object sync with binary world snapshots; uses Redis when AGENT_REDIS_URL is set.",
32
48
  sourceFiles: [
33
- "game-sync.ts",
34
- "game-sync-protocol.ts",
35
- "game-sync-world-layout.ts",
36
- "game-sync-sim.ts",
37
- "game-sync-redis.ts",
49
+ "game-sync/agent.ts",
50
+ "game-sync/protocol.ts",
51
+ "game-sync/world-layout.ts",
52
+ "game-sync/sim.ts",
53
+ "game-sync/redis.ts",
38
54
  ],
39
55
  npmDependencies: { ioredis: "^5.11.1" },
40
56
  },
@@ -90,61 +106,61 @@ export const AGENT_TEMPLATES = [
90
106
  },
91
107
  {
92
108
  id: "webhooks",
93
- entry: "webhooks.ts",
109
+ entry: "webhooks/agent.ts",
94
110
  kind: "product",
95
111
  seedOnCreate: true,
96
112
  description: "Inbound webhook handler — HMAC verify on raw body, then DataChannel + speak fan-out.",
97
- sourceFiles: ["webhooks.ts"],
113
+ sourceFiles: ["webhooks/agent.ts"],
98
114
  },
99
115
  {
100
116
  id: "webhooks-redis",
101
- entry: "webhooks-redis.ts",
117
+ entry: "webhooks-redis/agent.ts",
102
118
  kind: "product",
103
119
  seedOnCreate: true,
104
120
  description: "Webhook handler with Redis atomic shared counter plus DataChannel fan-out.",
105
- sourceFiles: ["webhooks-redis.ts"],
121
+ sourceFiles: ["webhooks-redis/agent.ts"],
106
122
  npmDependencies: { ioredis: "^5.11.1" },
107
123
  },
108
124
  {
109
125
  id: "echo-smoke",
110
- entry: "echo-smoke.ts",
126
+ entry: "echo-smoke/agent.ts",
111
127
  kind: "e2e",
112
128
  seedOnCreate: false,
113
129
  description: "Minimal echo agent for e2e voice-smoke, agent-smoke, and cli-smoke uploads.",
114
- sourceFiles: ["echo-smoke.ts"],
130
+ sourceFiles: ["echo-smoke/agent.ts"],
115
131
  },
116
132
  {
117
133
  id: "crash",
118
- entry: "crash.ts",
134
+ entry: "crash/agent.ts",
119
135
  kind: "e2e",
120
136
  seedOnCreate: false,
121
137
  description: "Crash / echo agent for session-errors-smoke and agent-crash-policy smokes.",
122
- sourceFiles: ["crash.ts"],
138
+ sourceFiles: ["crash/agent.ts"],
123
139
  },
124
140
  {
125
141
  id: "game-sync-smoke",
126
- entry: "game-sync-smoke.ts",
142
+ entry: "game-sync-smoke/agent.ts",
127
143
  kind: "e2e",
128
144
  seedOnCreate: false,
129
145
  description: "Minimal data-channel agent for deploy-smoke, shared-child, and idle smokes.",
130
- sourceFiles: ["game-sync-smoke.ts"],
146
+ sourceFiles: ["game-sync-smoke/agent.ts"],
131
147
  },
132
148
  {
133
149
  id: "redis-sync",
134
150
  entry: "redis-sync/agent.ts",
135
151
  kind: "e2e",
136
152
  seedOnCreate: false,
137
- description: "Redis-backed world buffer sync for redis-sync-smoke (Advanced tier + project Redis).",
153
+ description: "Redis-backed world buffer sync for redis-sync-smoke — binary 12-byte position frames + project Redis.",
138
154
  sourceFiles: ["redis-sync/agent.ts", "redis-sync/world-layout.ts"],
139
155
  npmDependencies: { ioredis: "^5.11.1" },
140
156
  },
141
157
  {
142
158
  id: "mix-smoke",
143
- entry: "mix-smoke.ts",
159
+ entry: "mix-smoke/agent.ts",
144
160
  kind: "e2e",
145
161
  seedOnCreate: false,
146
162
  description: "Positional mix DC commands for voice-data-mix-smoke (Voice+Data, shared child).",
147
- sourceFiles: ["mix-smoke.ts"],
163
+ sourceFiles: ["mix-smoke/agent.ts"],
148
164
  },
149
165
  ];
150
166
  const TEMPLATE_BY_ID = new Map(AGENT_TEMPLATES.map((template) => [template.id, template]));
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/templates/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/templates/registry.ts"],"names":[],"mappings":"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"}
@@ -779,7 +779,7 @@ function agentLog(level, message, fieldsOrSessionId, sessionId) {
779
779
  sendParentMessage(buildAgentLogPayload(level, message, fields, resolvedSessionId));
780
780
  }
781
781
 
782
- // templates/agent.ts
782
+ // templates/voice-starter/agent.ts
783
783
  var peers = /* @__PURE__ */ new Map();
784
784
  function peerState(sessionId) {
785
785
  let state = peers.get(sessionId);
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  const require = createRequire(import.meta.url);
3
3
 
4
4
 
5
- // templates/webhooks.ts
5
+ // templates/webhooks/agent.ts
6
6
  import { createHmac, timingSafeEqual } from "node:crypto";
7
7
 
8
8
  // dist/runtime.js
@@ -790,7 +790,7 @@ function agentLog(level, message, fieldsOrSessionId, sessionId) {
790
790
  sendParentMessage(buildAgentLogPayload(level, message, fields, resolvedSessionId));
791
791
  }
792
792
 
793
- // templates/webhooks.ts
793
+ // templates/webhooks/agent.ts
794
794
  var WEBHOOK_SIGNATURE_HEADER = "x-agent-webhook-signature";
795
795
  var connectedSessions = /* @__PURE__ */ new Set();
796
796
  function getHeaderCaseInsensitive(headers, name) {