@voicethere/agent 0.7.12 → 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.
- package/README.md +14 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +11 -2
- package/dist/runtime.js.map +1 -1
- package/dist/templates/echo/agent.js +1 -1
- package/dist/templates/echo-dc/agent.js +1 -1
- package/dist/templates/game-sync/agent.js +162 -125
- package/dist/templates/registry.d.ts +1 -1
- package/dist/templates/registry.d.ts.map +1 -1
- package/dist/templates/registry.js +42 -26
- package/dist/templates/registry.js.map +1 -1
- package/dist/templates/spatial-showcase/agent.js +261 -22
- package/dist/templates/voice-starter/agent.js +1 -1
- package/dist/templates/webhooks/agent.js +2 -2
- package/dist/templates/webhooks-redis/agent.js +11 -4
- package/dist/templates/world-sync/agent.js +829 -0
- package/dist/templates/world-sync-binary/agent.js +1031 -0
- package/package.json +3 -2
- package/templates/README.md +41 -69
- package/templates/crash/README.md +13 -0
- package/templates/echo/README.md +13 -0
- package/templates/{echo.ts → echo/agent.ts} +1 -1
- package/templates/echo-dc/README.md +13 -0
- package/templates/{echo-dc.ts → echo-dc/agent.ts} +1 -1
- package/templates/echo-smoke/README.md +13 -0
- package/templates/game-sync/README.md +21 -0
- package/templates/{game-sync.ts → game-sync/agent.ts} +126 -94
- package/templates/{game-sync-redis.ts → game-sync/redis.ts} +4 -13
- package/templates/{game-sync-sim.ts → game-sync/sim.ts} +14 -7
- package/templates/{game-sync-world-layout.ts → game-sync/world-layout.ts} +72 -30
- package/templates/game-sync-smoke/README.md +13 -0
- package/templates/mix-smoke/README.md +13 -0
- package/templates/positional-tts/README.md +13 -0
- package/templates/recording-consent/README.md +13 -0
- package/templates/redis-sync/README.md +23 -0
- package/templates/redis-sync/agent.ts +72 -95
- package/templates/redis-sync/world-layout.ts +103 -26
- package/templates/spatial-showcase/README.md +13 -0
- package/templates/spatial-showcase/agent.ts +245 -18
- package/templates/spatial-showcase/protocol.ts +79 -0
- package/templates/spatial-showcase/sine.ts +28 -5
- package/templates/voice-showcase/README.md +13 -0
- package/templates/voice-starter/README.md +13 -0
- package/templates/webhooks/README.md +13 -0
- package/templates/{webhooks.ts → webhooks/agent.ts} +1 -1
- package/templates/webhooks-redis/README.md +13 -0
- package/templates/{webhooks-redis.ts → webhooks-redis/agent.ts} +9 -9
- package/templates/world-sync/README.md +20 -0
- package/templates/world-sync/agent.ts +62 -0
- package/templates/world-sync-binary/README.md +21 -0
- package/templates/world-sync-binary/agent.ts +107 -0
- package/templates/world-sync-binary/protocol.ts +281 -0
- /package/templates/{crash.ts → crash/agent.ts} +0 -0
- /package/templates/{echo-smoke.ts → echo-smoke/agent.ts} +0 -0
- /package/templates/{game-sync-protocol.ts → game-sync/protocol.ts} +0 -0
- /package/templates/{game-sync-smoke.ts → game-sync-smoke/agent.ts} +0 -0
- /package/templates/{mix-smoke.ts → mix-smoke/agent.ts} +0 -0
- /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
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
11710
|
+
destBytes.fill(0);
|
|
11711
|
+
return dest;
|
|
11683
11712
|
}
|
|
11684
|
-
const
|
|
11685
|
-
|
|
11686
|
-
|
|
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
|
-
|
|
11689
|
-
|
|
11690
|
-
if (decoded.length === WORLD_FLOAT_COUNT) {
|
|
11691
|
-
return decoded;
|
|
11720
|
+
if (byteCount < destBytes.byteLength) {
|
|
11721
|
+
destBytes.fill(0, byteCount);
|
|
11692
11722
|
}
|
|
11693
|
-
|
|
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
|
-
|
|
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
|
-
|
|
11728
|
+
blob.writeFloatLE(objectId, (objectId - 1) * 4);
|
|
11709
11729
|
}
|
|
11710
|
-
return
|
|
11711
|
-
}
|
|
11712
|
-
|
|
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
|
|
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,
|
|
11807
|
-
for (
|
|
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 <
|
|
11831
|
-
const aId =
|
|
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 <
|
|
11836
|
-
const bId =
|
|
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
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
12130
|
-
|
|
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
|
-
|
|
12168
|
+
normalizeWorldBuffer(raw, worldState);
|
|
12145
12169
|
}
|
|
12146
|
-
async function saveWorldToRedis(
|
|
12170
|
+
async function saveWorldToRedis() {
|
|
12147
12171
|
if (!redis) return;
|
|
12148
|
-
await redis.set(REDIS_WORLD_KEY,
|
|
12172
|
+
await redis.set(REDIS_WORLD_KEY, worldStateBytes);
|
|
12149
12173
|
}
|
|
12150
|
-
|
|
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(
|
|
12159
|
-
|
|
12160
|
-
});
|
|
12161
|
-
broadcastWorldBuffer(worldState);
|
|
12215
|
+
await withWorldMutation(stepWorldInMemory);
|
|
12216
|
+
broadcastWorldBuffer();
|
|
12162
12217
|
return;
|
|
12163
12218
|
}
|
|
12164
|
-
await withWorldMutation(
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
12247
|
-
|
|
12248
|
-
|
|
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,
|
|
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
|
|
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
|
|
35
|
-
"game-sync
|
|
36
|
-
"game-sync
|
|
37
|
-
"game-sync
|
|
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
|
|
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":"AAgBA,MAAM,CAAC,MAAM,eAAe,GAAuC;IACjE;QACE,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/templates/registry.ts"],"names":[],"mappings":"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"}
|