@band-ai/sdk 0.2.1 → 0.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/dist/{ClaudeSDKAdapter-Cna5P1dR.d.ts → ClaudeSDKAdapter-CXud2DBE.d.ts} +2 -1
- package/dist/{ClaudeSDKAdapter-BY4zEbCl.d.cts → ClaudeSDKAdapter-Cx6zhSaG.d.cts} +2 -1
- package/dist/adapters.cjs +208 -115
- package/dist/adapters.d.cts +8 -4
- package/dist/adapters.d.ts +8 -4
- package/dist/adapters.js +105 -43
- package/dist/chunk-F63TPOI3.js +29 -0
- package/dist/{chunk-3BKAC4OZ.js → chunk-JADCAMZY.js} +8 -0
- package/dist/{chunk-N2QTUMGO.js → chunk-JJF44XWA.js} +365 -249
- package/dist/{chunk-TLBCKDQO.js → chunk-K5KAEYPF.js} +2 -2
- package/dist/{chunk-ZZJRRBPQ.js → chunk-KXJ74J73.js} +1 -1
- package/dist/{chunk-NMZLX7TP.js → chunk-MQBBWYRP.js} +52 -45
- package/dist/{chunk-RV76SKFT.js → chunk-MQY74R7D.js} +2 -20
- package/dist/{chunk-LBWKISBS.js → chunk-OH6VVVKT.js} +21 -0
- package/dist/{chunk-EAI2M3WM.js → chunk-W5IAI6Z4.js} +1 -1
- package/dist/{chunk-4IAXZBXX.js → chunk-WA7CHXUS.js} +2 -2
- package/dist/{chunk-NT7TBFX2.js → chunk-XWHWJP4I.js} +2 -2
- package/dist/{chunk-WLCM2OXG.js → chunk-YJ42AZO4.js} +1 -1
- package/dist/converters.js +6 -5
- package/dist/index.cjs +405 -277
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +12 -11
- package/dist/mcp-claude.js +4 -3
- package/dist/mcp.js +5 -4
- package/dist/rest.js +3 -3
- package/dist/runtime.cjs +387 -362
- package/dist/runtime.d.cts +10 -39
- package/dist/runtime.d.ts +10 -39
- package/dist/runtime.js +20 -142
- package/dist/{schemas-BotL3ZLH.d.cts → schemas-BgJhlqqO.d.cts} +57 -13
- package/dist/{schemas-DBsC4J1g.d.ts → schemas-C4mK1WSs.d.ts} +57 -13
- package/dist/testing.cjs +11 -0
- package/dist/testing.js +8 -1
- package/dist/{types-D958TC71.d.cts → types-BNNtOXu3.d.cts} +1 -1
- package/dist/{types-BTN_ZETM.d.ts → types-DFUtpxah.d.ts} +1 -1
- package/package.json +2 -2
package/dist/runtime.cjs
CHANGED
|
@@ -41,10 +41,11 @@ __export(runtime_exports, {
|
|
|
41
41
|
MCP_TOOL_PREFIX: () => MCP_TOOL_PREFIX,
|
|
42
42
|
MEMORY_SECTION: () => MEMORY_SECTION,
|
|
43
43
|
MEMORY_TOOL_NAMES: () => MEMORY_TOOL_NAMES,
|
|
44
|
-
ParticipantRoster: () =>
|
|
44
|
+
ParticipantRoster: () => import_band_sdk_core4.ParticipantRoster,
|
|
45
45
|
PlatformRuntime: () => PlatformRuntime,
|
|
46
|
-
RetryTracker: () =>
|
|
46
|
+
RetryTracker: () => import_band_sdk_core4.RetryTracker,
|
|
47
47
|
RoomPresence: () => RoomPresence,
|
|
48
|
+
RoomRoster: () => import_band_sdk_core4.RoomRoster,
|
|
48
49
|
SYNTHETIC_CONTACT_EVENTS_SENDER_ID: () => SYNTHETIC_CONTACT_EVENTS_SENDER_ID,
|
|
49
50
|
SYNTHETIC_CONTACT_EVENTS_SENDER_NAME: () => SYNTHETIC_CONTACT_EVENTS_SENDER_NAME,
|
|
50
51
|
SYNTHETIC_SENDER_TYPE: () => SYNTHETIC_SENDER_TYPE,
|
|
@@ -58,6 +59,7 @@ __export(runtime_exports, {
|
|
|
58
59
|
getToolDescription: () => getToolDescription,
|
|
59
60
|
isChatEventType: () => isChatEventType,
|
|
60
61
|
mcpToolNames: () => mcpToolNames,
|
|
62
|
+
mentionSubjectsFromMetadata: () => mentionSubjectsFromMetadata,
|
|
61
63
|
renderSystemPrompt: () => renderSystemPrompt,
|
|
62
64
|
replaceUuidMentions: () => replaceUuidMentions,
|
|
63
65
|
runWithGracefulShutdown: () => runWithGracefulShutdown
|
|
@@ -138,6 +140,26 @@ var RuntimeStateError = class extends BandSdkError {
|
|
|
138
140
|
function isMetadataMap(value) {
|
|
139
141
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
140
142
|
}
|
|
143
|
+
function mentionSubjectsFromMetadata(metadata) {
|
|
144
|
+
const mentions = metadata?.mentions;
|
|
145
|
+
if (!Array.isArray(mentions)) {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const subjects = [];
|
|
149
|
+
for (const mention of mentions) {
|
|
150
|
+
if (!isMetadataMap(mention) || typeof mention.id !== "string") {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const label = [mention.handle, mention.username, mention.name].find(
|
|
154
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
155
|
+
);
|
|
156
|
+
if (label === void 0) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
subjects.push({ id: mention.id, handle: label });
|
|
160
|
+
}
|
|
161
|
+
return subjects;
|
|
162
|
+
}
|
|
141
163
|
function replaceUuidMentions(content, participants) {
|
|
142
164
|
if (!content || participants.length === 0) {
|
|
143
165
|
return content;
|
|
@@ -1234,6 +1256,13 @@ function isToolExecutorError(value) {
|
|
|
1234
1256
|
const candidate = value;
|
|
1235
1257
|
return candidate.ok === false && typeof candidate.errorType === "string" && TOOL_EXECUTOR_ERROR_TYPES.includes(candidate.errorType) && typeof candidate.toolName === "string" && typeof candidate.message === "string" && typeof candidate.legacyMessage === "string";
|
|
1236
1258
|
}
|
|
1259
|
+
function isStructuredToolFailure(value) {
|
|
1260
|
+
if (!value || typeof value !== "object") {
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
const payload = value;
|
|
1264
|
+
return payload.ok === false && typeof payload.message === "string";
|
|
1265
|
+
}
|
|
1237
1266
|
var DEFAULT_AGENT_TOOLS_CAPABILITIES = {
|
|
1238
1267
|
peers: true,
|
|
1239
1268
|
contacts: true,
|
|
@@ -1711,10 +1740,12 @@ var AgentTools = class {
|
|
|
1711
1740
|
roster;
|
|
1712
1741
|
adapterTools;
|
|
1713
1742
|
toolHandlers;
|
|
1743
|
+
logger;
|
|
1714
1744
|
constructor(options) {
|
|
1715
1745
|
this.roomId = options.roomId;
|
|
1716
1746
|
this.rest = options.rest;
|
|
1717
1747
|
this.roster = options.roster ?? new import_band_sdk_core.ParticipantRoster();
|
|
1748
|
+
this.logger = options.logger ?? new NoopLogger();
|
|
1718
1749
|
this.capabilities = {
|
|
1719
1750
|
...DEFAULT_AGENT_TOOLS_CAPABILITIES,
|
|
1720
1751
|
...options.capabilities
|
|
@@ -1744,14 +1775,23 @@ var AgentTools = class {
|
|
|
1744
1775
|
}
|
|
1745
1776
|
async sendEvent(content, messageType, metadata) {
|
|
1746
1777
|
assertChatEventType(messageType);
|
|
1747
|
-
|
|
1748
|
-
this.
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1778
|
+
try {
|
|
1779
|
+
return await this.rest.createChatEvent(
|
|
1780
|
+
this.roomId,
|
|
1781
|
+
{
|
|
1782
|
+
content,
|
|
1783
|
+
messageType,
|
|
1784
|
+
metadata
|
|
1785
|
+
}
|
|
1786
|
+
);
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
try {
|
|
1789
|
+
this.logger.warn("chat event send failed", { roomId: this.roomId, messageType, error });
|
|
1790
|
+
} catch {
|
|
1753
1791
|
}
|
|
1754
|
-
|
|
1792
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1793
|
+
return { ok: false, status: "failed", message };
|
|
1794
|
+
}
|
|
1755
1795
|
}
|
|
1756
1796
|
async createChatroom(taskId) {
|
|
1757
1797
|
const room = await this.rest.createChat(taskId, DEFAULT_REQUEST_OPTIONS);
|
|
@@ -1854,7 +1894,16 @@ var AgentTools = class {
|
|
|
1854
1894
|
});
|
|
1855
1895
|
}
|
|
1856
1896
|
try {
|
|
1857
|
-
|
|
1897
|
+
const result = await handler(arguments_);
|
|
1898
|
+
if (toolName === "band_send_event" && isStructuredToolFailure(result) && !isToolExecutorError(result)) {
|
|
1899
|
+
return createToolExecutorError({
|
|
1900
|
+
errorType: "ToolExecutionError",
|
|
1901
|
+
toolName,
|
|
1902
|
+
message: result.message,
|
|
1903
|
+
legacyMessage: `Error executing ${toolName}: ${result.message}`
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
return result;
|
|
1858
1907
|
} catch (error) {
|
|
1859
1908
|
if (isToolExecutorError(error)) {
|
|
1860
1909
|
return error;
|
|
@@ -2555,7 +2604,8 @@ var ExecutionContext = class {
|
|
|
2555
2604
|
roomId: this.roomId,
|
|
2556
2605
|
rest: this.link.rest,
|
|
2557
2606
|
roster: this.roster,
|
|
2558
|
-
capabilities: this.link.capabilities
|
|
2607
|
+
capabilities: this.link.capabilities,
|
|
2608
|
+
logger: options.logger ?? new NoopLogger()
|
|
2559
2609
|
});
|
|
2560
2610
|
this.adapterTools = this.tools.getAdapterTools();
|
|
2561
2611
|
}
|
|
@@ -2803,70 +2853,278 @@ var ExecutionContext = class {
|
|
|
2803
2853
|
}
|
|
2804
2854
|
};
|
|
2805
2855
|
|
|
2856
|
+
// src/runtime/rooms/RoomPresence.ts
|
|
2857
|
+
var import_band_sdk_core3 = require("@band-ai/band-sdk-core");
|
|
2858
|
+
|
|
2806
2859
|
// src/runtime/rooms/subscriptions.ts
|
|
2807
|
-
function
|
|
2808
|
-
|
|
2860
|
+
async function hydrateExistingRooms(options) {
|
|
2861
|
+
try {
|
|
2862
|
+
const rooms = await options.link.listAllChats(void 0, options.requestOptions);
|
|
2863
|
+
for (const room of rooms) {
|
|
2864
|
+
const roomId = typeof room.id === "string" ? room.id : null;
|
|
2865
|
+
if (!roomId) {
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2868
|
+
if (options.roomFilter && !options.roomFilter(room)) {
|
|
2869
|
+
continue;
|
|
2870
|
+
}
|
|
2871
|
+
await options.onRoom(roomId, room);
|
|
2872
|
+
}
|
|
2873
|
+
} catch (error) {
|
|
2874
|
+
if (error instanceof UnsupportedFeatureError) {
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
if (options.onError) {
|
|
2878
|
+
await options.onError(error);
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
throw error;
|
|
2882
|
+
}
|
|
2809
2883
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2884
|
+
|
|
2885
|
+
// src/runtime/rooms/RoomPresence.ts
|
|
2886
|
+
var RoomPresence = class {
|
|
2887
|
+
roster = new import_band_sdk_core3.RoomRoster();
|
|
2888
|
+
onRoomJoined = null;
|
|
2889
|
+
onRoomLeft = null;
|
|
2890
|
+
onRoomEvent = null;
|
|
2891
|
+
onContactEvent = null;
|
|
2892
|
+
link;
|
|
2893
|
+
roomFilter;
|
|
2894
|
+
autoSubscribeExistingRooms;
|
|
2895
|
+
logger;
|
|
2896
|
+
eventController = null;
|
|
2897
|
+
eventTask = null;
|
|
2898
|
+
contactsSubscribed = false;
|
|
2899
|
+
lifecycle = Promise.resolve();
|
|
2900
|
+
admissionInFlight = /* @__PURE__ */ new Map();
|
|
2901
|
+
// Read once by `admitRoomOrThrow` right after a failed admission; a
|
|
2902
|
+
// subsequent successful subscribe clears it so a caller never attributes
|
|
2903
|
+
// today's failure to a stale reason from an earlier attempt.
|
|
2904
|
+
lastSubscribeError = /* @__PURE__ */ new Map();
|
|
2905
|
+
constructor(options) {
|
|
2906
|
+
this.link = options.link;
|
|
2907
|
+
this.roomFilter = options.roomFilter;
|
|
2908
|
+
this.autoSubscribeExistingRooms = options.autoSubscribeExistingRooms ?? true;
|
|
2909
|
+
this.logger = options.logger ?? new NoopLogger();
|
|
2813
2910
|
}
|
|
2814
|
-
|
|
2815
|
-
return
|
|
2911
|
+
async start() {
|
|
2912
|
+
return this.serialize(() => this.startBody());
|
|
2816
2913
|
}
|
|
2817
|
-
|
|
2818
|
-
return
|
|
2914
|
+
async stop() {
|
|
2915
|
+
return this.serialize(() => this.stopBody());
|
|
2819
2916
|
}
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
if (options.onJoined) {
|
|
2823
|
-
await options.onJoined(options.roomId, options.payload);
|
|
2917
|
+
async [Symbol.asyncDispose]() {
|
|
2918
|
+
await this.stop();
|
|
2824
2919
|
}
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
async function trackRoomLeave(options) {
|
|
2828
|
-
if (!hasRoomId(options.roomId) || !options.trackedRooms.has(options.roomId)) {
|
|
2829
|
-
return false;
|
|
2920
|
+
abortEventLoop() {
|
|
2921
|
+
this.eventController?.abort();
|
|
2830
2922
|
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
if (options.onLeft) {
|
|
2834
|
-
await options.onLeft(options.roomId);
|
|
2923
|
+
async waitUntilStopped() {
|
|
2924
|
+
await this.eventTask;
|
|
2835
2925
|
}
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2926
|
+
async admitRoom(roomId, payload, notify = true) {
|
|
2927
|
+
const ticket = this.roster.beginRoomAdmission(roomId, true);
|
|
2928
|
+
const admitted = ticket === void 0 ? await this.awaitInFlightAdmission(roomId) : await this.performAdmission(roomId, ticket);
|
|
2929
|
+
if (admitted && notify) {
|
|
2930
|
+
await this.onRoomJoined?.(roomId, payload);
|
|
2931
|
+
}
|
|
2932
|
+
return admitted;
|
|
2933
|
+
}
|
|
2934
|
+
/** Admit a room for a caller that needs to know *why* a failed subscribe happened, not just that it did. */
|
|
2935
|
+
async admitRoomOrThrow(roomId) {
|
|
2936
|
+
if (!await this.admitRoom(roomId, {}, false)) {
|
|
2937
|
+
throw new TransportError(`Failed to subscribe to room ${roomId}`, this.lastSubscribeError.get(roomId));
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
async awaitInFlightAdmission(roomId) {
|
|
2941
|
+
const inFlight = this.admissionInFlight.get(roomId);
|
|
2942
|
+
return inFlight ? await inFlight : this.roster.roomMembership(roomId) === "admitted";
|
|
2943
|
+
}
|
|
2944
|
+
async performAdmission(roomId, ticket) {
|
|
2945
|
+
const admission = this.completeAdmission(roomId, ticket);
|
|
2946
|
+
this.admissionInFlight.set(roomId, admission);
|
|
2947
|
+
try {
|
|
2948
|
+
return await admission;
|
|
2949
|
+
} finally {
|
|
2950
|
+
if (this.admissionInFlight.get(roomId) === admission) {
|
|
2951
|
+
this.admissionInFlight.delete(roomId);
|
|
2952
|
+
}
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
async completeAdmission(roomId, ticket) {
|
|
2956
|
+
let succeeded = false;
|
|
2957
|
+
let admitted = false;
|
|
2958
|
+
let subscribeError;
|
|
2959
|
+
try {
|
|
2960
|
+
await this.link.subscribeRoom(roomId);
|
|
2961
|
+
succeeded = true;
|
|
2962
|
+
} catch (error) {
|
|
2963
|
+
this.logger.warn("RoomPresence failed to subscribe room", { roomId, error });
|
|
2964
|
+
subscribeError = error;
|
|
2965
|
+
} finally {
|
|
2966
|
+
admitted = this.roster.recordRoomAdmission(roomId, ticket, succeeded);
|
|
2967
|
+
}
|
|
2968
|
+
const roomIsAdmitted = admitted || this.roster.roomMembership(roomId) === "admitted";
|
|
2969
|
+
if (succeeded && !admitted && !roomIsAdmitted) {
|
|
2970
|
+
this.logger.debug("RoomPresence admission ticket went stale", { roomId });
|
|
2971
|
+
await this.unsubscribeRoom(roomId);
|
|
2972
|
+
}
|
|
2973
|
+
if (roomIsAdmitted) {
|
|
2974
|
+
this.lastSubscribeError.delete(roomId);
|
|
2975
|
+
} else if (subscribeError !== void 0) {
|
|
2976
|
+
this.lastSubscribeError.set(roomId, subscribeError);
|
|
2977
|
+
}
|
|
2978
|
+
return roomIsAdmitted;
|
|
2979
|
+
}
|
|
2980
|
+
async serialize(body) {
|
|
2981
|
+
const run = this.lifecycle.then(body, body);
|
|
2982
|
+
this.lifecycle = run.then(
|
|
2983
|
+
() => void 0,
|
|
2984
|
+
() => void 0
|
|
2845
2985
|
);
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2986
|
+
return run;
|
|
2987
|
+
}
|
|
2988
|
+
async startBody() {
|
|
2989
|
+
if (this.eventTask) {
|
|
2990
|
+
throw new RuntimeStateError("RoomPresence is already started");
|
|
2991
|
+
}
|
|
2992
|
+
if (!this.link.isConnected()) {
|
|
2993
|
+
await this.link.connect();
|
|
2994
|
+
}
|
|
2995
|
+
const contactsReady = this.subscribeContacts();
|
|
2996
|
+
try {
|
|
2997
|
+
await this.link.subscribeAgentRooms();
|
|
2998
|
+
} catch (error) {
|
|
2999
|
+
this.logger.warn("RoomPresence failed to subscribe agent_rooms channel, continuing without it", {
|
|
3000
|
+
error
|
|
2854
3001
|
});
|
|
2855
3002
|
}
|
|
2856
|
-
|
|
2857
|
-
|
|
3003
|
+
if (this.autoSubscribeExistingRooms) {
|
|
3004
|
+
await this.subscribeExistingRooms();
|
|
3005
|
+
}
|
|
3006
|
+
await contactsReady;
|
|
3007
|
+
this.eventController = new AbortController();
|
|
3008
|
+
this.eventTask = this.consumeEvents(this.eventController.signal);
|
|
3009
|
+
}
|
|
3010
|
+
async subscribeContacts() {
|
|
3011
|
+
if (!this.link.capabilities.contacts) {
|
|
2858
3012
|
return;
|
|
2859
3013
|
}
|
|
2860
|
-
|
|
2861
|
-
await
|
|
3014
|
+
try {
|
|
3015
|
+
await this.link.subscribeAgentContacts();
|
|
3016
|
+
this.contactsSubscribed = true;
|
|
3017
|
+
} catch (error) {
|
|
3018
|
+
this.logger.warn("RoomPresence failed to subscribe agent_contacts channel, continuing without it", {
|
|
3019
|
+
error
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
async stopBody() {
|
|
3024
|
+
this.abortEventLoop();
|
|
3025
|
+
await this.eventTask?.catch(() => void 0);
|
|
3026
|
+
this.eventTask = null;
|
|
3027
|
+
this.eventController = null;
|
|
3028
|
+
if (this.contactsSubscribed) {
|
|
3029
|
+
try {
|
|
3030
|
+
await this.link.unsubscribeAgentContacts();
|
|
3031
|
+
} catch (error) {
|
|
3032
|
+
this.logger.warn("RoomPresence failed to unsubscribe agent_contacts channel", { error });
|
|
3033
|
+
} finally {
|
|
3034
|
+
this.contactsSubscribed = false;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
const roomIds = this.roster.trackedRoomIds();
|
|
3038
|
+
this.roster.clear();
|
|
3039
|
+
this.lastSubscribeError.clear();
|
|
3040
|
+
await Promise.all(
|
|
3041
|
+
roomIds.map(async (roomId) => {
|
|
3042
|
+
await this.unsubscribeRoom(roomId);
|
|
3043
|
+
await this.onRoomLeft?.(roomId);
|
|
3044
|
+
})
|
|
3045
|
+
);
|
|
3046
|
+
}
|
|
3047
|
+
async consumeEvents(signal) {
|
|
3048
|
+
while (!signal.aborted) {
|
|
3049
|
+
const event = await this.link.nextEvent(signal);
|
|
3050
|
+
if (!event) {
|
|
3051
|
+
return;
|
|
3052
|
+
}
|
|
3053
|
+
switch (event.type) {
|
|
3054
|
+
case "room_added":
|
|
3055
|
+
await this.handleRoomAdded(event.roomId, event.payload);
|
|
3056
|
+
break;
|
|
3057
|
+
case "room_removed":
|
|
3058
|
+
case "room_deleted":
|
|
3059
|
+
await this.handleRoomRemoved(event.roomId);
|
|
3060
|
+
break;
|
|
3061
|
+
case "contact_request_received":
|
|
3062
|
+
case "contact_request_updated":
|
|
3063
|
+
case "contact_added":
|
|
3064
|
+
case "contact_removed":
|
|
3065
|
+
await this.onContactEvent?.(event);
|
|
3066
|
+
break;
|
|
3067
|
+
case "message_created":
|
|
3068
|
+
case "participant_added":
|
|
3069
|
+
case "participant_removed":
|
|
3070
|
+
if (event.roomId && this.roster.roomMembership(event.roomId) === "admitted") {
|
|
3071
|
+
await this.onRoomEvent?.(event.roomId, event);
|
|
3072
|
+
}
|
|
3073
|
+
break;
|
|
3074
|
+
default:
|
|
3075
|
+
assertNever2(event);
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
async handleRoomAdded(roomId, payload) {
|
|
3080
|
+
if (!roomId) {
|
|
2862
3081
|
return;
|
|
2863
3082
|
}
|
|
2864
|
-
|
|
3083
|
+
if (this.roomFilter && !this.roomFilter(payload)) {
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
await this.admitRoom(roomId, payload);
|
|
3087
|
+
}
|
|
3088
|
+
async handleRoomRemoved(roomId) {
|
|
3089
|
+
if (!roomId) {
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
await this.unsubscribeRoom(roomId);
|
|
3093
|
+
this.lastSubscribeError.delete(roomId);
|
|
3094
|
+
if (!this.roster.recordRoomRemoved(roomId)) {
|
|
3095
|
+
this.logger.debug("RoomPresence ignoring removal for untracked room", { roomId });
|
|
3096
|
+
return;
|
|
3097
|
+
}
|
|
3098
|
+
await this.onRoomLeft?.(roomId);
|
|
3099
|
+
}
|
|
3100
|
+
async unsubscribeRoom(roomId) {
|
|
3101
|
+
try {
|
|
3102
|
+
await this.link.unsubscribeRoom(roomId);
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
this.logger.warn("RoomPresence failed to unsubscribe room", { roomId, error });
|
|
3105
|
+
}
|
|
2865
3106
|
}
|
|
3107
|
+
async subscribeExistingRooms() {
|
|
3108
|
+
await hydrateExistingRooms({
|
|
3109
|
+
link: this.link,
|
|
3110
|
+
roomFilter: this.roomFilter,
|
|
3111
|
+
requestOptions: DEFAULT_REQUEST_OPTIONS,
|
|
3112
|
+
onRoom: async (roomId, payload) => {
|
|
3113
|
+
await this.admitRoom(roomId, payload);
|
|
3114
|
+
},
|
|
3115
|
+
onError: (error) => {
|
|
3116
|
+
this.logger.warn("RoomPresence failed to subscribe existing rooms", { error });
|
|
3117
|
+
}
|
|
3118
|
+
});
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
function assertNever2(value) {
|
|
3122
|
+
throw new Error(`Unhandled platform event: ${JSON.stringify(value)}`);
|
|
2866
3123
|
}
|
|
2867
3124
|
|
|
2868
3125
|
// src/runtime/rooms/AgentRuntime.ts
|
|
2869
3126
|
var AgentRuntime = class {
|
|
3127
|
+
presence;
|
|
2870
3128
|
link;
|
|
2871
3129
|
agentId;
|
|
2872
3130
|
onExecute;
|
|
@@ -2877,19 +3135,14 @@ var AgentRuntime = class {
|
|
|
2877
3135
|
onParticipantAdded;
|
|
2878
3136
|
onParticipantRemoved;
|
|
2879
3137
|
onError;
|
|
2880
|
-
roomFilter;
|
|
2881
3138
|
contextFactory;
|
|
2882
3139
|
sessionConfig;
|
|
2883
|
-
autoSubscribeExistingRooms;
|
|
2884
|
-
subscribedRooms = /* @__PURE__ */ new Set();
|
|
2885
3140
|
contexts = /* @__PURE__ */ new Map();
|
|
2886
3141
|
executions = /* @__PURE__ */ new Map();
|
|
2887
3142
|
executionWatchers = /* @__PURE__ */ new Map();
|
|
2888
3143
|
logger;
|
|
2889
3144
|
running = false;
|
|
2890
3145
|
stopping = false;
|
|
2891
|
-
stopController = new AbortController();
|
|
2892
|
-
consumeTask = null;
|
|
2893
3146
|
fatalError = null;
|
|
2894
3147
|
constructor(options) {
|
|
2895
3148
|
this.link = options.link;
|
|
@@ -2903,7 +3156,6 @@ var AgentRuntime = class {
|
|
|
2903
3156
|
this.onContactEvent = options.onContactEvent;
|
|
2904
3157
|
this.onParticipantAdded = options.onParticipantAdded;
|
|
2905
3158
|
this.onParticipantRemoved = options.onParticipantRemoved;
|
|
2906
|
-
this.roomFilter = options.roomFilter;
|
|
2907
3159
|
this.contextFactory = options.contextFactory;
|
|
2908
3160
|
this.sessionConfig = {
|
|
2909
3161
|
enableContextCache: options.sessionConfig?.enableContextCache ?? true,
|
|
@@ -2912,7 +3164,48 @@ var AgentRuntime = class {
|
|
|
2912
3164
|
maxMessageRetries: options.sessionConfig?.maxMessageRetries ?? 1,
|
|
2913
3165
|
enableContextHydration: options.sessionConfig?.enableContextHydration ?? true
|
|
2914
3166
|
};
|
|
2915
|
-
this.
|
|
3167
|
+
this.presence = new RoomPresence({
|
|
3168
|
+
link: this.link,
|
|
3169
|
+
roomFilter: options.roomFilter,
|
|
3170
|
+
autoSubscribeExistingRooms: options.agentConfig?.autoSubscribeExistingRooms ?? false,
|
|
3171
|
+
logger: this.logger
|
|
3172
|
+
});
|
|
3173
|
+
this.presence.onRoomJoined = async (roomId, payload) => {
|
|
3174
|
+
this.getOrCreateExecution(roomId);
|
|
3175
|
+
await this.onRoomJoined?.(roomId, payload);
|
|
3176
|
+
};
|
|
3177
|
+
this.presence.onRoomLeft = async (roomId) => {
|
|
3178
|
+
await this.teardownExecution(roomId);
|
|
3179
|
+
await this.onRoomLeft?.(roomId);
|
|
3180
|
+
};
|
|
3181
|
+
this.presence.onRoomEvent = async (roomId, event) => {
|
|
3182
|
+
switch (event.type) {
|
|
3183
|
+
case "participant_added": {
|
|
3184
|
+
const context = this.getOrCreateContext(roomId);
|
|
3185
|
+
const participant = {
|
|
3186
|
+
id: event.payload.id,
|
|
3187
|
+
name: event.payload.name,
|
|
3188
|
+
type: event.payload.type,
|
|
3189
|
+
handle: event.payload.handle
|
|
3190
|
+
};
|
|
3191
|
+
context.addParticipant(participant);
|
|
3192
|
+
await this.onParticipantAdded?.(roomId, participant);
|
|
3193
|
+
return;
|
|
3194
|
+
}
|
|
3195
|
+
case "participant_removed": {
|
|
3196
|
+
const context = this.getOrCreateContext(roomId);
|
|
3197
|
+
context.removeParticipant(event.payload.id);
|
|
3198
|
+
await this.onParticipantRemoved?.(roomId, event.payload.id);
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
case "message_created":
|
|
3202
|
+
await this.getOrCreateExecution(roomId).enqueue(event);
|
|
3203
|
+
return;
|
|
3204
|
+
default:
|
|
3205
|
+
assertNever3(event);
|
|
3206
|
+
}
|
|
3207
|
+
};
|
|
3208
|
+
this.presence.onContactEvent = this.onContactEvent ?? null;
|
|
2916
3209
|
}
|
|
2917
3210
|
async start() {
|
|
2918
3211
|
if (this.running) {
|
|
@@ -2921,45 +3214,17 @@ var AgentRuntime = class {
|
|
|
2921
3214
|
this.running = true;
|
|
2922
3215
|
this.stopping = false;
|
|
2923
3216
|
this.fatalError = null;
|
|
2924
|
-
if (!this.stopController.signal.aborted) {
|
|
2925
|
-
this.stopController.abort();
|
|
2926
|
-
}
|
|
2927
|
-
this.stopController = new AbortController();
|
|
2928
3217
|
try {
|
|
2929
|
-
await this.
|
|
3218
|
+
await this.presence.start();
|
|
2930
3219
|
} catch (error) {
|
|
2931
3220
|
await this.handleStartFailure();
|
|
2932
3221
|
throw error;
|
|
2933
3222
|
}
|
|
2934
|
-
|
|
2935
|
-
await this.link.subscribeAgentRooms();
|
|
2936
|
-
} catch {
|
|
2937
|
-
this.logger.warn("AgentRuntime failed to subscribe agent_rooms channel, continuing without it");
|
|
2938
|
-
}
|
|
2939
|
-
try {
|
|
2940
|
-
await this.subscribeExistingRooms();
|
|
2941
|
-
} catch (error) {
|
|
2942
|
-
await this.handleStartFailure();
|
|
2943
|
-
throw error;
|
|
2944
|
-
}
|
|
2945
|
-
this.consumeTask = this.consumeLoop(this.stopController.signal);
|
|
2946
|
-
if (!this.link.capabilities.contacts) {
|
|
2947
|
-
return;
|
|
2948
|
-
}
|
|
2949
|
-
try {
|
|
2950
|
-
await this.link.subscribeAgentContacts();
|
|
2951
|
-
} catch {
|
|
2952
|
-
this.logger.warn("AgentRuntime failed to subscribe agent_contacts channel, continuing without it");
|
|
2953
|
-
}
|
|
3223
|
+
void this.presence.waitUntilStopped().catch((error) => this.failRuntime(error, syntheticRuntimeFailureEvent(this.agentId)));
|
|
2954
3224
|
}
|
|
2955
3225
|
async handleStartFailure() {
|
|
2956
3226
|
this.running = false;
|
|
2957
3227
|
this.stopping = false;
|
|
2958
|
-
this.stopController.abort();
|
|
2959
|
-
if (this.consumeTask) {
|
|
2960
|
-
await this.consumeTask;
|
|
2961
|
-
this.consumeTask = null;
|
|
2962
|
-
}
|
|
2963
3228
|
await this.link.disconnect();
|
|
2964
3229
|
}
|
|
2965
3230
|
async stop(timeoutMs) {
|
|
@@ -2968,34 +3233,25 @@ var AgentRuntime = class {
|
|
|
2968
3233
|
}
|
|
2969
3234
|
this.stopping = true;
|
|
2970
3235
|
this.running = false;
|
|
2971
|
-
this.
|
|
2972
|
-
|
|
2973
|
-
await this.consumeTask;
|
|
2974
|
-
this.consumeTask = null;
|
|
2975
|
-
}
|
|
2976
|
-
const deadline = timeoutMs === void 0 ? void 0 : Date.now() + timeoutMs;
|
|
3236
|
+
this.presence.abortEventLoop();
|
|
3237
|
+
await this.presence.waitUntilStopped().catch(() => void 0);
|
|
2977
3238
|
let graceful = true;
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
}
|
|
3239
|
+
await Promise.all(
|
|
3240
|
+
[...this.executions].map(async ([roomId, execution]) => {
|
|
3241
|
+
const stopped = await execution.stop(timeoutMs);
|
|
3242
|
+
if (!stopped) {
|
|
3243
|
+
graceful = false;
|
|
3244
|
+
}
|
|
3245
|
+
this.executions.delete(roomId);
|
|
3246
|
+
})
|
|
3247
|
+
);
|
|
3248
|
+
await this.presence.stop();
|
|
2989
3249
|
for (const roomId of [...this.contexts.keys()]) {
|
|
2990
3250
|
await this.onSessionCleanup(roomId);
|
|
2991
3251
|
}
|
|
2992
|
-
this.subscribedRooms.clear();
|
|
2993
3252
|
this.contexts.clear();
|
|
2994
3253
|
this.executions.clear();
|
|
2995
3254
|
this.executionWatchers.clear();
|
|
2996
|
-
if (this.link.capabilities.contacts) {
|
|
2997
|
-
await this.link.unsubscribeAgentContacts();
|
|
2998
|
-
}
|
|
2999
3255
|
await this.link.disconnect();
|
|
3000
3256
|
if (this.fatalError) {
|
|
3001
3257
|
throw this.fatalError instanceof Error ? this.fatalError : new Error(String(this.fatalError));
|
|
@@ -3006,11 +3262,7 @@ var AgentRuntime = class {
|
|
|
3006
3262
|
return this.contexts.get(roomId);
|
|
3007
3263
|
}
|
|
3008
3264
|
async waitUntilStopped() {
|
|
3009
|
-
|
|
3010
|
-
await this.consumeTask;
|
|
3011
|
-
} else {
|
|
3012
|
-
await this.link.runForever(this.stopController.signal);
|
|
3013
|
-
}
|
|
3265
|
+
await this.presence.waitUntilStopped().catch(() => void 0);
|
|
3014
3266
|
if (this.fatalError) {
|
|
3015
3267
|
throw this.fatalError instanceof Error ? this.fatalError : new Error(String(this.fatalError));
|
|
3016
3268
|
}
|
|
@@ -3018,97 +3270,19 @@ var AgentRuntime = class {
|
|
|
3018
3270
|
getContexts() {
|
|
3019
3271
|
return [...this.contexts.values()];
|
|
3020
3272
|
}
|
|
3021
|
-
async consumeLoop(signal) {
|
|
3022
|
-
while (!signal.aborted) {
|
|
3023
|
-
let event;
|
|
3024
|
-
try {
|
|
3025
|
-
event = await this.link.nextEvent(signal);
|
|
3026
|
-
} catch (error) {
|
|
3027
|
-
await this.failRuntime(error, syntheticRuntimeFailureEvent(this.agentId));
|
|
3028
|
-
return;
|
|
3029
|
-
}
|
|
3030
|
-
if (!event) {
|
|
3031
|
-
return;
|
|
3032
|
-
}
|
|
3033
|
-
try {
|
|
3034
|
-
await this.handleEvent(event);
|
|
3035
|
-
} catch (error) {
|
|
3036
|
-
await this.failRuntime(error, event);
|
|
3037
|
-
return;
|
|
3038
|
-
}
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
async handleEvent(event) {
|
|
3042
|
-
switch (event.type) {
|
|
3043
|
-
case "room_added":
|
|
3044
|
-
await trackRoomJoin({
|
|
3045
|
-
link: this.link,
|
|
3046
|
-
roomId: event.roomId,
|
|
3047
|
-
payload: event.payload,
|
|
3048
|
-
trackedRooms: this.subscribedRooms,
|
|
3049
|
-
roomFilter: this.roomFilter,
|
|
3050
|
-
onJoined: async (roomId) => {
|
|
3051
|
-
this.getOrCreateExecution(roomId);
|
|
3052
|
-
await this.onRoomJoined?.(roomId, event.payload);
|
|
3053
|
-
}
|
|
3054
|
-
});
|
|
3055
|
-
return;
|
|
3056
|
-
case "room_removed":
|
|
3057
|
-
case "room_deleted":
|
|
3058
|
-
if (event.roomId) {
|
|
3059
|
-
await this.onRoomLeft?.(event.roomId);
|
|
3060
|
-
await this.leaveTrackedRoom(event.roomId);
|
|
3061
|
-
}
|
|
3062
|
-
return;
|
|
3063
|
-
case "participant_added":
|
|
3064
|
-
if (event.roomId) {
|
|
3065
|
-
const context = this.getOrCreateContext(event.roomId);
|
|
3066
|
-
const participant = {
|
|
3067
|
-
id: event.payload.id,
|
|
3068
|
-
name: event.payload.name,
|
|
3069
|
-
type: event.payload.type,
|
|
3070
|
-
handle: event.payload.handle
|
|
3071
|
-
};
|
|
3072
|
-
context.addParticipant(participant);
|
|
3073
|
-
await this.onParticipantAdded?.(event.roomId, participant);
|
|
3074
|
-
}
|
|
3075
|
-
return;
|
|
3076
|
-
case "participant_removed":
|
|
3077
|
-
if (event.roomId) {
|
|
3078
|
-
const context = this.getOrCreateContext(event.roomId);
|
|
3079
|
-
context.removeParticipant(event.payload.id);
|
|
3080
|
-
await this.onParticipantRemoved?.(event.roomId, event.payload.id);
|
|
3081
|
-
}
|
|
3082
|
-
return;
|
|
3083
|
-
case "contact_request_received":
|
|
3084
|
-
case "contact_request_updated":
|
|
3085
|
-
case "contact_added":
|
|
3086
|
-
case "contact_removed":
|
|
3087
|
-
await this.onContactEvent?.(event);
|
|
3088
|
-
return;
|
|
3089
|
-
case "message_created":
|
|
3090
|
-
if (!event.roomId) {
|
|
3091
|
-
return;
|
|
3092
|
-
}
|
|
3093
|
-
await this.getOrCreateExecution(event.roomId).enqueue(event);
|
|
3094
|
-
return;
|
|
3095
|
-
}
|
|
3096
|
-
return assertNever2(event);
|
|
3097
|
-
}
|
|
3098
3273
|
async enqueueEvent(roomId, event) {
|
|
3099
3274
|
await this.getOrCreateExecution(roomId).enqueue(event);
|
|
3100
3275
|
}
|
|
3101
3276
|
async bootstrapRoomMessage(roomId, message) {
|
|
3102
|
-
await this.
|
|
3103
|
-
this.subscribedRooms.add(roomId);
|
|
3277
|
+
await this.presence.admitRoomOrThrow(roomId);
|
|
3104
3278
|
await this.getOrCreateExecution(roomId).bootstrapMessage(message);
|
|
3105
3279
|
}
|
|
3106
3280
|
async resetRoomSession(roomId, timeoutMs) {
|
|
3281
|
+
return this.teardownExecution(roomId, timeoutMs);
|
|
3282
|
+
}
|
|
3283
|
+
async teardownExecution(roomId, timeoutMs) {
|
|
3107
3284
|
const execution = this.executions.get(roomId);
|
|
3108
|
-
|
|
3109
|
-
if (execution) {
|
|
3110
|
-
graceful = await execution.stop(timeoutMs);
|
|
3111
|
-
}
|
|
3285
|
+
const graceful = execution ? await execution.stop(timeoutMs) : true;
|
|
3112
3286
|
this.executions.delete(roomId);
|
|
3113
3287
|
this.contexts.delete(roomId);
|
|
3114
3288
|
await this.onSessionCleanup(roomId);
|
|
@@ -3164,44 +3338,13 @@ var AgentRuntime = class {
|
|
|
3164
3338
|
maxMessageRetries: this.sessionConfig.maxMessageRetries,
|
|
3165
3339
|
enableContextCache: this.sessionConfig.enableContextCache,
|
|
3166
3340
|
contextCacheTtlSeconds: this.sessionConfig.contextCacheTtlSeconds,
|
|
3167
|
-
enableContextHydration: this.sessionConfig.enableContextHydration
|
|
3341
|
+
enableContextHydration: this.sessionConfig.enableContextHydration,
|
|
3342
|
+
logger: this.logger
|
|
3168
3343
|
};
|
|
3169
3344
|
const context = this.contextFactory ? this.contextFactory(roomId, defaults) : new ExecutionContext(defaults);
|
|
3170
3345
|
this.contexts.set(roomId, context);
|
|
3171
3346
|
return context;
|
|
3172
3347
|
}
|
|
3173
|
-
async subscribeExistingRooms() {
|
|
3174
|
-
if (!this.autoSubscribeExistingRooms) {
|
|
3175
|
-
return;
|
|
3176
|
-
}
|
|
3177
|
-
await hydrateTrackedRooms({
|
|
3178
|
-
link: this.link,
|
|
3179
|
-
trackedRooms: this.subscribedRooms,
|
|
3180
|
-
roomFilter: this.roomFilter,
|
|
3181
|
-
onJoined: async (roomId, payload) => {
|
|
3182
|
-
this.getOrCreateExecution(roomId);
|
|
3183
|
-
await this.onRoomJoined?.(roomId, payload);
|
|
3184
|
-
},
|
|
3185
|
-
onError: async (error) => {
|
|
3186
|
-
this.logger.warn("AgentRuntime failed to subscribe existing rooms", {
|
|
3187
|
-
error
|
|
3188
|
-
});
|
|
3189
|
-
}
|
|
3190
|
-
});
|
|
3191
|
-
}
|
|
3192
|
-
async leaveTrackedRoom(roomId, timeoutMs) {
|
|
3193
|
-
await trackRoomLeave({
|
|
3194
|
-
link: this.link,
|
|
3195
|
-
roomId,
|
|
3196
|
-
trackedRooms: this.subscribedRooms,
|
|
3197
|
-
onLeft: async (leftRoomId) => {
|
|
3198
|
-
await this.executions.get(leftRoomId)?.stop(timeoutMs);
|
|
3199
|
-
this.contexts.delete(leftRoomId);
|
|
3200
|
-
this.executions.delete(leftRoomId);
|
|
3201
|
-
await this.onSessionCleanup(leftRoomId);
|
|
3202
|
-
}
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3205
3348
|
async failRuntime(error, event) {
|
|
3206
3349
|
if (!this.fatalError) {
|
|
3207
3350
|
this.fatalError = error;
|
|
@@ -3213,9 +3356,7 @@ var AgentRuntime = class {
|
|
|
3213
3356
|
});
|
|
3214
3357
|
this.notifyOnError(error, event);
|
|
3215
3358
|
}
|
|
3216
|
-
|
|
3217
|
-
this.stopController.abort();
|
|
3218
|
-
}
|
|
3359
|
+
this.presence.abortEventLoop();
|
|
3219
3360
|
}
|
|
3220
3361
|
notifyOnError(error, event) {
|
|
3221
3362
|
if (!this.onError) {
|
|
@@ -3232,6 +3373,9 @@ var AgentRuntime = class {
|
|
|
3232
3373
|
}
|
|
3233
3374
|
}
|
|
3234
3375
|
};
|
|
3376
|
+
function assertNever3(value) {
|
|
3377
|
+
throw new Error(`Unhandled room event: ${JSON.stringify(value)}`);
|
|
3378
|
+
}
|
|
3235
3379
|
function syntheticRuntimeFailureEvent(agentId) {
|
|
3236
3380
|
return {
|
|
3237
3381
|
type: "message_created",
|
|
@@ -3249,9 +3393,6 @@ function syntheticRuntimeFailureEvent(agentId) {
|
|
|
3249
3393
|
}
|
|
3250
3394
|
};
|
|
3251
3395
|
}
|
|
3252
|
-
function assertNever2(value) {
|
|
3253
|
-
throw new Error(`Unhandled platform event: ${JSON.stringify(value)}`);
|
|
3254
|
-
}
|
|
3255
3396
|
|
|
3256
3397
|
// src/client/rest/pagination.ts
|
|
3257
3398
|
var DEFAULT_PAGE_SIZE = 100;
|
|
@@ -5293,6 +5434,9 @@ var PlatformRuntime = class {
|
|
|
5293
5434
|
this.stopping = false;
|
|
5294
5435
|
return graceful;
|
|
5295
5436
|
}
|
|
5437
|
+
async [Symbol.asyncDispose]() {
|
|
5438
|
+
await this.stop();
|
|
5439
|
+
}
|
|
5296
5440
|
async runForever() {
|
|
5297
5441
|
if (!this.runtime) {
|
|
5298
5442
|
throw new RuntimeStateError("Runtime not started");
|
|
@@ -5343,129 +5487,8 @@ var PlatformRuntime = class {
|
|
|
5343
5487
|
}
|
|
5344
5488
|
};
|
|
5345
5489
|
|
|
5346
|
-
// src/runtime/rooms/RoomPresence.ts
|
|
5347
|
-
var RoomPresence = class {
|
|
5348
|
-
rooms = /* @__PURE__ */ new Set();
|
|
5349
|
-
onRoomJoined = null;
|
|
5350
|
-
onRoomLeft = null;
|
|
5351
|
-
onRoomEvent = null;
|
|
5352
|
-
onContactEvent = null;
|
|
5353
|
-
link;
|
|
5354
|
-
roomFilter;
|
|
5355
|
-
autoSubscribeExistingRooms;
|
|
5356
|
-
logger;
|
|
5357
|
-
eventController = null;
|
|
5358
|
-
eventTask = null;
|
|
5359
|
-
contactsSubscribed = false;
|
|
5360
|
-
constructor(options) {
|
|
5361
|
-
this.link = options.link;
|
|
5362
|
-
this.roomFilter = options.roomFilter;
|
|
5363
|
-
this.autoSubscribeExistingRooms = options.autoSubscribeExistingRooms ?? true;
|
|
5364
|
-
this.logger = options.logger ?? new NoopLogger();
|
|
5365
|
-
}
|
|
5366
|
-
async start() {
|
|
5367
|
-
if (this.eventTask) {
|
|
5368
|
-
return;
|
|
5369
|
-
}
|
|
5370
|
-
if (!this.link.isConnected()) {
|
|
5371
|
-
await this.link.connect();
|
|
5372
|
-
}
|
|
5373
|
-
try {
|
|
5374
|
-
await this.link.subscribeAgentRooms();
|
|
5375
|
-
} catch {
|
|
5376
|
-
}
|
|
5377
|
-
if (this.autoSubscribeExistingRooms) {
|
|
5378
|
-
await this.subscribeExistingRooms();
|
|
5379
|
-
}
|
|
5380
|
-
if (this.link.capabilities.contacts) {
|
|
5381
|
-
await this.link.subscribeAgentContacts();
|
|
5382
|
-
this.contactsSubscribed = true;
|
|
5383
|
-
}
|
|
5384
|
-
this.eventController = new AbortController();
|
|
5385
|
-
this.eventTask = this.consumeEvents(this.eventController.signal);
|
|
5386
|
-
}
|
|
5387
|
-
async stop() {
|
|
5388
|
-
this.eventController?.abort();
|
|
5389
|
-
await this.eventTask;
|
|
5390
|
-
this.eventTask = null;
|
|
5391
|
-
this.eventController = null;
|
|
5392
|
-
if (this.contactsSubscribed) {
|
|
5393
|
-
await this.link.unsubscribeAgentContacts();
|
|
5394
|
-
this.contactsSubscribed = false;
|
|
5395
|
-
}
|
|
5396
|
-
for (const roomId of [...this.rooms]) {
|
|
5397
|
-
await trackRoomLeave({
|
|
5398
|
-
link: this.link,
|
|
5399
|
-
roomId,
|
|
5400
|
-
trackedRooms: this.rooms,
|
|
5401
|
-
onLeft: this.onRoomLeft ?? void 0
|
|
5402
|
-
});
|
|
5403
|
-
}
|
|
5404
|
-
}
|
|
5405
|
-
async consumeEvents(signal) {
|
|
5406
|
-
while (!signal.aborted) {
|
|
5407
|
-
const event = await this.link.nextEvent(signal);
|
|
5408
|
-
if (!event) {
|
|
5409
|
-
return;
|
|
5410
|
-
}
|
|
5411
|
-
switch (event.type) {
|
|
5412
|
-
case "room_added":
|
|
5413
|
-
await this.handleRoomAdded(event.roomId, event.payload);
|
|
5414
|
-
break;
|
|
5415
|
-
case "room_removed":
|
|
5416
|
-
case "room_deleted":
|
|
5417
|
-
await this.handleRoomRemoved(event.roomId);
|
|
5418
|
-
break;
|
|
5419
|
-
case "contact_request_received":
|
|
5420
|
-
case "contact_request_updated":
|
|
5421
|
-
case "contact_added":
|
|
5422
|
-
case "contact_removed":
|
|
5423
|
-
await this.onContactEvent?.(event);
|
|
5424
|
-
break;
|
|
5425
|
-
default:
|
|
5426
|
-
if (event.roomId && this.rooms.has(event.roomId)) {
|
|
5427
|
-
await this.onRoomEvent?.(event.roomId, event);
|
|
5428
|
-
}
|
|
5429
|
-
break;
|
|
5430
|
-
}
|
|
5431
|
-
}
|
|
5432
|
-
}
|
|
5433
|
-
async handleRoomAdded(roomId, payload) {
|
|
5434
|
-
await trackRoomJoin({
|
|
5435
|
-
link: this.link,
|
|
5436
|
-
roomId,
|
|
5437
|
-
payload,
|
|
5438
|
-
trackedRooms: this.rooms,
|
|
5439
|
-
roomFilter: this.roomFilter,
|
|
5440
|
-
onJoined: this.onRoomJoined ?? void 0
|
|
5441
|
-
});
|
|
5442
|
-
}
|
|
5443
|
-
async handleRoomRemoved(roomId) {
|
|
5444
|
-
await trackRoomLeave({
|
|
5445
|
-
link: this.link,
|
|
5446
|
-
roomId,
|
|
5447
|
-
trackedRooms: this.rooms,
|
|
5448
|
-
onLeft: this.onRoomLeft ?? void 0
|
|
5449
|
-
});
|
|
5450
|
-
}
|
|
5451
|
-
async subscribeExistingRooms() {
|
|
5452
|
-
await hydrateTrackedRooms({
|
|
5453
|
-
link: this.link,
|
|
5454
|
-
trackedRooms: this.rooms,
|
|
5455
|
-
requestOptions: DEFAULT_REQUEST_OPTIONS,
|
|
5456
|
-
roomFilter: this.roomFilter,
|
|
5457
|
-
onJoined: this.onRoomJoined ?? void 0,
|
|
5458
|
-
onError: async (error) => {
|
|
5459
|
-
this.logger.warn("RoomPresence failed to subscribe existing rooms", {
|
|
5460
|
-
error
|
|
5461
|
-
});
|
|
5462
|
-
}
|
|
5463
|
-
});
|
|
5464
|
-
}
|
|
5465
|
-
};
|
|
5466
|
-
|
|
5467
5490
|
// src/runtime/index.ts
|
|
5468
|
-
var
|
|
5491
|
+
var import_band_sdk_core4 = require("@band-ai/band-sdk-core");
|
|
5469
5492
|
|
|
5470
5493
|
// src/runtime/prompts/base.ts
|
|
5471
5494
|
var ENVIRONMENT_SECTION = `
|
|
@@ -5719,6 +5742,7 @@ async function runWithGracefulShutdown(agent, options) {
|
|
|
5719
5742
|
PlatformRuntime,
|
|
5720
5743
|
RetryTracker,
|
|
5721
5744
|
RoomPresence,
|
|
5745
|
+
RoomRoster,
|
|
5722
5746
|
SYNTHETIC_CONTACT_EVENTS_SENDER_ID,
|
|
5723
5747
|
SYNTHETIC_CONTACT_EVENTS_SENDER_NAME,
|
|
5724
5748
|
SYNTHETIC_SENDER_TYPE,
|
|
@@ -5732,6 +5756,7 @@ async function runWithGracefulShutdown(agent, options) {
|
|
|
5732
5756
|
getToolDescription,
|
|
5733
5757
|
isChatEventType,
|
|
5734
5758
|
mcpToolNames,
|
|
5759
|
+
mentionSubjectsFromMetadata,
|
|
5735
5760
|
renderSystemPrompt,
|
|
5736
5761
|
replaceUuidMentions,
|
|
5737
5762
|
runWithGracefulShutdown
|