@band-ai/sdk 0.1.6 → 0.2.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 +372 -0
- package/dist/{ClaudeSDKAdapter-CRq4R-WB.d.cts → ClaudeSDKAdapter-BY4zEbCl.d.cts} +14 -10
- package/dist/{ClaudeSDKAdapter-BHOkjN3X.d.ts → ClaudeSDKAdapter-Cna5P1dR.d.ts} +14 -10
- package/dist/{acp-server-B1Da7L6u.d.ts → acp-server-CiUqN3G3.d.ts} +2 -2
- package/dist/{acp-server-BdRz9_UN.d.cts → acp-server-Dlj7D563.d.cts} +2 -2
- package/dist/adapters.cjs +734 -279
- package/dist/adapters.d.cts +21 -19
- package/dist/adapters.d.ts +21 -19
- package/dist/adapters.js +65 -44
- package/dist/backends-D-dBdDm-.d.ts +27 -0
- package/dist/backends-ZLxmQrTZ.d.cts +27 -0
- package/dist/{chunk-MSL6CWHY.js → chunk-4IAXZBXX.js} +77 -37
- package/dist/{chunk-SG4WLD2H.js → chunk-EAI2M3WM.js} +38 -94
- package/dist/{chunk-YR3BOQNW.js → chunk-JY75VSQK.js} +7 -7
- package/dist/{chunk-INA6YZTZ.js → chunk-LBWKISBS.js} +51 -31
- package/dist/{chunk-I5EZG52P.js → chunk-N2QTUMGO.js} +532 -327
- package/dist/{chunk-RHVH2GZR.js → chunk-NMZLX7TP.js} +110 -56
- package/dist/{chunk-EDPKUUJL.js → chunk-NT7TBFX2.js} +9 -1
- package/dist/{chunk-GVEQ3RAH.js → chunk-RV76SKFT.js} +169 -54
- package/dist/{chunk-W5NDZSYE.js → chunk-TLBCKDQO.js} +23 -23
- package/dist/chunk-US226AS4.js +130 -0
- package/dist/{chunk-IZPV6QS6.js → chunk-WL2HNJZ6.js} +38 -11
- package/dist/chunk-WLCM2OXG.js +181 -0
- package/dist/config.cjs +40 -13
- package/dist/config.d.cts +7 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.js +2 -2
- package/dist/converters.cjs +491 -35
- package/dist/converters.d.cts +5 -5
- package/dist/converters.d.ts +5 -5
- package/dist/converters.js +4 -3
- package/dist/core.cjs +53 -10
- package/dist/core.d.cts +10 -9
- package/dist/core.d.ts +10 -9
- package/dist/core.js +8 -4
- package/dist/disconnectReason-IuADl6TH.d.cts +34 -0
- package/dist/disconnectReason-IuADl6TH.d.ts +34 -0
- package/dist/{dtos-DUpbIu8k.d.ts → dtos-B8KU_q4d.d.cts} +26 -6
- package/dist/{dtos-DUpbIu8k.d.cts → dtos-B8KU_q4d.d.ts} +26 -6
- package/dist/index.cjs +1510 -735
- package/dist/index.d.cts +18 -16
- package/dist/index.d.ts +18 -16
- package/dist/index.js +21 -13
- package/dist/linear.cjs +1044 -112
- package/dist/linear.d.cts +146 -16
- package/dist/linear.d.ts +146 -16
- package/dist/linear.js +1031 -110
- package/dist/mcp-claude.cjs +338 -66
- package/dist/mcp-claude.d.cts +3 -3
- package/dist/mcp-claude.d.ts +3 -3
- package/dist/mcp-claude.js +215 -16
- package/dist/mcp.cjs +414 -105
- package/dist/mcp.d.cts +29 -16
- package/dist/mcp.d.ts +29 -16
- package/dist/mcp.js +14 -14
- package/dist/{opencode-BBcDchcN.d.cts → opencode-2YdscIc1.d.cts} +5 -5
- package/dist/{opencode-DthQQUsZ.d.ts → opencode-Bld62x5t.d.ts} +5 -5
- package/dist/{pagination-CcDkVFxK.d.ts → pagination-BgEx-HeL.d.ts} +2 -2
- package/dist/{pagination-BPiys10t.d.cts → pagination-DqdkQArT.d.cts} +2 -2
- package/dist/{protocols-DrhzOH6K.d.ts → protocols-Bwwcql0h.d.ts} +1 -1
- package/dist/{protocols-CInhtFpA.d.cts → protocols-Bz1rxcUg.d.cts} +1 -1
- package/dist/rest.cjs +41 -97
- package/dist/rest.d.cts +7 -7
- package/dist/rest.d.ts +7 -7
- package/dist/rest.js +2 -2
- package/dist/runtime.cjs +998 -620
- package/dist/runtime.d.cts +22 -29
- package/dist/runtime.d.ts +22 -29
- package/dist/runtime.js +19 -67
- package/dist/{schemas-BpEBkq5V.d.cts → schemas-BotL3ZLH.d.cts} +51 -56
- package/dist/{schemas-vos1AaBc.d.ts → schemas-DBsC4J1g.d.ts} +51 -56
- package/dist/{sdk-CwTAxhwI.d.cts → sdk-BTciSLRQ.d.cts} +35 -5
- package/dist/{sdk-CcnQ5OUC.d.ts → sdk-qKJtMma_.d.ts} +35 -5
- package/dist/{simpleAdapter-9OE_p6QW.d.ts → simpleAdapter--wznuoOw.d.ts} +1 -1
- package/dist/{simpleAdapter-DqhvjsGr.d.cts → simpleAdapter-BpT4XbZC.d.cts} +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/{types-7jVzOeOP.d.ts → types-BTN_ZETM.d.ts} +2 -2
- package/dist/{types-CxII3XkA.d.ts → types-BgYFd_Yw.d.cts} +5 -5
- package/dist/{types-CSHFipIc.d.cts → types-BivGO7I9.d.ts} +5 -5
- package/dist/{types-CovcHpYf.d.cts → types-D958TC71.d.cts} +2 -2
- package/package.json +25 -23
- package/dist/backends-CzDbiQar.d.ts +0 -20
- package/dist/backends-SVMT-7l4.d.cts +0 -20
- package/dist/chunk-SFVKOEQH.js +0 -103
package/dist/index.cjs
CHANGED
|
@@ -31,35 +31,35 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
33
|
// src/core/errors.ts
|
|
34
|
-
var
|
|
34
|
+
var BandSdkError, UnsupportedFeatureError, ValidationError, TransportError, RuntimeStateError;
|
|
35
35
|
var init_errors = __esm({
|
|
36
36
|
"src/core/errors.ts"() {
|
|
37
37
|
"use strict";
|
|
38
|
-
|
|
38
|
+
BandSdkError = class extends Error {
|
|
39
39
|
constructor(message, cause) {
|
|
40
40
|
super(message, cause !== void 0 ? { cause } : void 0);
|
|
41
|
-
this.name = "
|
|
41
|
+
this.name = "BandSdkError";
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
-
UnsupportedFeatureError = class extends
|
|
44
|
+
UnsupportedFeatureError = class extends BandSdkError {
|
|
45
45
|
constructor(message) {
|
|
46
46
|
super(message);
|
|
47
47
|
this.name = "UnsupportedFeatureError";
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
-
ValidationError = class extends
|
|
50
|
+
ValidationError = class extends BandSdkError {
|
|
51
51
|
constructor(message, cause) {
|
|
52
52
|
super(message, cause);
|
|
53
53
|
this.name = "ValidationError";
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
-
TransportError = class extends
|
|
56
|
+
TransportError = class extends BandSdkError {
|
|
57
57
|
constructor(message, cause) {
|
|
58
58
|
super(message, cause);
|
|
59
59
|
this.name = "TransportError";
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
|
-
RuntimeStateError = class extends
|
|
62
|
+
RuntimeStateError = class extends BandSdkError {
|
|
63
63
|
constructor(message) {
|
|
64
64
|
super(message);
|
|
65
65
|
this.name = "RuntimeStateError";
|
|
@@ -133,6 +133,114 @@ var init_chatEvents = __esm({
|
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
+
// src/contracts/memory.ts
|
|
137
|
+
function namedValues(values) {
|
|
138
|
+
return Object.fromEntries(values.map((value) => [value, value]));
|
|
139
|
+
}
|
|
140
|
+
function isMemorySystem(value) {
|
|
141
|
+
return MEMORY_SYSTEMS.includes(value);
|
|
142
|
+
}
|
|
143
|
+
function isMemoryType(value) {
|
|
144
|
+
return MEMORY_TYPES.includes(value);
|
|
145
|
+
}
|
|
146
|
+
function isMemoryTypeForSystem(system, type) {
|
|
147
|
+
return MEMORY_SYSTEM_TYPES[system].includes(type);
|
|
148
|
+
}
|
|
149
|
+
function isMemorySegment(value) {
|
|
150
|
+
return MEMORY_SEGMENTS.includes(value);
|
|
151
|
+
}
|
|
152
|
+
function isMemoryStoreScope(value) {
|
|
153
|
+
return MEMORY_STORE_SCOPES.includes(value);
|
|
154
|
+
}
|
|
155
|
+
function isMemoryListScope(value) {
|
|
156
|
+
return MEMORY_LIST_SCOPES.includes(value);
|
|
157
|
+
}
|
|
158
|
+
function isMemoryStatus(value) {
|
|
159
|
+
return MEMORY_STATUSES.includes(value);
|
|
160
|
+
}
|
|
161
|
+
function expectedList(values) {
|
|
162
|
+
return values.join(", ");
|
|
163
|
+
}
|
|
164
|
+
function expectedMemoryTypesForSystem(system) {
|
|
165
|
+
return expectedList(MEMORY_SYSTEM_TYPES[system]);
|
|
166
|
+
}
|
|
167
|
+
function memoryTypeForSystemError(system) {
|
|
168
|
+
return `type must be one of: ${expectedMemoryTypesForSystem(system)} for system "${system}"`;
|
|
169
|
+
}
|
|
170
|
+
var SENSORY_MEMORY_TYPES, COGNITIVE_MEMORY_TYPES, MEMORY_SYSTEM_TYPES, MEMORY_SYSTEMS, MEMORY_TYPES, MEMORY_SEGMENTS, MEMORY_STORE_SCOPES, MEMORY_LIST_SCOPES, MEMORY_STATUSES, MEMORY_SYSTEM, MEMORY_TYPE, MEMORY_SEGMENT, MEMORY_STORE_SCOPE;
|
|
171
|
+
var init_memory = __esm({
|
|
172
|
+
"src/contracts/memory.ts"() {
|
|
173
|
+
"use strict";
|
|
174
|
+
SENSORY_MEMORY_TYPES = [
|
|
175
|
+
"iconic",
|
|
176
|
+
// Visual input
|
|
177
|
+
"echoic",
|
|
178
|
+
// Auditory input
|
|
179
|
+
"haptic"
|
|
180
|
+
// Tactile input
|
|
181
|
+
];
|
|
182
|
+
COGNITIVE_MEMORY_TYPES = [
|
|
183
|
+
"episodic",
|
|
184
|
+
// Events that occurred
|
|
185
|
+
"semantic",
|
|
186
|
+
// Facts, preferences, learned knowledge
|
|
187
|
+
"procedural"
|
|
188
|
+
// How to perform tasks
|
|
189
|
+
];
|
|
190
|
+
MEMORY_SYSTEM_TYPES = {
|
|
191
|
+
sensory: SENSORY_MEMORY_TYPES,
|
|
192
|
+
// Brief sensory inputs
|
|
193
|
+
working: COGNITIVE_MEMORY_TYPES,
|
|
194
|
+
// Short-term session context
|
|
195
|
+
long_term: COGNITIVE_MEMORY_TYPES
|
|
196
|
+
// Persistent cross-conversation memory
|
|
197
|
+
};
|
|
198
|
+
MEMORY_SYSTEMS = Object.keys(MEMORY_SYSTEM_TYPES);
|
|
199
|
+
MEMORY_TYPES = [
|
|
200
|
+
...SENSORY_MEMORY_TYPES,
|
|
201
|
+
...COGNITIVE_MEMORY_TYPES
|
|
202
|
+
];
|
|
203
|
+
MEMORY_SEGMENTS = [
|
|
204
|
+
"user",
|
|
205
|
+
// User preferences or profile info
|
|
206
|
+
"agent",
|
|
207
|
+
// Facts or events about agents/entities
|
|
208
|
+
"tool",
|
|
209
|
+
// Tool usage or task procedures
|
|
210
|
+
"guideline"
|
|
211
|
+
// Behavioral rules or policies
|
|
212
|
+
];
|
|
213
|
+
MEMORY_STORE_SCOPES = [
|
|
214
|
+
"subject",
|
|
215
|
+
// About one person/agent; requires subject_id
|
|
216
|
+
"organization"
|
|
217
|
+
// Shared org-wide
|
|
218
|
+
];
|
|
219
|
+
MEMORY_LIST_SCOPES = [
|
|
220
|
+
"subject",
|
|
221
|
+
// Subject-scoped memories only
|
|
222
|
+
"organization",
|
|
223
|
+
// Organization-scoped memories only
|
|
224
|
+
"all"
|
|
225
|
+
// Both scopes (no scope filter)
|
|
226
|
+
];
|
|
227
|
+
MEMORY_STATUSES = [
|
|
228
|
+
"active",
|
|
229
|
+
// Normal, visible memories
|
|
230
|
+
"superseded",
|
|
231
|
+
// Outdated; soft-deleted via band_supersede_memory
|
|
232
|
+
"archived",
|
|
233
|
+
// Hidden but preserved via band_archive_memory
|
|
234
|
+
"all"
|
|
235
|
+
// Any status (no filter)
|
|
236
|
+
];
|
|
237
|
+
MEMORY_SYSTEM = namedValues(MEMORY_SYSTEMS);
|
|
238
|
+
MEMORY_TYPE = namedValues(MEMORY_TYPES);
|
|
239
|
+
MEMORY_SEGMENT = namedValues(MEMORY_SEGMENTS);
|
|
240
|
+
MEMORY_STORE_SCOPE = namedValues(MEMORY_STORE_SCOPES);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
136
244
|
// src/runtime/tools/schemas.ts
|
|
137
245
|
function mcpToolNames(names) {
|
|
138
246
|
return [...names].sort((a, b) => a.localeCompare(b)).map((name) => `${MCP_TOOL_PREFIX}${name}`);
|
|
@@ -141,13 +249,14 @@ function getToolDescription(name) {
|
|
|
141
249
|
const model = TOOL_MODELS[name];
|
|
142
250
|
return model?.description ?? `Execute ${name}`;
|
|
143
251
|
}
|
|
144
|
-
var TOOL_MODELS, ALL_TOOL_NAMES, MEMORY_TOOL_NAMES, CONTACT_TOOL_NAMES, BASE_TOOL_NAMES, CHAT_TOOL_NAMES, MCP_TOOL_PREFIX;
|
|
252
|
+
var TOOL_MODELS, ALL_TOOL_NAMES, MEMORY_TOOL_NAMES, CONTACT_TOOL_NAMES, BASE_TOOL_NAMES, CHAT_TOOL_NAMES, MCP_TOOL_PREFIX, MCP_SERVER_NAME, SEND_MESSAGE_TOOL_NAME, SEND_EVENT_TOOL_NAME;
|
|
145
253
|
var init_schemas = __esm({
|
|
146
254
|
"src/runtime/tools/schemas.ts"() {
|
|
147
255
|
"use strict";
|
|
148
256
|
init_chatEvents();
|
|
257
|
+
init_memory();
|
|
149
258
|
TOOL_MODELS = {
|
|
150
|
-
|
|
259
|
+
band_send_message: {
|
|
151
260
|
description: "Send a message to the chat room. Use this to respond to users or other agents. Messages require at least one @mention in the mentions array. You MUST use this tool to communicate \u2014 plain text responses won't reach users. When delegating, send the full task context in this message instead of assuming hidden state.",
|
|
152
261
|
properties: {
|
|
153
262
|
content: {
|
|
@@ -163,7 +272,7 @@ var init_schemas = __esm({
|
|
|
163
272
|
},
|
|
164
273
|
required: ["content", "mentions"]
|
|
165
274
|
},
|
|
166
|
-
|
|
275
|
+
band_send_event: {
|
|
167
276
|
description: "Send an event to the chat room. No mentions required. 'thought': Share your reasoning or plan BEFORE taking actions. Explain what you're about to do and why. 'error': Report an error or problem that occurred. 'task': Report task progress or completion status. Always send a thought before complex actions to keep users informed.",
|
|
168
277
|
properties: {
|
|
169
278
|
content: {
|
|
@@ -182,12 +291,12 @@ var init_schemas = __esm({
|
|
|
182
291
|
},
|
|
183
292
|
required: ["content", "message_type"]
|
|
184
293
|
},
|
|
185
|
-
|
|
186
|
-
description: "Add a participant (agent or user) to the chat room by name. IMPORTANT: Use
|
|
294
|
+
band_add_participant: {
|
|
295
|
+
description: "Add a participant (agent or user) to the chat room by name. IMPORTANT: Use band_lookup_peers() first to find available agents. Pass the exact peer name from band_lookup_peers, not the handle. For normal delegation, omit role or use 'member'.",
|
|
187
296
|
properties: {
|
|
188
297
|
name: {
|
|
189
298
|
type: "string",
|
|
190
|
-
description: "Name of participant to add (must match a name from
|
|
299
|
+
description: "Name of participant to add (must match a name from band_lookup_peers)."
|
|
191
300
|
},
|
|
192
301
|
role: {
|
|
193
302
|
type: "string",
|
|
@@ -197,7 +306,7 @@ var init_schemas = __esm({
|
|
|
197
306
|
},
|
|
198
307
|
required: ["name"]
|
|
199
308
|
},
|
|
200
|
-
|
|
309
|
+
band_remove_participant: {
|
|
201
310
|
description: "Remove a participant from the chat room by name.",
|
|
202
311
|
properties: {
|
|
203
312
|
name: {
|
|
@@ -207,12 +316,12 @@ var init_schemas = __esm({
|
|
|
207
316
|
},
|
|
208
317
|
required: ["name"]
|
|
209
318
|
},
|
|
210
|
-
|
|
319
|
+
band_get_participants: {
|
|
211
320
|
description: "Get a list of all participants in the current chat room.",
|
|
212
321
|
properties: {},
|
|
213
322
|
required: []
|
|
214
323
|
},
|
|
215
|
-
|
|
324
|
+
band_lookup_peers: {
|
|
216
325
|
description: "List available peers (agents and users) that can be added to this room. Automatically excludes peers already in the room. Returns dict with 'peers' list and 'metadata' (page, page_size, total_count, total_pages). Use this to find specialized agents (e.g., Weather Agent) when you cannot answer a question directly.",
|
|
217
326
|
properties: {
|
|
218
327
|
page: {
|
|
@@ -227,7 +336,7 @@ var init_schemas = __esm({
|
|
|
227
336
|
},
|
|
228
337
|
required: []
|
|
229
338
|
},
|
|
230
|
-
|
|
339
|
+
band_create_chatroom: {
|
|
231
340
|
description: "Create a new chat room for a specific task or conversation.",
|
|
232
341
|
properties: {
|
|
233
342
|
task_id: {
|
|
@@ -237,7 +346,7 @@ var init_schemas = __esm({
|
|
|
237
346
|
},
|
|
238
347
|
required: []
|
|
239
348
|
},
|
|
240
|
-
|
|
349
|
+
band_list_contacts: {
|
|
241
350
|
description: "List agent's contacts with pagination.",
|
|
242
351
|
properties: {
|
|
243
352
|
page: {
|
|
@@ -254,7 +363,7 @@ var init_schemas = __esm({
|
|
|
254
363
|
},
|
|
255
364
|
required: []
|
|
256
365
|
},
|
|
257
|
-
|
|
366
|
+
band_add_contact: {
|
|
258
367
|
description: "Send a contact request to add someone as a contact. Returns 'pending' when request is created. Returns 'approved' when inverse request existed and was auto-accepted.",
|
|
259
368
|
properties: {
|
|
260
369
|
handle: {
|
|
@@ -268,7 +377,7 @@ var init_schemas = __esm({
|
|
|
268
377
|
},
|
|
269
378
|
required: ["handle"]
|
|
270
379
|
},
|
|
271
|
-
|
|
380
|
+
band_remove_contact: {
|
|
272
381
|
description: "Remove an existing contact by handle or ID.",
|
|
273
382
|
properties: {
|
|
274
383
|
handle: {
|
|
@@ -282,7 +391,7 @@ var init_schemas = __esm({
|
|
|
282
391
|
},
|
|
283
392
|
required: []
|
|
284
393
|
},
|
|
285
|
-
|
|
394
|
+
band_list_contact_requests: {
|
|
286
395
|
description: "List both received and sent contact requests. Received requests are always filtered to pending status. Sent requests can be filtered by status.",
|
|
287
396
|
properties: {
|
|
288
397
|
page: {
|
|
@@ -304,7 +413,7 @@ var init_schemas = __esm({
|
|
|
304
413
|
},
|
|
305
414
|
required: []
|
|
306
415
|
},
|
|
307
|
-
|
|
416
|
+
band_respond_contact_request: {
|
|
308
417
|
description: "Respond to a contact request. 'approve'/'reject': For requests you RECEIVED (handle = requester's handle). 'cancel': For requests you SENT (handle = recipient's handle).",
|
|
309
418
|
properties: {
|
|
310
419
|
action: {
|
|
@@ -323,7 +432,7 @@ var init_schemas = __esm({
|
|
|
323
432
|
},
|
|
324
433
|
required: ["action"]
|
|
325
434
|
},
|
|
326
|
-
|
|
435
|
+
band_list_memories: {
|
|
327
436
|
description: "List memories accessible to the agent. Returns memories about the specified subject (cross-agent sharing) and organization-wide shared memories.",
|
|
328
437
|
properties: {
|
|
329
438
|
subject_id: {
|
|
@@ -332,29 +441,22 @@ var init_schemas = __esm({
|
|
|
332
441
|
},
|
|
333
442
|
scope: {
|
|
334
443
|
type: "string",
|
|
335
|
-
enum: [
|
|
444
|
+
enum: [...MEMORY_LIST_SCOPES],
|
|
336
445
|
description: "Filter by scope."
|
|
337
446
|
},
|
|
338
447
|
system: {
|
|
339
448
|
type: "string",
|
|
340
|
-
enum: [
|
|
449
|
+
enum: [...MEMORY_SYSTEMS],
|
|
341
450
|
description: "Filter by memory system."
|
|
342
451
|
},
|
|
343
452
|
type: {
|
|
344
453
|
type: "string",
|
|
345
|
-
enum: [
|
|
346
|
-
"iconic",
|
|
347
|
-
"echoic",
|
|
348
|
-
"haptic",
|
|
349
|
-
"episodic",
|
|
350
|
-
"semantic",
|
|
351
|
-
"procedural"
|
|
352
|
-
],
|
|
454
|
+
enum: [...MEMORY_TYPES],
|
|
353
455
|
description: "Filter by memory type."
|
|
354
456
|
},
|
|
355
457
|
segment: {
|
|
356
458
|
type: "string",
|
|
357
|
-
enum: [
|
|
459
|
+
enum: [...MEMORY_SEGMENTS],
|
|
358
460
|
description: "Filter by segment."
|
|
359
461
|
},
|
|
360
462
|
content_query: {
|
|
@@ -369,13 +471,13 @@ var init_schemas = __esm({
|
|
|
369
471
|
},
|
|
370
472
|
status: {
|
|
371
473
|
type: "string",
|
|
372
|
-
enum: [
|
|
474
|
+
enum: [...MEMORY_STATUSES],
|
|
373
475
|
description: "Filter by status."
|
|
374
476
|
}
|
|
375
477
|
},
|
|
376
478
|
required: []
|
|
377
479
|
},
|
|
378
|
-
|
|
480
|
+
band_store_memory: {
|
|
379
481
|
description: "Store a new memory entry. The memory will be associated with the authenticated agent as the source. For subject-scoped memories, provide a subject_id. For organization-scoped memories, omit subject_id.",
|
|
380
482
|
properties: {
|
|
381
483
|
content: {
|
|
@@ -384,24 +486,17 @@ var init_schemas = __esm({
|
|
|
384
486
|
},
|
|
385
487
|
system: {
|
|
386
488
|
type: "string",
|
|
387
|
-
enum: [
|
|
489
|
+
enum: [...MEMORY_SYSTEMS],
|
|
388
490
|
description: "Memory system tier."
|
|
389
491
|
},
|
|
390
492
|
type: {
|
|
391
493
|
type: "string",
|
|
392
|
-
enum: [
|
|
393
|
-
"iconic",
|
|
394
|
-
"echoic",
|
|
395
|
-
"haptic",
|
|
396
|
-
"episodic",
|
|
397
|
-
"semantic",
|
|
398
|
-
"procedural"
|
|
399
|
-
],
|
|
494
|
+
enum: [...MEMORY_TYPES],
|
|
400
495
|
description: "Memory type (must be valid for selected system)."
|
|
401
496
|
},
|
|
402
497
|
segment: {
|
|
403
498
|
type: "string",
|
|
404
|
-
enum: [
|
|
499
|
+
enum: [...MEMORY_SEGMENTS],
|
|
405
500
|
description: "Logical segment."
|
|
406
501
|
},
|
|
407
502
|
thought: {
|
|
@@ -410,7 +505,7 @@ var init_schemas = __esm({
|
|
|
410
505
|
},
|
|
411
506
|
scope: {
|
|
412
507
|
type: "string",
|
|
413
|
-
enum: [
|
|
508
|
+
enum: [...MEMORY_STORE_SCOPES],
|
|
414
509
|
description: "Visibility scope."
|
|
415
510
|
},
|
|
416
511
|
subject_id: {
|
|
@@ -424,7 +519,7 @@ var init_schemas = __esm({
|
|
|
424
519
|
},
|
|
425
520
|
required: ["content", "system", "type", "segment", "thought"]
|
|
426
521
|
},
|
|
427
|
-
|
|
522
|
+
band_get_memory: {
|
|
428
523
|
description: "Retrieve a specific memory by ID.",
|
|
429
524
|
properties: {
|
|
430
525
|
memory_id: {
|
|
@@ -434,7 +529,7 @@ var init_schemas = __esm({
|
|
|
434
529
|
},
|
|
435
530
|
required: ["memory_id"]
|
|
436
531
|
},
|
|
437
|
-
|
|
532
|
+
band_supersede_memory: {
|
|
438
533
|
description: "Mark a memory as superseded (soft delete). Use when information is outdated or incorrect. The memory remains for audit trail but won't appear in normal queries. Only the source agent can supersede.",
|
|
439
534
|
properties: {
|
|
440
535
|
memory_id: {
|
|
@@ -444,7 +539,7 @@ var init_schemas = __esm({
|
|
|
444
539
|
},
|
|
445
540
|
required: ["memory_id"]
|
|
446
541
|
},
|
|
447
|
-
|
|
542
|
+
band_archive_memory: {
|
|
448
543
|
description: "Archive a memory (hide but preserve). Use when memory is valid but not currently needed. Archived memories can be restored later by humans. Only the source agent can archive.",
|
|
449
544
|
properties: {
|
|
450
545
|
memory_id: {
|
|
@@ -457,18 +552,18 @@ var init_schemas = __esm({
|
|
|
457
552
|
};
|
|
458
553
|
ALL_TOOL_NAMES = new Set(Object.keys(TOOL_MODELS));
|
|
459
554
|
MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
460
|
-
"
|
|
461
|
-
"
|
|
462
|
-
"
|
|
463
|
-
"
|
|
464
|
-
"
|
|
555
|
+
"band_list_memories",
|
|
556
|
+
"band_store_memory",
|
|
557
|
+
"band_get_memory",
|
|
558
|
+
"band_supersede_memory",
|
|
559
|
+
"band_archive_memory"
|
|
465
560
|
]);
|
|
466
561
|
CONTACT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
467
|
-
"
|
|
468
|
-
"
|
|
469
|
-
"
|
|
470
|
-
"
|
|
471
|
-
"
|
|
562
|
+
"band_list_contacts",
|
|
563
|
+
"band_add_contact",
|
|
564
|
+
"band_remove_contact",
|
|
565
|
+
"band_list_contact_requests",
|
|
566
|
+
"band_respond_contact_request"
|
|
472
567
|
]);
|
|
473
568
|
BASE_TOOL_NAMES = new Set(
|
|
474
569
|
[...ALL_TOOL_NAMES].filter((name) => !MEMORY_TOOL_NAMES.has(name))
|
|
@@ -476,7 +571,10 @@ var init_schemas = __esm({
|
|
|
476
571
|
CHAT_TOOL_NAMES = new Set(
|
|
477
572
|
[...BASE_TOOL_NAMES].filter((name) => !CONTACT_TOOL_NAMES.has(name))
|
|
478
573
|
);
|
|
479
|
-
MCP_TOOL_PREFIX = "
|
|
574
|
+
MCP_TOOL_PREFIX = "mcp__band__";
|
|
575
|
+
MCP_SERVER_NAME = "band";
|
|
576
|
+
SEND_MESSAGE_TOOL_NAME = "band_send_message";
|
|
577
|
+
SEND_EVENT_TOOL_NAME = "band_send_event";
|
|
480
578
|
}
|
|
481
579
|
});
|
|
482
580
|
|
|
@@ -598,6 +696,13 @@ function serializeValue(value) {
|
|
|
598
696
|
return String(value);
|
|
599
697
|
}
|
|
600
698
|
}
|
|
699
|
+
function resolveSingleRoomTools(getToolsForRoom) {
|
|
700
|
+
const tools = getToolsForRoom("");
|
|
701
|
+
if (!tools) {
|
|
702
|
+
throw new Error('Single-room mode requires getToolsForRoom("") to return a tools instance');
|
|
703
|
+
}
|
|
704
|
+
return tools;
|
|
705
|
+
}
|
|
601
706
|
var init_registrations = __esm({
|
|
602
707
|
"src/mcp/registrations.ts"() {
|
|
603
708
|
"use strict";
|
|
@@ -607,42 +712,42 @@ var init_registrations = __esm({
|
|
|
607
712
|
});
|
|
608
713
|
|
|
609
714
|
// src/mcp/zod.ts
|
|
610
|
-
function buildZodShape(
|
|
715
|
+
function buildZodShape(z6, properties, required) {
|
|
611
716
|
const shape = {};
|
|
612
717
|
for (const [name, schema] of Object.entries(properties)) {
|
|
613
|
-
const validator = jsonSchemaToZod(
|
|
718
|
+
const validator = jsonSchemaToZod(z6, schema);
|
|
614
719
|
shape[name] = required.has(name) ? validator : validator.optional();
|
|
615
720
|
}
|
|
616
721
|
return shape;
|
|
617
722
|
}
|
|
618
|
-
function jsonSchemaToZod(
|
|
723
|
+
function jsonSchemaToZod(z6, schema) {
|
|
619
724
|
const type = schema.type;
|
|
620
725
|
if (type === "string") {
|
|
621
726
|
if (Array.isArray(schema.enum) && schema.enum.every((v) => typeof v === "string")) {
|
|
622
727
|
const values = schema.enum;
|
|
623
728
|
if (values.length > 0) {
|
|
624
|
-
return
|
|
729
|
+
return z6.enum(values);
|
|
625
730
|
}
|
|
626
731
|
}
|
|
627
|
-
return
|
|
732
|
+
return z6.string();
|
|
628
733
|
}
|
|
629
734
|
if (type === "integer" || type === "number") {
|
|
630
|
-
return
|
|
735
|
+
return z6.number();
|
|
631
736
|
}
|
|
632
737
|
if (type === "boolean") {
|
|
633
|
-
return
|
|
738
|
+
return z6.boolean();
|
|
634
739
|
}
|
|
635
740
|
if (type === "array") {
|
|
636
741
|
const itemSchema = schema.items;
|
|
637
742
|
if (itemSchema && typeof itemSchema === "object") {
|
|
638
|
-
return
|
|
743
|
+
return z6.array(jsonSchemaToZod(z6, itemSchema));
|
|
639
744
|
}
|
|
640
|
-
return
|
|
745
|
+
return z6.array(z6.unknown());
|
|
641
746
|
}
|
|
642
747
|
if (type === "object") {
|
|
643
|
-
return
|
|
748
|
+
return z6.record(z6.string(), z6.unknown());
|
|
644
749
|
}
|
|
645
|
-
return
|
|
750
|
+
return z6.unknown();
|
|
646
751
|
}
|
|
647
752
|
var init_zod = __esm({
|
|
648
753
|
"src/mcp/zod.ts"() {
|
|
@@ -653,32 +758,228 @@ var init_zod = __esm({
|
|
|
653
758
|
// src/mcp/sdk.ts
|
|
654
759
|
var sdk_exports = {};
|
|
655
760
|
__export(sdk_exports, {
|
|
656
|
-
|
|
761
|
+
createBandSdkMcpServer: () => createBandSdkMcpServer
|
|
657
762
|
});
|
|
658
|
-
function
|
|
659
|
-
const
|
|
660
|
-
options.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
);
|
|
763
|
+
function createBandSdkMcpServer(options) {
|
|
764
|
+
const registrationOptions = {
|
|
765
|
+
enableMemoryTools: options.enableMemoryTools,
|
|
766
|
+
enableContactTools: true,
|
|
767
|
+
additionalTools: options.additionalTools
|
|
768
|
+
};
|
|
769
|
+
const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolveSingleRoomTools(options.getToolsForRoom), registrationOptions) : buildRoomScopedRegistrations(options.getToolsForRoom, registrationOptions);
|
|
667
770
|
const toolDefinitions = registrations.map(toSdkToolDefinition);
|
|
668
771
|
const toolNames = new Set(registrations.map((r) => r.name));
|
|
772
|
+
const contextCache = /* @__PURE__ */ new Map();
|
|
773
|
+
const MAX_CONTEXT_CACHE_ENTRIES = 100;
|
|
669
774
|
const serverConfig = (0, import_claude_agent_sdk.createSdkMcpServer)({
|
|
670
|
-
name:
|
|
775
|
+
name: MCP_SERVER_NAME,
|
|
671
776
|
tools: toolDefinitions
|
|
672
777
|
});
|
|
673
778
|
return {
|
|
674
779
|
serverConfig,
|
|
675
780
|
allowedTools: mcpToolNames(toolNames),
|
|
676
|
-
toolDefinitions
|
|
781
|
+
toolDefinitions,
|
|
782
|
+
getSystemPromptContext: async (roomId, contextOptions) => {
|
|
783
|
+
const context = await getOrBuildSystemPromptContext(
|
|
784
|
+
roomId,
|
|
785
|
+
contextOptions,
|
|
786
|
+
options.getToolsForRoom,
|
|
787
|
+
contextCache,
|
|
788
|
+
MAX_CONTEXT_CACHE_ENTRIES
|
|
789
|
+
);
|
|
790
|
+
return context.markdown;
|
|
791
|
+
},
|
|
792
|
+
getSystemPromptContextData: (roomId, contextOptions) => {
|
|
793
|
+
return getOrBuildSystemPromptContext(
|
|
794
|
+
roomId,
|
|
795
|
+
contextOptions,
|
|
796
|
+
options.getToolsForRoom,
|
|
797
|
+
contextCache,
|
|
798
|
+
MAX_CONTEXT_CACHE_ENTRIES
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
async function getOrBuildSystemPromptContext(roomId, contextOptions, getToolsForRoom, contextCache, maxEntries) {
|
|
804
|
+
const ttlMs = contextOptions?.ttlMs ?? 3e4;
|
|
805
|
+
const now = Date.now();
|
|
806
|
+
const cached = contextCache.get(roomId);
|
|
807
|
+
if (cached && cached.expiresAt > now) {
|
|
808
|
+
cached.lastAccessedAt = now;
|
|
809
|
+
return cached.value;
|
|
810
|
+
}
|
|
811
|
+
if (cached) {
|
|
812
|
+
contextCache.delete(roomId);
|
|
813
|
+
}
|
|
814
|
+
const tools = getToolsForRoom(roomId);
|
|
815
|
+
if (!tools) {
|
|
816
|
+
return buildUnavailableSystemPromptContext(roomId);
|
|
817
|
+
}
|
|
818
|
+
const context = await buildSystemPromptContext(roomId, tools);
|
|
819
|
+
contextCache.set(roomId, {
|
|
820
|
+
value: context,
|
|
821
|
+
expiresAt: now + ttlMs,
|
|
822
|
+
lastAccessedAt: now
|
|
823
|
+
});
|
|
824
|
+
evictLeastRecentlyUsedContext(contextCache, maxEntries);
|
|
825
|
+
return context;
|
|
826
|
+
}
|
|
827
|
+
async function buildSystemPromptContext(roomId, tools) {
|
|
828
|
+
const participants = await tools.getParticipants();
|
|
829
|
+
const warnings = [];
|
|
830
|
+
const agentResolution = await resolveAgentIdentity(tools);
|
|
831
|
+
if (agentResolution.warning) {
|
|
832
|
+
warnings.push(agentResolution.warning);
|
|
833
|
+
}
|
|
834
|
+
const roomResolution = await resolveRoomTitle(tools, roomId);
|
|
835
|
+
if (roomResolution.warning) {
|
|
836
|
+
warnings.push(roomResolution.warning);
|
|
837
|
+
}
|
|
838
|
+
const agentIdentity = agentResolution.value;
|
|
839
|
+
const roomTitle = roomResolution.value;
|
|
840
|
+
const normalizedParticipants = participants.map((participant) => ({
|
|
841
|
+
id: String(participant.id),
|
|
842
|
+
name: String(participant.name ?? "Unknown"),
|
|
843
|
+
type: String(participant.type ?? "Unknown"),
|
|
844
|
+
handle: normalizeHandle2(participant.handle),
|
|
845
|
+
isSelf: participant.id === agentIdentity?.id
|
|
846
|
+
}));
|
|
847
|
+
const selfHandle = normalizeHandle2(agentIdentity?.handle);
|
|
848
|
+
const selfName = agentIdentity?.name ?? "Agent";
|
|
849
|
+
const mentionHandles = normalizedParticipants.filter((participant) => !participant.isSelf).map((participant) => participant.handle).filter((handle) => Boolean(handle));
|
|
850
|
+
const mentionFormat = mentionHandles.length > 0 ? mentionHandles.join(", ") : "No participant handles available";
|
|
851
|
+
const roomLabel = roomTitle ? `"${roomTitle}"` : "this room";
|
|
852
|
+
const agentLabel = selfHandle ? `${selfName} (${selfHandle})` : selfName;
|
|
853
|
+
const participantLines = normalizedParticipants.length > 0 ? normalizedParticipants.map((participant) => {
|
|
854
|
+
const suffix = participant.isSelf ? " (you)" : "";
|
|
855
|
+
const handle = participant.handle ? ` (${participant.handle})` : "";
|
|
856
|
+
return `- **${participant.name}**${handle} -- ${participant.type}${suffix}`;
|
|
857
|
+
}).join("\n") : "- No participants found";
|
|
858
|
+
const markdown = [
|
|
859
|
+
"## Room Context",
|
|
860
|
+
"",
|
|
861
|
+
`You are **${agentLabel}** in room ${roomLabel} (id: ${roomId}).`,
|
|
862
|
+
"",
|
|
863
|
+
"### Participants",
|
|
864
|
+
participantLines,
|
|
865
|
+
"",
|
|
866
|
+
"### Mention Format",
|
|
867
|
+
`To address someone, use their exact handle: ${mentionFormat}`,
|
|
868
|
+
...warnings.length > 0 ? ["", "### Warnings", ...warnings.map((warning) => `- ${warning}`)] : []
|
|
869
|
+
].join("\n");
|
|
870
|
+
return {
|
|
871
|
+
roomId,
|
|
872
|
+
roomTitle,
|
|
873
|
+
agent: {
|
|
874
|
+
id: agentIdentity?.id ?? "unknown-agent",
|
|
875
|
+
name: selfName,
|
|
876
|
+
handle: selfHandle,
|
|
877
|
+
description: agentIdentity?.description ?? null
|
|
878
|
+
},
|
|
879
|
+
participants: normalizedParticipants,
|
|
880
|
+
mentionFormat,
|
|
881
|
+
warnings,
|
|
882
|
+
markdown
|
|
677
883
|
};
|
|
678
884
|
}
|
|
885
|
+
async function resolveAgentIdentity(tools) {
|
|
886
|
+
const maybeTools = tools;
|
|
887
|
+
try {
|
|
888
|
+
if (maybeTools.getAgentIdentity) {
|
|
889
|
+
return { value: await maybeTools.getAgentIdentity(), warning: null };
|
|
890
|
+
}
|
|
891
|
+
if (maybeTools.rest?.getAgentMe) {
|
|
892
|
+
return { value: await maybeTools.rest.getAgentMe(), warning: null };
|
|
893
|
+
}
|
|
894
|
+
} catch (error) {
|
|
895
|
+
return {
|
|
896
|
+
value: null,
|
|
897
|
+
warning: `Unable to resolve agent identity: ${error instanceof Error ? error.message : String(error)}`
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
return { value: null, warning: null };
|
|
901
|
+
}
|
|
902
|
+
async function resolveRoomTitle(tools, roomId) {
|
|
903
|
+
const maybeTools = tools;
|
|
904
|
+
const rest = maybeTools.rest;
|
|
905
|
+
if (!rest?.listChats) {
|
|
906
|
+
return { value: null, warning: null };
|
|
907
|
+
}
|
|
908
|
+
try {
|
|
909
|
+
let page = 1;
|
|
910
|
+
const pageSize = 100;
|
|
911
|
+
while (true) {
|
|
912
|
+
const response = await rest.listChats({ page, pageSize });
|
|
913
|
+
const room = response?.data?.find((entry) => entry.id === roomId);
|
|
914
|
+
if (typeof room?.title === "string" && room.title.length > 0) {
|
|
915
|
+
return { value: room.title, warning: null };
|
|
916
|
+
}
|
|
917
|
+
const totalPages = response?.metadata?.totalPages ?? page;
|
|
918
|
+
if (page >= totalPages) {
|
|
919
|
+
return { value: null, warning: null };
|
|
920
|
+
}
|
|
921
|
+
page += 1;
|
|
922
|
+
}
|
|
923
|
+
} catch (error) {
|
|
924
|
+
return {
|
|
925
|
+
value: null,
|
|
926
|
+
warning: `Unable to resolve room title: ${error instanceof Error ? error.message : String(error)}`
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
function buildUnavailableSystemPromptContext(roomId) {
|
|
931
|
+
const warnings = [`No tool context found for room_id ${roomId}`];
|
|
932
|
+
const markdown = [
|
|
933
|
+
"## Room Context",
|
|
934
|
+
"",
|
|
935
|
+
`You are **Agent** in this room (id: ${roomId}).`,
|
|
936
|
+
"",
|
|
937
|
+
"### Participants",
|
|
938
|
+
"- No participants found",
|
|
939
|
+
"",
|
|
940
|
+
"### Mention Format",
|
|
941
|
+
"No participant handles available",
|
|
942
|
+
"",
|
|
943
|
+
"### Warnings",
|
|
944
|
+
...warnings.map((warning) => `- ${warning}`)
|
|
945
|
+
].join("\n");
|
|
946
|
+
return {
|
|
947
|
+
roomId,
|
|
948
|
+
roomTitle: null,
|
|
949
|
+
agent: {
|
|
950
|
+
id: "unknown-agent",
|
|
951
|
+
name: "Agent",
|
|
952
|
+
handle: null,
|
|
953
|
+
description: null
|
|
954
|
+
},
|
|
955
|
+
participants: [],
|
|
956
|
+
mentionFormat: "No participant handles available",
|
|
957
|
+
warnings,
|
|
958
|
+
markdown
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function evictLeastRecentlyUsedContext(contextCache, maxEntries) {
|
|
962
|
+
if (contextCache.size <= maxEntries) {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
let oldestKey = null;
|
|
966
|
+
let oldestAccessedAt = Number.POSITIVE_INFINITY;
|
|
967
|
+
for (const [key, entry] of contextCache.entries()) {
|
|
968
|
+
if (entry.lastAccessedAt < oldestAccessedAt) {
|
|
969
|
+
oldestAccessedAt = entry.lastAccessedAt;
|
|
970
|
+
oldestKey = key;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
if (oldestKey) {
|
|
974
|
+
contextCache.delete(oldestKey);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function normalizeHandle2(handle) {
|
|
978
|
+
return typeof handle === "string" && handle.trim().length > 0 ? handle.trim() : null;
|
|
979
|
+
}
|
|
679
980
|
function toSdkToolDefinition(registration) {
|
|
680
981
|
const shape = buildZodShape(
|
|
681
|
-
|
|
982
|
+
import_zod7.z,
|
|
682
983
|
registration.inputSchema.properties,
|
|
683
984
|
new Set(registration.inputSchema.required)
|
|
684
985
|
);
|
|
@@ -689,12 +990,12 @@ function toSdkToolDefinition(registration) {
|
|
|
689
990
|
async (args) => registration.execute(args)
|
|
690
991
|
);
|
|
691
992
|
}
|
|
692
|
-
var import_claude_agent_sdk,
|
|
993
|
+
var import_claude_agent_sdk, import_zod7;
|
|
693
994
|
var init_sdk = __esm({
|
|
694
995
|
"src/mcp/sdk.ts"() {
|
|
695
996
|
"use strict";
|
|
696
997
|
import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
|
|
697
|
-
|
|
998
|
+
import_zod7 = require("zod");
|
|
698
999
|
init_schemas();
|
|
699
1000
|
init_registrations();
|
|
700
1001
|
init_zod();
|
|
@@ -709,6 +1010,7 @@ __export(src_exports, {
|
|
|
709
1010
|
Agent: () => Agent,
|
|
710
1011
|
AgentRuntime: () => AgentRuntime,
|
|
711
1012
|
AnthropicAdapter: () => AnthropicAdapter,
|
|
1013
|
+
BandLink: () => BandLink,
|
|
712
1014
|
CODEX_REASONING_EFFORTS: () => CODEX_REASONING_EFFORTS,
|
|
713
1015
|
CODEX_REASONING_SUMMARIES: () => CODEX_REASONING_SUMMARIES,
|
|
714
1016
|
CODEX_WEB_SEARCH_MODES: () => CODEX_WEB_SEARCH_MODES,
|
|
@@ -720,6 +1022,7 @@ __export(src_exports, {
|
|
|
720
1022
|
GoogleADKAdapter: () => GoogleADKAdapter,
|
|
721
1023
|
LangGraphAdapter: () => LangGraphAdapter,
|
|
722
1024
|
LettaAdapter: () => LettaAdapter,
|
|
1025
|
+
MCP_SERVER_NAME: () => MCP_SERVER_NAME,
|
|
723
1026
|
MCP_TOOL_PREFIX: () => MCP_TOOL_PREFIX,
|
|
724
1027
|
OpenAIAdapter: () => OpenAIAdapter,
|
|
725
1028
|
OpencodeAdapter: () => OpencodeAdapter,
|
|
@@ -727,8 +1030,9 @@ __export(src_exports, {
|
|
|
727
1030
|
PlatformRuntime: () => PlatformRuntime,
|
|
728
1031
|
SimpleAdapter: () => SimpleAdapter,
|
|
729
1032
|
TOOL_MODELS: () => TOOL_MODELS,
|
|
730
|
-
ThenvoiLink: () => ThenvoiLink,
|
|
731
1033
|
VercelAISDKAdapter: () => VercelAISDKAdapter,
|
|
1034
|
+
WebSocketDisconnectError: () => WebSocketDisconnectError,
|
|
1035
|
+
deriveDefaultRestUrl: () => deriveDefaultRestUrl,
|
|
732
1036
|
isDirectExecution: () => isDirectExecution,
|
|
733
1037
|
loadAgentConfig: () => loadAgentConfig,
|
|
734
1038
|
loadAgentConfigFromEnv: () => loadAgentConfigFromEnv
|
|
@@ -1024,56 +1328,19 @@ init_errors();
|
|
|
1024
1328
|
var DEFAULT_REQUEST_OPTIONS = {
|
|
1025
1329
|
maxRetries: 3
|
|
1026
1330
|
};
|
|
1331
|
+
var MESSAGE_SEND_MAX_RETRIES = 2;
|
|
1027
1332
|
|
|
1028
1333
|
// src/client/rest/FernRestAdapter.ts
|
|
1029
|
-
function mergeOptions(options) {
|
|
1334
|
+
function mergeOptions(options, maxRetries) {
|
|
1030
1335
|
return {
|
|
1031
1336
|
...DEFAULT_REQUEST_OPTIONS,
|
|
1337
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
1032
1338
|
...options
|
|
1033
1339
|
};
|
|
1034
1340
|
}
|
|
1035
|
-
var AGENT_ME_RETRY_LIMIT = 4;
|
|
1036
|
-
var AGENT_ME_RETRY_BASE_DELAY_MS = 2e3;
|
|
1037
|
-
var MESSAGE_SEND_RETRY_LIMIT = 3;
|
|
1038
|
-
var MESSAGE_SEND_RETRY_BASE_DELAY_MS = 500;
|
|
1039
1341
|
function asMetadataMap2(value) {
|
|
1040
1342
|
return asOptionalRecord(value);
|
|
1041
1343
|
}
|
|
1042
|
-
function extractHttpStatus(error) {
|
|
1043
|
-
const record = asOptionalRecord(error);
|
|
1044
|
-
if (!record) {
|
|
1045
|
-
return void 0;
|
|
1046
|
-
}
|
|
1047
|
-
const response = asOptionalRecord(record.response);
|
|
1048
|
-
const status = record.statusCode ?? record.status ?? response?.statusCode ?? response?.status;
|
|
1049
|
-
return typeof status === "number" ? status : void 0;
|
|
1050
|
-
}
|
|
1051
|
-
function isFernRateLimitError(error) {
|
|
1052
|
-
return extractHttpStatus(error) === 429;
|
|
1053
|
-
}
|
|
1054
|
-
async function sleep(ms) {
|
|
1055
|
-
await new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
1056
|
-
}
|
|
1057
|
-
function computeRetryDelayMs(baseDelayMs, attempt) {
|
|
1058
|
-
const backoff = baseDelayMs * 2 ** (attempt - 1);
|
|
1059
|
-
const jitter = Math.floor(Math.random() * Math.max(1, Math.floor(backoff / 4)));
|
|
1060
|
-
return backoff + jitter;
|
|
1061
|
-
}
|
|
1062
|
-
async function withRateLimitRetry(operation, options) {
|
|
1063
|
-
let lastError;
|
|
1064
|
-
for (let attempt = 1; attempt <= options.retryLimit; attempt += 1) {
|
|
1065
|
-
try {
|
|
1066
|
-
return await operation();
|
|
1067
|
-
} catch (error) {
|
|
1068
|
-
lastError = error;
|
|
1069
|
-
if (!isFernRateLimitError(error) || attempt === options.retryLimit) {
|
|
1070
|
-
throw error;
|
|
1071
|
-
}
|
|
1072
|
-
await sleep(computeRetryDelayMs(options.baseDelayMs, attempt));
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
throw lastError instanceof Error ? lastError : new Error("Rate-limit retry exhausted without a terminal error.");
|
|
1076
|
-
}
|
|
1077
1344
|
function requireNonEmptyStringField(value, field, source) {
|
|
1078
1345
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1079
1346
|
throw new Error(`Invalid ${source} response: expected non-empty string AgentIdentity.${field}`);
|
|
@@ -1281,28 +1548,21 @@ var FernRestAdapter = class {
|
|
|
1281
1548
|
this.client = client;
|
|
1282
1549
|
}
|
|
1283
1550
|
async getAgentMe(options) {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
"profile.getMyProfile"
|
|
1300
|
-
);
|
|
1301
|
-
},
|
|
1302
|
-
{
|
|
1303
|
-
retryLimit: AGENT_ME_RETRY_LIMIT,
|
|
1304
|
-
baseDelayMs: AGENT_ME_RETRY_BASE_DELAY_MS
|
|
1305
|
-
}
|
|
1551
|
+
const requestOptions = mergeOptions(options);
|
|
1552
|
+
if (this.client.agentApiIdentity?.getAgentMe) {
|
|
1553
|
+
const response = await this.client.agentApiIdentity.getAgentMe(requestOptions);
|
|
1554
|
+
return normalizeAgentIdentityEnvelope(response, "agentApiIdentity.getAgentMe");
|
|
1555
|
+
}
|
|
1556
|
+
const profileClient = this.client.myProfile ?? this.client.humanApiProfile;
|
|
1557
|
+
if (!profileClient?.getMyProfile) {
|
|
1558
|
+
throw new UnsupportedFeatureError(
|
|
1559
|
+
"Fern client missing agentApiIdentity.getAgentMe or humanApiProfile.getMyProfile"
|
|
1560
|
+
);
|
|
1561
|
+
}
|
|
1562
|
+
const profile = await profileClient.getMyProfile(requestOptions);
|
|
1563
|
+
return normalizeLegacyProfileIdentity(
|
|
1564
|
+
normalizeLegacyProfileEnvelope(profile),
|
|
1565
|
+
"profile.getMyProfile"
|
|
1306
1566
|
);
|
|
1307
1567
|
}
|
|
1308
1568
|
async createChatMessage(chatId, message, options) {
|
|
@@ -1310,45 +1570,33 @@ var FernRestAdapter = class {
|
|
|
1310
1570
|
if (!api) {
|
|
1311
1571
|
throw new UnsupportedFeatureError("Fern client missing chat message creation endpoint");
|
|
1312
1572
|
}
|
|
1313
|
-
const response = await
|
|
1314
|
-
|
|
1315
|
-
chatId,
|
|
1316
|
-
{
|
|
1317
|
-
message: {
|
|
1318
|
-
content: message.content,
|
|
1319
|
-
message_type: message.messageType,
|
|
1320
|
-
metadata: message.metadata,
|
|
1321
|
-
mentions: message.mentions
|
|
1322
|
-
}
|
|
1323
|
-
},
|
|
1324
|
-
mergeOptions(options)
|
|
1325
|
-
),
|
|
1573
|
+
const response = await api(
|
|
1574
|
+
chatId,
|
|
1326
1575
|
{
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1576
|
+
message: {
|
|
1577
|
+
content: message.content,
|
|
1578
|
+
message_type: message.messageType,
|
|
1579
|
+
metadata: message.metadata,
|
|
1580
|
+
mentions: message.mentions
|
|
1581
|
+
}
|
|
1582
|
+
},
|
|
1583
|
+
mergeOptions(options, MESSAGE_SEND_MAX_RETRIES)
|
|
1330
1584
|
);
|
|
1331
1585
|
return normalizeToolOperationResult(response);
|
|
1332
1586
|
}
|
|
1333
1587
|
async createChatEvent(chatId, event, options) {
|
|
1334
1588
|
const createAgentChatEvent = this.client.agentApiEvents?.createAgentChatEvent?.bind(this.client.agentApiEvents);
|
|
1335
1589
|
if (createAgentChatEvent) {
|
|
1336
|
-
const response = await
|
|
1337
|
-
|
|
1338
|
-
chatId,
|
|
1339
|
-
{
|
|
1340
|
-
event: {
|
|
1341
|
-
content: event.content,
|
|
1342
|
-
message_type: event.messageType,
|
|
1343
|
-
metadata: event.metadata
|
|
1344
|
-
}
|
|
1345
|
-
},
|
|
1346
|
-
mergeOptions(options)
|
|
1347
|
-
),
|
|
1590
|
+
const response = await createAgentChatEvent(
|
|
1591
|
+
chatId,
|
|
1348
1592
|
{
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1593
|
+
event: {
|
|
1594
|
+
content: event.content,
|
|
1595
|
+
message_type: event.messageType,
|
|
1596
|
+
metadata: event.metadata
|
|
1597
|
+
}
|
|
1598
|
+
},
|
|
1599
|
+
mergeOptions(options, MESSAGE_SEND_MAX_RETRIES)
|
|
1352
1600
|
);
|
|
1353
1601
|
return normalizeToolOperationResult(response);
|
|
1354
1602
|
}
|
|
@@ -1644,7 +1892,7 @@ var FernRestAdapter = class {
|
|
|
1644
1892
|
}
|
|
1645
1893
|
};
|
|
1646
1894
|
|
|
1647
|
-
// src/platform/
|
|
1895
|
+
// src/platform/BandLink.ts
|
|
1648
1896
|
init_errors();
|
|
1649
1897
|
|
|
1650
1898
|
// src/contracts/capabilities.ts
|
|
@@ -1758,56 +2006,242 @@ var payloadSchemas = {
|
|
|
1758
2006
|
|
|
1759
2007
|
// src/platform/streaming/PhoenixChannelsTransport.ts
|
|
1760
2008
|
var import_phoenix = require("phoenix");
|
|
1761
|
-
var import_ws = require("ws");
|
|
1762
2009
|
init_errors();
|
|
2010
|
+
|
|
2011
|
+
// src/platform/streaming/disconnectReason.ts
|
|
2012
|
+
var import_zod2 = require("zod");
|
|
2013
|
+
var UPGRADE_CODES = [
|
|
2014
|
+
"invalid_on_conflict",
|
|
2015
|
+
"connection_conflict",
|
|
2016
|
+
"too_many_requests",
|
|
2017
|
+
"tracking_failed"
|
|
2018
|
+
];
|
|
2019
|
+
var UPGRADE_REASONS = {
|
|
2020
|
+
invalid_on_conflict: {
|
|
2021
|
+
status: 400,
|
|
2022
|
+
message: "Invalid websocket conflict policy.",
|
|
2023
|
+
retryable: false
|
|
2024
|
+
},
|
|
2025
|
+
connection_conflict: {
|
|
2026
|
+
status: 409,
|
|
2027
|
+
message: "Websocket connection conflict.",
|
|
2028
|
+
retryable: false
|
|
2029
|
+
},
|
|
2030
|
+
too_many_requests: {
|
|
2031
|
+
status: 429,
|
|
2032
|
+
message: "Too many websocket connection attempts.",
|
|
2033
|
+
retryable: true
|
|
2034
|
+
},
|
|
2035
|
+
tracking_failed: {
|
|
2036
|
+
status: 503,
|
|
2037
|
+
message: "Websocket connection tracking failed.",
|
|
2038
|
+
retryable: true
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
var upgradeErrorSchema = import_zod2.z.object({
|
|
2042
|
+
status: import_zod2.z.number(),
|
|
2043
|
+
body: import_zod2.z.preprocess(
|
|
2044
|
+
(body) => {
|
|
2045
|
+
if (typeof body !== "string") {
|
|
2046
|
+
return body;
|
|
2047
|
+
}
|
|
2048
|
+
try {
|
|
2049
|
+
return JSON.parse(body);
|
|
2050
|
+
} catch {
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2053
|
+
},
|
|
2054
|
+
import_zod2.z.object({
|
|
2055
|
+
error: import_zod2.z.object({
|
|
2056
|
+
code: import_zod2.z.enum(UPGRADE_CODES),
|
|
2057
|
+
message: import_zod2.z.string().optional(),
|
|
2058
|
+
retry_after: import_zod2.z.number().nullable().optional(),
|
|
2059
|
+
request_id: import_zod2.z.string().nullable().optional()
|
|
2060
|
+
})
|
|
2061
|
+
})
|
|
2062
|
+
),
|
|
2063
|
+
headers: import_zod2.z.record(import_zod2.z.unknown()).optional()
|
|
2064
|
+
});
|
|
2065
|
+
var WebSocketDisconnectError = class extends Error {
|
|
2066
|
+
reason;
|
|
2067
|
+
constructor(reason) {
|
|
2068
|
+
super(reason.message);
|
|
2069
|
+
this.name = "WebSocketDisconnectError";
|
|
2070
|
+
this.reason = reason;
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
function parseSupersedeDisconnectReason(payload) {
|
|
2074
|
+
if (typeof payload.reason !== "string" || typeof payload.message !== "string") {
|
|
2075
|
+
return null;
|
|
2076
|
+
}
|
|
2077
|
+
return {
|
|
2078
|
+
source: "agent_control",
|
|
2079
|
+
code: payload.reason,
|
|
2080
|
+
message: payload.message,
|
|
2081
|
+
retryable: false,
|
|
2082
|
+
retryAfter: typeof payload.retry_after === "number" ? payload.retry_after : null,
|
|
2083
|
+
targetSocketId: typeof payload.target_socket_id === "string" ? payload.target_socket_id : null,
|
|
2084
|
+
correlationId: typeof payload.correlation_id === "string" ? payload.correlation_id : null
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
function parseUpgradeDisconnectReason(event) {
|
|
2088
|
+
const parsed = upgradeErrorSchema.safeParse(event);
|
|
2089
|
+
if (!parsed.success) {
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
const { status, body, headers } = parsed.data;
|
|
2093
|
+
const {
|
|
2094
|
+
code,
|
|
2095
|
+
message,
|
|
2096
|
+
retry_after: retryAfter,
|
|
2097
|
+
request_id: requestId
|
|
2098
|
+
} = body.error;
|
|
2099
|
+
const reason = UPGRADE_REASONS[code];
|
|
2100
|
+
if (status !== reason.status) {
|
|
2101
|
+
return null;
|
|
2102
|
+
}
|
|
2103
|
+
return {
|
|
2104
|
+
source: "upgrade",
|
|
2105
|
+
status: reason.status,
|
|
2106
|
+
code,
|
|
2107
|
+
message: message ?? reason.message,
|
|
2108
|
+
retryable: reason.retryable,
|
|
2109
|
+
retryAfter: retryAfter ?? retryAfterFromHeaders(headers),
|
|
2110
|
+
requestId: requestId ?? null
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
function genericCloseReason(event) {
|
|
2114
|
+
return {
|
|
2115
|
+
source: "websocket_close",
|
|
2116
|
+
code: "websocket.closed",
|
|
2117
|
+
message: "Phoenix socket closed without a platform disconnect reason.",
|
|
2118
|
+
retryable: true,
|
|
2119
|
+
closeCode: typeof event?.code === "number" ? event.code : null,
|
|
2120
|
+
closeReason: typeof event?.reason === "string" && event.reason.length > 0 ? event.reason : null
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
function retryAfterFromHeaders(headers) {
|
|
2124
|
+
const value = headers?.["retry-after"] ?? headers?.["Retry-After"];
|
|
2125
|
+
if (typeof value === "number") {
|
|
2126
|
+
return value;
|
|
2127
|
+
}
|
|
2128
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
2129
|
+
const seconds = Number(value);
|
|
2130
|
+
return Number.isFinite(seconds) ? seconds : null;
|
|
2131
|
+
}
|
|
2132
|
+
return null;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
// src/platform/streaming/nodeWebSocketFactory.ts
|
|
2136
|
+
var import_ws = require("ws");
|
|
2137
|
+
function createNodeWebSocketFactory(headers) {
|
|
2138
|
+
const Constructor = import_ws.WebSocket;
|
|
2139
|
+
class BandNodeWebSocket {
|
|
2140
|
+
constructor(address, protocols) {
|
|
2141
|
+
const socket = new Constructor(address, protocols, headers ? { headers } : void 0);
|
|
2142
|
+
socket.once("unexpected-response", (request, response) => {
|
|
2143
|
+
void emitUpgradeError(socket, request, response);
|
|
2144
|
+
});
|
|
2145
|
+
return socket;
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return BandNodeWebSocket;
|
|
2149
|
+
}
|
|
2150
|
+
async function emitUpgradeError(websocket, request, response) {
|
|
2151
|
+
const body = await readResponseBody(response);
|
|
2152
|
+
const error = new Error(
|
|
2153
|
+
`Unexpected server response: ${response.statusCode ?? "unknown"}`
|
|
2154
|
+
);
|
|
2155
|
+
error.status = response.statusCode;
|
|
2156
|
+
error.body = body;
|
|
2157
|
+
error.headers = response.headers;
|
|
2158
|
+
request.destroy();
|
|
2159
|
+
websocket.emit("error", error);
|
|
2160
|
+
websocket.emit("close", 1006, Buffer.alloc(0));
|
|
2161
|
+
}
|
|
2162
|
+
async function readResponseBody(response) {
|
|
2163
|
+
const chunks = [];
|
|
2164
|
+
for await (const chunk of response) {
|
|
2165
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
2166
|
+
}
|
|
2167
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
// src/platform/streaming/PhoenixChannelsTransport.ts
|
|
1763
2171
|
var PhoenixChannelsTransport = class {
|
|
1764
2172
|
socket;
|
|
2173
|
+
agentId;
|
|
1765
2174
|
channels = /* @__PURE__ */ new Map();
|
|
1766
2175
|
channelRefs = /* @__PURE__ */ new Map();
|
|
1767
2176
|
pendingJoins = /* @__PURE__ */ new Map();
|
|
1768
2177
|
logger;
|
|
2178
|
+
onTerminalDisconnect;
|
|
1769
2179
|
onHandlerError;
|
|
1770
2180
|
connected = false;
|
|
1771
2181
|
connectPromise = null;
|
|
1772
2182
|
connectResolve = null;
|
|
2183
|
+
connectReject = null;
|
|
2184
|
+
lastDisconnectReason = null;
|
|
2185
|
+
terminalDisconnectError = null;
|
|
2186
|
+
runForeverWaiters = /* @__PURE__ */ new Set();
|
|
2187
|
+
stoppingReconnect = false;
|
|
2188
|
+
suppressNextCloseReason = false;
|
|
1773
2189
|
constructor(options) {
|
|
1774
2190
|
this.logger = options.logger ?? new NoopLogger();
|
|
2191
|
+
this.agentId = options.agentId;
|
|
2192
|
+
this.onTerminalDisconnect = options.onTerminalDisconnect;
|
|
1775
2193
|
let wsUrl = options.wsUrl;
|
|
1776
2194
|
if (wsUrl.endsWith("/websocket")) {
|
|
1777
2195
|
wsUrl = wsUrl.slice(0, -"/websocket".length);
|
|
1778
2196
|
}
|
|
2197
|
+
const reconnectAfterMs = options.reconnectAfterMs ?? ((tries) => [1e3, 2e3, 5e3, 1e4, 3e4][tries - 1] ?? 3e4);
|
|
1779
2198
|
this.socket = new import_phoenix.Socket(wsUrl, {
|
|
1780
2199
|
params: {
|
|
1781
|
-
|
|
1782
|
-
|
|
2200
|
+
agent_id: options.agentId,
|
|
2201
|
+
...options.conflictPolicy ? { on_conflict: options.conflictPolicy } : {}
|
|
1783
2202
|
},
|
|
1784
2203
|
heartbeatIntervalMs: options.heartbeatIntervalMs,
|
|
1785
|
-
reconnectAfterMs:
|
|
1786
|
-
|
|
2204
|
+
reconnectAfterMs: (tries) => {
|
|
2205
|
+
if (this.terminalDisconnectError) {
|
|
2206
|
+
return Number.POSITIVE_INFINITY;
|
|
2207
|
+
}
|
|
2208
|
+
return reconnectAfterMs(tries);
|
|
2209
|
+
},
|
|
2210
|
+
transport: options.websocketFactory ?? resolveWebSocketFactory(options.apiKey)
|
|
1787
2211
|
});
|
|
1788
2212
|
this.socket.onOpen(() => {
|
|
1789
|
-
this.
|
|
1790
|
-
this.connectResolve?.();
|
|
1791
|
-
this.connectResolve = null;
|
|
1792
|
-
this.logger.info("Phoenix socket opened", {
|
|
1793
|
-
channels: getSocketChannelCount(this.socket)
|
|
1794
|
-
});
|
|
2213
|
+
void this.handleOpen();
|
|
1795
2214
|
});
|
|
1796
2215
|
this.socket.onClose((event) => {
|
|
1797
|
-
this.
|
|
1798
|
-
if (getSocketChannelCount(this.socket) === 0) {
|
|
1799
|
-
this.socket.disconnect();
|
|
1800
|
-
}
|
|
1801
|
-
this.logger.info("Phoenix socket closed", {
|
|
1802
|
-
code: event?.code ?? null,
|
|
1803
|
-
reason: event?.reason ?? null
|
|
1804
|
-
});
|
|
2216
|
+
this.recordSocketClose(event);
|
|
1805
2217
|
});
|
|
1806
2218
|
this.socket.onError((event) => {
|
|
2219
|
+
const errorEvent = unwrapErrorEvent(event);
|
|
2220
|
+
const upgradeReason = parseUpgradeDisconnectReason(errorEvent);
|
|
2221
|
+
if (upgradeReason) {
|
|
2222
|
+
if (upgradeReason.retryable) {
|
|
2223
|
+
this.lastDisconnectReason = upgradeReason;
|
|
2224
|
+
this.connectReject?.(new WebSocketDisconnectError(upgradeReason));
|
|
2225
|
+
this.stopReconnectIfNoChannels({ suppressCloseReason: true });
|
|
2226
|
+
} else {
|
|
2227
|
+
this.recordTerminalDisconnect(upgradeReason);
|
|
2228
|
+
}
|
|
2229
|
+
this.logger.warn("Phoenix socket upgrade failed", {
|
|
2230
|
+
reason: upgradeReason
|
|
2231
|
+
});
|
|
2232
|
+
return;
|
|
2233
|
+
}
|
|
2234
|
+
this.connectReject?.(
|
|
2235
|
+
new TransportError("Phoenix socket connection failed", errorEvent)
|
|
2236
|
+
);
|
|
2237
|
+
this.stopReconnectIfNoChannels({ suppressCloseReason: true });
|
|
1807
2238
|
this.logger.warn("Phoenix socket error", { event });
|
|
1808
2239
|
});
|
|
1809
2240
|
}
|
|
1810
2241
|
async connect() {
|
|
2242
|
+
if (this.terminalDisconnectError) {
|
|
2243
|
+
throw this.terminalDisconnectError;
|
|
2244
|
+
}
|
|
1811
2245
|
if (this.connected) {
|
|
1812
2246
|
return;
|
|
1813
2247
|
}
|
|
@@ -1831,15 +2265,30 @@ var PhoenixChannelsTransport = class {
|
|
|
1831
2265
|
await this.connectPromise;
|
|
1832
2266
|
}
|
|
1833
2267
|
async disconnect() {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2268
|
+
const results = await Promise.allSettled(
|
|
2269
|
+
[...this.channels.keys()].map((topic) => this.leave(topic))
|
|
2270
|
+
);
|
|
1837
2271
|
this.socket.disconnect();
|
|
1838
2272
|
this.connected = false;
|
|
2273
|
+
const failures = [];
|
|
2274
|
+
for (const result of results) {
|
|
2275
|
+
if (result.status === "rejected") {
|
|
2276
|
+
failures.push(result.reason);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
if (failures.length > 0) {
|
|
2280
|
+
throw new AggregateError(
|
|
2281
|
+
failures,
|
|
2282
|
+
"Failed to leave one or more Phoenix topics during disconnect"
|
|
2283
|
+
);
|
|
2284
|
+
}
|
|
1839
2285
|
}
|
|
1840
2286
|
isConnected() {
|
|
1841
2287
|
return this.connected;
|
|
1842
2288
|
}
|
|
2289
|
+
getDisconnectReason() {
|
|
2290
|
+
return this.lastDisconnectReason;
|
|
2291
|
+
}
|
|
1843
2292
|
async join(topic, handlers) {
|
|
1844
2293
|
if (this.channels.has(topic)) {
|
|
1845
2294
|
return;
|
|
@@ -1875,7 +2324,10 @@ var PhoenixChannelsTransport = class {
|
|
|
1875
2324
|
channel.join().receive("ok", () => resolve()).receive(
|
|
1876
2325
|
"error",
|
|
1877
2326
|
(error) => reject(new TransportError(`Failed to join topic ${topic}`, error))
|
|
1878
|
-
).receive(
|
|
2327
|
+
).receive(
|
|
2328
|
+
"timeout",
|
|
2329
|
+
() => reject(new TransportError(`Timeout joining topic ${topic}`))
|
|
2330
|
+
);
|
|
1879
2331
|
});
|
|
1880
2332
|
} catch (error) {
|
|
1881
2333
|
for (const [event, ref] of refs) {
|
|
@@ -1903,19 +2355,127 @@ var PhoenixChannelsTransport = class {
|
|
|
1903
2355
|
channel.leave().receive("ok", () => resolve()).receive(
|
|
1904
2356
|
"error",
|
|
1905
2357
|
(error) => reject(new TransportError(`Failed to leave topic ${topic}`, error))
|
|
1906
|
-
).receive(
|
|
2358
|
+
).receive(
|
|
2359
|
+
"timeout",
|
|
2360
|
+
() => reject(new TransportError(`Timeout leaving topic ${topic}`))
|
|
2361
|
+
);
|
|
1907
2362
|
});
|
|
1908
2363
|
this.channels.delete(topic);
|
|
1909
2364
|
this.logger.debug("Left topic", { topic });
|
|
1910
2365
|
}
|
|
1911
2366
|
async runForever(signal) {
|
|
2367
|
+
if (this.terminalDisconnectError) {
|
|
2368
|
+
throw this.terminalDisconnectError;
|
|
2369
|
+
}
|
|
1912
2370
|
if (signal.aborted) {
|
|
1913
2371
|
return;
|
|
1914
2372
|
}
|
|
1915
|
-
await new Promise((resolve) => {
|
|
1916
|
-
|
|
2373
|
+
await new Promise((resolve, reject) => {
|
|
2374
|
+
let settled = false;
|
|
2375
|
+
const abortController = new AbortController();
|
|
2376
|
+
const waiter = {
|
|
2377
|
+
reject: (error) => {
|
|
2378
|
+
if (settled) {
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
settled = true;
|
|
2382
|
+
this.runForeverWaiters.delete(waiter);
|
|
2383
|
+
abortController.abort();
|
|
2384
|
+
reject(error);
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
this.runForeverWaiters.add(waiter);
|
|
2388
|
+
signal.addEventListener(
|
|
2389
|
+
"abort",
|
|
2390
|
+
() => {
|
|
2391
|
+
if (settled) {
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
settled = true;
|
|
2395
|
+
this.runForeverWaiters.delete(waiter);
|
|
2396
|
+
resolve();
|
|
2397
|
+
},
|
|
2398
|
+
{ once: true, signal: abortController.signal }
|
|
2399
|
+
);
|
|
1917
2400
|
});
|
|
1918
2401
|
}
|
|
2402
|
+
async handleOpen() {
|
|
2403
|
+
try {
|
|
2404
|
+
await this.subscribeAgentControl();
|
|
2405
|
+
} catch (error) {
|
|
2406
|
+
this.connected = false;
|
|
2407
|
+
this.socket.disconnect();
|
|
2408
|
+
this.connectReject?.(
|
|
2409
|
+
error instanceof Error ? error : new TransportError(String(error))
|
|
2410
|
+
);
|
|
2411
|
+
this.logger.warn("Failed to join mandatory agent_control channel", {
|
|
2412
|
+
error
|
|
2413
|
+
});
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
this.connected = true;
|
|
2417
|
+
this.connectResolve?.();
|
|
2418
|
+
this.connectResolve = null;
|
|
2419
|
+
this.connectReject = null;
|
|
2420
|
+
this.logger.info("Phoenix socket opened", {
|
|
2421
|
+
channels: getSocketChannelCount(this.socket)
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
stopReconnectIfNoChannels(options = {}) {
|
|
2425
|
+
if (this.stoppingReconnect || getSocketChannelCount(this.socket) !== 0) {
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
this.suppressNextCloseReason = options.suppressCloseReason ?? false;
|
|
2429
|
+
this.stoppingReconnect = true;
|
|
2430
|
+
this.socket.disconnect();
|
|
2431
|
+
this.stoppingReconnect = false;
|
|
2432
|
+
}
|
|
2433
|
+
async subscribeAgentControl() {
|
|
2434
|
+
if (!this.agentId) {
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
await this.join(`agent_control:${this.agentId}`, {
|
|
2438
|
+
supersede: (payload) => {
|
|
2439
|
+
const reason = parseSupersedeDisconnectReason(payload);
|
|
2440
|
+
if (!reason) {
|
|
2441
|
+
this.logger.warn("Invalid agent_control supersede payload", {
|
|
2442
|
+
payload
|
|
2443
|
+
});
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2446
|
+
this.recordTerminalDisconnect(reason);
|
|
2447
|
+
}
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
recordSocketClose(event) {
|
|
2451
|
+
this.connected = false;
|
|
2452
|
+
const suppressCloseReason = this.suppressNextCloseReason;
|
|
2453
|
+
this.suppressNextCloseReason = false;
|
|
2454
|
+
this.stopReconnectIfNoChannels();
|
|
2455
|
+
if (!suppressCloseReason && !this.terminalDisconnectError && !this.lastDisconnectReason) {
|
|
2456
|
+
this.lastDisconnectReason = genericCloseReason(event);
|
|
2457
|
+
}
|
|
2458
|
+
this.logger.info("Phoenix socket closed", {
|
|
2459
|
+
code: event?.code ?? null,
|
|
2460
|
+
reason: event?.reason ?? null,
|
|
2461
|
+
platformReason: this.lastDisconnectReason
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
recordTerminalDisconnect(reason) {
|
|
2465
|
+
if (this.terminalDisconnectError) {
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
const error = new WebSocketDisconnectError(reason);
|
|
2469
|
+
this.lastDisconnectReason = reason;
|
|
2470
|
+
this.terminalDisconnectError = error;
|
|
2471
|
+
this.onTerminalDisconnect?.(reason);
|
|
2472
|
+
this.connectReject?.(error);
|
|
2473
|
+
for (const waiter of this.runForeverWaiters) {
|
|
2474
|
+
waiter.reject(error);
|
|
2475
|
+
}
|
|
2476
|
+
this.runForeverWaiters.clear();
|
|
2477
|
+
this.socket.disconnect();
|
|
2478
|
+
}
|
|
1919
2479
|
async waitForConnection(timeoutMs = 1e4) {
|
|
1920
2480
|
if (this.connected) {
|
|
1921
2481
|
return;
|
|
@@ -1923,20 +2483,43 @@ var PhoenixChannelsTransport = class {
|
|
|
1923
2483
|
await new Promise((resolve, reject) => {
|
|
1924
2484
|
const timeout = setTimeout(() => {
|
|
1925
2485
|
this.connectResolve = null;
|
|
1926
|
-
|
|
2486
|
+
this.connectReject = null;
|
|
2487
|
+
reject(
|
|
2488
|
+
new TransportError("Timed out waiting for Phoenix socket connection")
|
|
2489
|
+
);
|
|
1927
2490
|
}, timeoutMs);
|
|
1928
2491
|
this.connectResolve = () => {
|
|
1929
2492
|
clearTimeout(timeout);
|
|
2493
|
+
this.connectReject = null;
|
|
1930
2494
|
resolve();
|
|
1931
2495
|
};
|
|
2496
|
+
this.connectReject = (error) => {
|
|
2497
|
+
clearTimeout(timeout);
|
|
2498
|
+
this.connectResolve = null;
|
|
2499
|
+
this.connectReject = null;
|
|
2500
|
+
reject(
|
|
2501
|
+
error instanceof Error ? error : new TransportError(String(error))
|
|
2502
|
+
);
|
|
2503
|
+
};
|
|
1932
2504
|
});
|
|
1933
2505
|
}
|
|
1934
2506
|
};
|
|
1935
|
-
function resolveWebSocketFactory() {
|
|
2507
|
+
function resolveWebSocketFactory(apiKey) {
|
|
1936
2508
|
if (typeof process !== "undefined" && process.versions?.node) {
|
|
1937
|
-
return
|
|
2509
|
+
return createNodeWebSocketFactory({ "x-api-key": apiKey });
|
|
1938
2510
|
}
|
|
1939
|
-
|
|
2511
|
+
throw new TransportError(
|
|
2512
|
+
"Phoenix WebSocket API-key auth requires a WebSocket transport that can set handshake headers."
|
|
2513
|
+
);
|
|
2514
|
+
}
|
|
2515
|
+
function unwrapErrorEvent(event) {
|
|
2516
|
+
if (!isErrorEvent(event)) {
|
|
2517
|
+
return event;
|
|
2518
|
+
}
|
|
2519
|
+
return event.error;
|
|
2520
|
+
}
|
|
2521
|
+
function isErrorEvent(event) {
|
|
2522
|
+
return typeof event === "object" && event !== null && "error" in event;
|
|
1940
2523
|
}
|
|
1941
2524
|
function removeSocketChannel(socket, channel) {
|
|
1942
2525
|
const candidate = socket;
|
|
@@ -1950,15 +2533,21 @@ function getSocketChannelCount(socket) {
|
|
|
1950
2533
|
return candidate.channels.length;
|
|
1951
2534
|
}
|
|
1952
2535
|
|
|
1953
|
-
// src/platform/
|
|
2536
|
+
// src/platform/BandLink.ts
|
|
1954
2537
|
init_protocols();
|
|
1955
|
-
var import_rest_client = require("@
|
|
1956
|
-
var DEFAULT_WS_URL = "wss://app.
|
|
2538
|
+
var import_rest_client = require("@band-ai/rest-client");
|
|
2539
|
+
var DEFAULT_WS_URL = "wss://app.band.ai/api/v1/socket";
|
|
1957
2540
|
function deriveDefaultRestUrl(wsUrl) {
|
|
1958
2541
|
const parsed = new URL(wsUrl);
|
|
1959
2542
|
const protocol = parsed.protocol === "ws:" ? "http:" : "https:";
|
|
1960
2543
|
return `${protocol}//${parsed.host}`;
|
|
1961
2544
|
}
|
|
2545
|
+
function roomTopics(roomId) {
|
|
2546
|
+
return {
|
|
2547
|
+
chat: `chat_room:${roomId}`,
|
|
2548
|
+
participants: `room_participants:${roomId}`
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
1962
2551
|
function toPlatformMessage(roomId, message) {
|
|
1963
2552
|
return {
|
|
1964
2553
|
id: message.id,
|
|
@@ -1972,7 +2561,7 @@ function toPlatformMessage(roomId, message) {
|
|
|
1972
2561
|
createdAt: new Date(message.inserted_at)
|
|
1973
2562
|
};
|
|
1974
2563
|
}
|
|
1975
|
-
var
|
|
2564
|
+
var BandLink = class {
|
|
1976
2565
|
agentId;
|
|
1977
2566
|
apiKey;
|
|
1978
2567
|
wsUrl;
|
|
@@ -1985,6 +2574,8 @@ var ThenvoiLink = class {
|
|
|
1985
2574
|
eventQueue = [];
|
|
1986
2575
|
waiters = [];
|
|
1987
2576
|
connected = false;
|
|
2577
|
+
lastDisconnectReason = null;
|
|
2578
|
+
terminalDisconnectError = null;
|
|
1988
2579
|
constructor(options) {
|
|
1989
2580
|
this.agentId = options.agentId;
|
|
1990
2581
|
this.apiKey = options.apiKey;
|
|
@@ -1996,7 +2587,7 @@ var ThenvoiLink = class {
|
|
|
1996
2587
|
...options.capabilities
|
|
1997
2588
|
};
|
|
1998
2589
|
const restApi = options.restApi ?? new FernRestAdapter(
|
|
1999
|
-
new import_rest_client.
|
|
2590
|
+
new import_rest_client.BandClient({
|
|
2000
2591
|
apiKey: this.apiKey,
|
|
2001
2592
|
baseUrl: this.restUrl
|
|
2002
2593
|
})
|
|
@@ -2006,17 +2597,35 @@ var ThenvoiLink = class {
|
|
|
2006
2597
|
wsUrl: this.wsUrl,
|
|
2007
2598
|
apiKey: this.apiKey,
|
|
2008
2599
|
agentId: this.agentId,
|
|
2009
|
-
logger: this.logger
|
|
2600
|
+
logger: this.logger,
|
|
2601
|
+
conflictPolicy: options.conflictPolicy,
|
|
2602
|
+
onTerminalDisconnect: (reason) => {
|
|
2603
|
+
this.recordDisconnectReason(reason);
|
|
2604
|
+
}
|
|
2010
2605
|
});
|
|
2011
2606
|
}
|
|
2012
2607
|
isConnected() {
|
|
2013
2608
|
return this.connected;
|
|
2014
2609
|
}
|
|
2610
|
+
getDisconnectReason() {
|
|
2611
|
+
return this.lastDisconnectReason;
|
|
2612
|
+
}
|
|
2015
2613
|
async connect() {
|
|
2016
2614
|
if (this.connected) {
|
|
2017
2615
|
return;
|
|
2018
2616
|
}
|
|
2019
|
-
|
|
2617
|
+
try {
|
|
2618
|
+
await this.transport.connect();
|
|
2619
|
+
} catch (error) {
|
|
2620
|
+
if (error instanceof WebSocketDisconnectError) {
|
|
2621
|
+
if (error.reason.retryable) {
|
|
2622
|
+
this.lastDisconnectReason = error.reason;
|
|
2623
|
+
} else {
|
|
2624
|
+
this.recordDisconnectError(error);
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
throw error;
|
|
2628
|
+
}
|
|
2020
2629
|
this.connected = true;
|
|
2021
2630
|
}
|
|
2022
2631
|
async disconnect() {
|
|
@@ -2030,8 +2639,23 @@ var ThenvoiLink = class {
|
|
|
2030
2639
|
this.connected = false;
|
|
2031
2640
|
}
|
|
2032
2641
|
async runForever(signal) {
|
|
2642
|
+
if (this.terminalDisconnectError) {
|
|
2643
|
+
throw this.terminalDisconnectError;
|
|
2644
|
+
}
|
|
2033
2645
|
await this.transport.runForever(signal);
|
|
2034
2646
|
}
|
|
2647
|
+
recordDisconnectReason(reason) {
|
|
2648
|
+
this.recordDisconnectError(new WebSocketDisconnectError(reason));
|
|
2649
|
+
}
|
|
2650
|
+
recordDisconnectError(error) {
|
|
2651
|
+
this.connected = false;
|
|
2652
|
+
this.lastDisconnectReason = error.reason;
|
|
2653
|
+
this.terminalDisconnectError = error;
|
|
2654
|
+
while (this.waiters.length > 0) {
|
|
2655
|
+
const waiter = this.waiters.shift();
|
|
2656
|
+
waiter?.reject(error);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2035
2659
|
queueEvent(event) {
|
|
2036
2660
|
const waiter = this.waiters.shift();
|
|
2037
2661
|
if (waiter) {
|
|
@@ -2056,32 +2680,42 @@ var ThenvoiLink = class {
|
|
|
2056
2680
|
if (this.subscribedRooms.has(roomId)) {
|
|
2057
2681
|
return;
|
|
2058
2682
|
}
|
|
2059
|
-
await this.
|
|
2060
|
-
message_created: (payload) => {
|
|
2061
|
-
this.emit("message_created", payload, roomId);
|
|
2062
|
-
}
|
|
2063
|
-
});
|
|
2064
|
-
await this.transport.join(`room_participants:${roomId}`, {
|
|
2065
|
-
participant_added: (payload) => {
|
|
2066
|
-
this.emit("participant_added", payload, roomId);
|
|
2067
|
-
},
|
|
2068
|
-
participant_removed: (payload) => {
|
|
2069
|
-
this.emit("participant_removed", payload, roomId);
|
|
2070
|
-
},
|
|
2071
|
-
room_deleted: (payload) => {
|
|
2072
|
-
this.emit("room_deleted", payload, roomId);
|
|
2073
|
-
}
|
|
2074
|
-
});
|
|
2683
|
+
await this.joinRoomTopics(roomId);
|
|
2075
2684
|
this.subscribedRooms.add(roomId);
|
|
2076
2685
|
}
|
|
2077
2686
|
async unsubscribeRoom(roomId) {
|
|
2078
2687
|
if (!this.subscribedRooms.has(roomId)) {
|
|
2079
2688
|
return;
|
|
2080
2689
|
}
|
|
2081
|
-
|
|
2082
|
-
await this.transport.leave(
|
|
2690
|
+
const topics = roomTopics(roomId);
|
|
2691
|
+
await this.transport.leave(topics.chat);
|
|
2692
|
+
await this.transport.leave(topics.participants);
|
|
2083
2693
|
this.subscribedRooms.delete(roomId);
|
|
2084
2694
|
}
|
|
2695
|
+
async joinRoomTopics(roomId) {
|
|
2696
|
+
const topics = roomTopics(roomId);
|
|
2697
|
+
await this.transport.join(topics.chat, {
|
|
2698
|
+
message_created: (payload) => {
|
|
2699
|
+
this.emit("message_created", payload, roomId);
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2702
|
+
try {
|
|
2703
|
+
await this.transport.join(topics.participants, {
|
|
2704
|
+
participant_added: (payload) => {
|
|
2705
|
+
this.emit("participant_added", payload, roomId);
|
|
2706
|
+
},
|
|
2707
|
+
participant_removed: (payload) => {
|
|
2708
|
+
this.emit("participant_removed", payload, roomId);
|
|
2709
|
+
},
|
|
2710
|
+
room_deleted: (payload) => {
|
|
2711
|
+
this.emit("room_deleted", payload, roomId);
|
|
2712
|
+
}
|
|
2713
|
+
});
|
|
2714
|
+
} catch (error) {
|
|
2715
|
+
await this.transport.leave(topics.chat);
|
|
2716
|
+
throw error;
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2085
2719
|
async subscribeAgentContacts() {
|
|
2086
2720
|
assertCapability(this.capabilities, "contacts", "Contacts streaming");
|
|
2087
2721
|
await this.transport.join(`agent_contacts:${this.agentId}`, {
|
|
@@ -2103,6 +2737,9 @@ var ThenvoiLink = class {
|
|
|
2103
2737
|
await this.transport.leave(`agent_contacts:${this.agentId}`);
|
|
2104
2738
|
}
|
|
2105
2739
|
async nextEvent(signal) {
|
|
2740
|
+
if (this.terminalDisconnectError) {
|
|
2741
|
+
throw this.terminalDisconnectError;
|
|
2742
|
+
}
|
|
2106
2743
|
if (signal?.aborted) {
|
|
2107
2744
|
return null;
|
|
2108
2745
|
}
|
|
@@ -2110,19 +2747,19 @@ var ThenvoiLink = class {
|
|
|
2110
2747
|
if (queued) {
|
|
2111
2748
|
return queued;
|
|
2112
2749
|
}
|
|
2113
|
-
return new Promise((resolve) => {
|
|
2750
|
+
return new Promise((resolve, reject) => {
|
|
2114
2751
|
let settled = false;
|
|
2115
2752
|
const onAbort = () => {
|
|
2116
2753
|
const index = this.waiters.indexOf(waiter);
|
|
2117
2754
|
if (index >= 0) {
|
|
2118
2755
|
this.waiters.splice(index, 1);
|
|
2119
2756
|
}
|
|
2120
|
-
|
|
2757
|
+
finalizeResolve(null);
|
|
2121
2758
|
};
|
|
2122
2759
|
const cleanup = () => {
|
|
2123
2760
|
signal?.removeEventListener("abort", onAbort);
|
|
2124
2761
|
};
|
|
2125
|
-
const
|
|
2762
|
+
const finalizeResolve = (event) => {
|
|
2126
2763
|
if (settled) {
|
|
2127
2764
|
return;
|
|
2128
2765
|
}
|
|
@@ -2130,8 +2767,17 @@ var ThenvoiLink = class {
|
|
|
2130
2767
|
cleanup();
|
|
2131
2768
|
resolve(event);
|
|
2132
2769
|
};
|
|
2770
|
+
const finalizeReject = (error) => {
|
|
2771
|
+
if (settled) {
|
|
2772
|
+
return;
|
|
2773
|
+
}
|
|
2774
|
+
settled = true;
|
|
2775
|
+
cleanup();
|
|
2776
|
+
reject(error);
|
|
2777
|
+
};
|
|
2133
2778
|
const waiter = {
|
|
2134
|
-
resolve:
|
|
2779
|
+
resolve: finalizeResolve,
|
|
2780
|
+
reject: finalizeReject,
|
|
2135
2781
|
cleanup
|
|
2136
2782
|
};
|
|
2137
2783
|
this.waiters.push(waiter);
|
|
@@ -2143,7 +2789,10 @@ var ThenvoiLink = class {
|
|
|
2143
2789
|
next: async () => {
|
|
2144
2790
|
const value = await this.nextEvent();
|
|
2145
2791
|
if (value === null) {
|
|
2146
|
-
return {
|
|
2792
|
+
return {
|
|
2793
|
+
done: true,
|
|
2794
|
+
value: void 0
|
|
2795
|
+
};
|
|
2147
2796
|
}
|
|
2148
2797
|
return { done: false, value };
|
|
2149
2798
|
}
|
|
@@ -2225,7 +2874,9 @@ var ThenvoiLink = class {
|
|
|
2225
2874
|
}
|
|
2226
2875
|
async listChats(request, requestOptions) {
|
|
2227
2876
|
if (!this.rest.listChats) {
|
|
2228
|
-
throw new UnsupportedFeatureError(
|
|
2877
|
+
throw new UnsupportedFeatureError(
|
|
2878
|
+
"Chat listing is not available in current REST adapter"
|
|
2879
|
+
);
|
|
2229
2880
|
}
|
|
2230
2881
|
return this.rest.listChats(request, requestOptions);
|
|
2231
2882
|
}
|
|
@@ -2554,10 +3205,109 @@ var Execution = class {
|
|
|
2554
3205
|
init_errors();
|
|
2555
3206
|
|
|
2556
3207
|
// src/runtime/tools/AgentTools.ts
|
|
2557
|
-
init_errors();
|
|
3208
|
+
init_errors();
|
|
3209
|
+
var import_band_sdk_core = require("@band-ai/band-sdk-core");
|
|
3210
|
+
|
|
3211
|
+
// src/runtime/types.ts
|
|
3212
|
+
var HistoryProvider = class {
|
|
3213
|
+
raw;
|
|
3214
|
+
constructor(raw) {
|
|
3215
|
+
this.raw = raw;
|
|
3216
|
+
}
|
|
3217
|
+
convert(converter) {
|
|
3218
|
+
return converter.convert(this.raw);
|
|
3219
|
+
}
|
|
3220
|
+
get length() {
|
|
3221
|
+
return this.raw.length;
|
|
3222
|
+
}
|
|
3223
|
+
};
|
|
3224
|
+
var SYNTHETIC_SENDER_TYPE = "System";
|
|
3225
|
+
var SYNTHETIC_CONTACT_EVENTS_SENDER_ID = "contact-events";
|
|
3226
|
+
var SYNTHETIC_CONTACT_EVENTS_SENDER_NAME = "Contact Events";
|
|
3227
|
+
function ensureHandlePrefix(handle) {
|
|
3228
|
+
if (!handle) {
|
|
3229
|
+
return null;
|
|
3230
|
+
}
|
|
3231
|
+
return handle.startsWith("@") ? handle : `@${handle}`;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// src/runtime/formatters.ts
|
|
3235
|
+
function isMetadataMap(value) {
|
|
3236
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3237
|
+
}
|
|
3238
|
+
function replaceUuidMentions(content, participants) {
|
|
3239
|
+
if (!content || participants.length === 0) {
|
|
3240
|
+
return content;
|
|
3241
|
+
}
|
|
3242
|
+
let next = content;
|
|
3243
|
+
for (const participant of participants) {
|
|
3244
|
+
const participantId = participant.id;
|
|
3245
|
+
const handle = participant.handle;
|
|
3246
|
+
if (typeof participantId === "string" && typeof handle === "string") {
|
|
3247
|
+
next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
return next;
|
|
3251
|
+
}
|
|
3252
|
+
function formatMessageForLlm(message, participants) {
|
|
3253
|
+
const senderType = String(message.sender_type ?? "");
|
|
3254
|
+
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
3255
|
+
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
3256
|
+
return {
|
|
3257
|
+
role: senderType === "Agent" ? "assistant" : "user",
|
|
3258
|
+
content,
|
|
3259
|
+
sender_name: senderName,
|
|
3260
|
+
sender_type: senderType,
|
|
3261
|
+
message_type: String(message.message_type ?? "text"),
|
|
3262
|
+
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
function formatHistoryForLlm(messages, options) {
|
|
3266
|
+
const excludeId = options?.excludeId;
|
|
3267
|
+
const participants = options?.participants;
|
|
3268
|
+
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
3269
|
+
}
|
|
3270
|
+
function toParticipantRecord(fields) {
|
|
3271
|
+
return {
|
|
3272
|
+
id: fields.id,
|
|
3273
|
+
name: fields.name ?? "unknown",
|
|
3274
|
+
type: fields.type ?? "unknown",
|
|
3275
|
+
handle: fields.handle ?? null
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
function toParticipantRecordFromRest(participant) {
|
|
3279
|
+
return {
|
|
3280
|
+
id: participant.id,
|
|
3281
|
+
name: participant.name,
|
|
3282
|
+
type: participant.type,
|
|
3283
|
+
handle: participant.handle ?? null
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
function buildParticipantsMessage(participants) {
|
|
3287
|
+
if (participants.length === 0) {
|
|
3288
|
+
return "## Current Participants\nNo other participants in this room.";
|
|
3289
|
+
}
|
|
3290
|
+
const lines = ["## Current Participants"];
|
|
3291
|
+
for (const participant of participants) {
|
|
3292
|
+
const participantType = String(participant.type ?? "Unknown");
|
|
3293
|
+
const participantName = String(participant.name ?? "Unknown");
|
|
3294
|
+
const participantHandle = String(participant.handle ?? "Unknown");
|
|
3295
|
+
lines.push(
|
|
3296
|
+
`- ${ensureHandlePrefix(participantHandle) ?? ""} \u2014 ${participantName} (${participantType})`
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3299
|
+
lines.push("");
|
|
3300
|
+
lines.push(
|
|
3301
|
+
"IMPORTANT: In band_send_message mentions, always use the exact handle shown above (e.g. '@john' for users, '@john/weather-agent' for agents), NOT the display name. Handles are lowercase with no spaces."
|
|
3302
|
+
);
|
|
3303
|
+
return lines.join("\n");
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
// src/runtime/tools/AgentTools.ts
|
|
2558
3307
|
init_chatEvents();
|
|
2559
3308
|
init_protocols();
|
|
2560
3309
|
init_schemas();
|
|
3310
|
+
init_memory();
|
|
2561
3311
|
var REQUIRED_ADAPTER_TOOL_METHODS = [
|
|
2562
3312
|
"sendMessage",
|
|
2563
3313
|
"sendEvent",
|
|
@@ -2592,51 +3342,17 @@ var CONTACT_REQUEST_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
2592
3342
|
"reject",
|
|
2593
3343
|
"cancel"
|
|
2594
3344
|
]);
|
|
2595
|
-
var MEMORY_SYSTEMS = /* @__PURE__ */ new Set([
|
|
2596
|
-
"sensory",
|
|
2597
|
-
"working",
|
|
2598
|
-
"long_term"
|
|
2599
|
-
]);
|
|
2600
|
-
var MEMORY_TYPES = /* @__PURE__ */ new Set([
|
|
2601
|
-
"iconic",
|
|
2602
|
-
"echoic",
|
|
2603
|
-
"haptic",
|
|
2604
|
-
"episodic",
|
|
2605
|
-
"semantic",
|
|
2606
|
-
"procedural"
|
|
2607
|
-
]);
|
|
2608
|
-
var MEMORY_SEGMENTS = /* @__PURE__ */ new Set([
|
|
2609
|
-
"user",
|
|
2610
|
-
"agent",
|
|
2611
|
-
"tool",
|
|
2612
|
-
"guideline"
|
|
2613
|
-
]);
|
|
2614
|
-
var LIST_MEMORY_SCOPES = /* @__PURE__ */ new Set([
|
|
2615
|
-
"subject",
|
|
2616
|
-
"organization",
|
|
2617
|
-
"all"
|
|
2618
|
-
]);
|
|
2619
|
-
var LIST_MEMORY_STATUSES = /* @__PURE__ */ new Set([
|
|
2620
|
-
"active",
|
|
2621
|
-
"superseded",
|
|
2622
|
-
"archived",
|
|
2623
|
-
"all"
|
|
2624
|
-
]);
|
|
2625
|
-
var MEMORY_SCOPES = /* @__PURE__ */ new Set([
|
|
2626
|
-
"subject",
|
|
2627
|
-
"organization"
|
|
2628
|
-
]);
|
|
2629
3345
|
var AgentTools = class {
|
|
2630
3346
|
roomId;
|
|
2631
3347
|
capabilities;
|
|
2632
3348
|
rest;
|
|
2633
|
-
|
|
3349
|
+
roster;
|
|
2634
3350
|
adapterTools;
|
|
2635
3351
|
toolHandlers;
|
|
2636
3352
|
constructor(options) {
|
|
2637
3353
|
this.roomId = options.roomId;
|
|
2638
3354
|
this.rest = options.rest;
|
|
2639
|
-
this.
|
|
3355
|
+
this.roster = options.roster ?? new import_band_sdk_core.ParticipantRoster();
|
|
2640
3356
|
this.capabilities = {
|
|
2641
3357
|
...DEFAULT_AGENT_TOOLS_CAPABILITIES,
|
|
2642
3358
|
...options.capabilities
|
|
@@ -2648,17 +3364,20 @@ var AgentTools = class {
|
|
|
2648
3364
|
return this.adapterTools;
|
|
2649
3365
|
}
|
|
2650
3366
|
async sendMessage(content, mentions = []) {
|
|
2651
|
-
|
|
2652
|
-
|
|
3367
|
+
let participants;
|
|
3368
|
+
if (mentions.length > 0 && typeof mentions[0] === "string") {
|
|
3369
|
+
participants = this.roster.list();
|
|
3370
|
+
if (participants.length === 0) {
|
|
3371
|
+
participants = await this.syncParticipants();
|
|
3372
|
+
}
|
|
2653
3373
|
}
|
|
2654
|
-
const resolvedMentions = this.resolveMentions(mentions);
|
|
3374
|
+
const resolvedMentions = this.resolveMentions(mentions, participants);
|
|
2655
3375
|
return this.rest.createChatMessage(
|
|
2656
3376
|
this.roomId,
|
|
2657
3377
|
{
|
|
2658
3378
|
content,
|
|
2659
3379
|
mentions: resolvedMentions
|
|
2660
|
-
}
|
|
2661
|
-
DEFAULT_REQUEST_OPTIONS
|
|
3380
|
+
}
|
|
2662
3381
|
);
|
|
2663
3382
|
}
|
|
2664
3383
|
async sendEvent(content, messageType, metadata) {
|
|
@@ -2669,8 +3388,7 @@ var AgentTools = class {
|
|
|
2669
3388
|
content,
|
|
2670
3389
|
messageType,
|
|
2671
3390
|
metadata
|
|
2672
|
-
}
|
|
2673
|
-
DEFAULT_REQUEST_OPTIONS
|
|
3391
|
+
}
|
|
2674
3392
|
);
|
|
2675
3393
|
}
|
|
2676
3394
|
async createChatroom(taskId) {
|
|
@@ -2709,7 +3427,7 @@ var AgentTools = class {
|
|
|
2709
3427
|
type: String(peer.type ?? "Agent"),
|
|
2710
3428
|
handle: typeof peer.handle === "string" ? peer.handle : null
|
|
2711
3429
|
};
|
|
2712
|
-
this.
|
|
3430
|
+
this.roster.add(participantRecord);
|
|
2713
3431
|
return {
|
|
2714
3432
|
...participantRecord,
|
|
2715
3433
|
status: "added"
|
|
@@ -2724,7 +3442,7 @@ var AgentTools = class {
|
|
|
2724
3442
|
throw new ValidationError(`Participant '${name}' not found in room`);
|
|
2725
3443
|
}
|
|
2726
3444
|
await this.rest.removeChatParticipant(this.roomId, String(participant.id), DEFAULT_REQUEST_OPTIONS);
|
|
2727
|
-
this.
|
|
3445
|
+
this.roster.remove(participant.id);
|
|
2728
3446
|
return {
|
|
2729
3447
|
id: participant.id,
|
|
2730
3448
|
name,
|
|
@@ -2752,17 +3470,12 @@ var AgentTools = class {
|
|
|
2752
3470
|
}
|
|
2753
3471
|
async fetchParticipants() {
|
|
2754
3472
|
const participants = await this.rest.listChatParticipants(this.roomId, DEFAULT_REQUEST_OPTIONS);
|
|
2755
|
-
return participants.map(
|
|
2756
|
-
id: participant.id,
|
|
2757
|
-
name: participant.name,
|
|
2758
|
-
type: participant.type,
|
|
2759
|
-
handle: participant.handle ?? null
|
|
2760
|
-
}));
|
|
3473
|
+
return participants.map(toParticipantRecordFromRest);
|
|
2761
3474
|
}
|
|
2762
3475
|
async syncParticipants() {
|
|
2763
3476
|
const participants = await this.fetchParticipants();
|
|
2764
|
-
this.
|
|
2765
|
-
return
|
|
3477
|
+
this.roster.setAll(participants);
|
|
3478
|
+
return this.roster.list().map(toParticipantRecord);
|
|
2766
3479
|
}
|
|
2767
3480
|
async executeToolCall(toolName, arguments_) {
|
|
2768
3481
|
const validationError = validateToolArgs(toolName, arguments_);
|
|
@@ -2810,7 +3523,7 @@ var AgentTools = class {
|
|
|
2810
3523
|
if (!CHAT_TOOL_NAMES.has(name) && !this.capabilities.contacts) {
|
|
2811
3524
|
return false;
|
|
2812
3525
|
}
|
|
2813
|
-
if (name === "
|
|
3526
|
+
if (name === "band_lookup_peers" && !this.capabilities.peers) {
|
|
2814
3527
|
return false;
|
|
2815
3528
|
}
|
|
2816
3529
|
return true;
|
|
@@ -3005,7 +3718,7 @@ var AgentTools = class {
|
|
|
3005
3718
|
}
|
|
3006
3719
|
return this.rest.archiveMemory(normalizedMemoryId, DEFAULT_REQUEST_OPTIONS);
|
|
3007
3720
|
}
|
|
3008
|
-
resolveMentions(mentions) {
|
|
3721
|
+
resolveMentions(mentions, participants) {
|
|
3009
3722
|
if (mentions.length === 0) {
|
|
3010
3723
|
return [];
|
|
3011
3724
|
}
|
|
@@ -3018,7 +3731,7 @@ var AgentTools = class {
|
|
|
3018
3731
|
const participantsByHandle = /* @__PURE__ */ new Map();
|
|
3019
3732
|
const participantsById = /* @__PURE__ */ new Map();
|
|
3020
3733
|
const participantsByName = /* @__PURE__ */ new Map();
|
|
3021
|
-
for (const participant of
|
|
3734
|
+
for (const participant of participants ?? []) {
|
|
3022
3735
|
const ref = {
|
|
3023
3736
|
id: String(participant.id),
|
|
3024
3737
|
handle: typeof participant.handle === "string" ? participant.handle : void 0
|
|
@@ -3074,9 +3787,6 @@ var AgentTools = class {
|
|
|
3074
3787
|
normalizeMentionHandle(handle) {
|
|
3075
3788
|
return handle.trim().replace(/^@+/, "").toLowerCase();
|
|
3076
3789
|
}
|
|
3077
|
-
replaceParticipants(participants) {
|
|
3078
|
-
this.participants.splice(0, this.participants.length, ...participants);
|
|
3079
|
-
}
|
|
3080
3790
|
buildAdapterTools() {
|
|
3081
3791
|
const tools = {
|
|
3082
3792
|
capabilities: this.capabilities
|
|
@@ -3107,51 +3817,51 @@ var AgentTools = class {
|
|
|
3107
3817
|
}
|
|
3108
3818
|
buildMessagingToolHandlers() {
|
|
3109
3819
|
return {
|
|
3110
|
-
|
|
3820
|
+
band_send_message: async (arguments_) => this.sendMessage(
|
|
3111
3821
|
String(arguments_.content ?? ""),
|
|
3112
3822
|
this.normalizeMentionInput(arguments_.mentions)
|
|
3113
3823
|
),
|
|
3114
|
-
|
|
3824
|
+
band_send_event: async (arguments_) => this.sendEvent(
|
|
3115
3825
|
String(arguments_.content ?? ""),
|
|
3116
3826
|
String(arguments_.message_type ?? "task"),
|
|
3117
3827
|
this.normalizeOptionalMetadata(arguments_.metadata)
|
|
3118
3828
|
),
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3829
|
+
band_add_participant: async (arguments_) => this.addParticipant(String(arguments_.name ?? ""), String(arguments_.role ?? "member")),
|
|
3830
|
+
band_remove_participant: async (arguments_) => this.removeParticipant(String(arguments_.name ?? "")),
|
|
3831
|
+
band_lookup_peers: async (arguments_) => this.lookupPeers(
|
|
3122
3832
|
coercePositiveInt(arguments_.page, 1),
|
|
3123
3833
|
coercePositiveInt(arguments_.page_size, 50)
|
|
3124
3834
|
),
|
|
3125
|
-
|
|
3126
|
-
|
|
3835
|
+
band_get_participants: async () => this.getParticipants(),
|
|
3836
|
+
band_create_chatroom: async (arguments_) => this.createChatroom(this.normalizeOptionalString(arguments_.task_id))
|
|
3127
3837
|
};
|
|
3128
3838
|
}
|
|
3129
3839
|
buildContactToolHandlers() {
|
|
3130
3840
|
return {
|
|
3131
|
-
|
|
3841
|
+
band_list_contacts: async (arguments_) => this.listContacts({
|
|
3132
3842
|
page: coercePositiveInt(arguments_.page, 1),
|
|
3133
3843
|
pageSize: coercePositiveInt(arguments_.page_size, 50)
|
|
3134
3844
|
}),
|
|
3135
|
-
|
|
3845
|
+
band_add_contact: async (arguments_) => this.addContact({
|
|
3136
3846
|
handle: String(arguments_.handle ?? ""),
|
|
3137
3847
|
...typeof arguments_.message === "string" ? { message: arguments_.message } : {}
|
|
3138
3848
|
}),
|
|
3139
|
-
|
|
3140
|
-
|
|
3849
|
+
band_remove_contact: async (arguments_) => this.removeContact(this.toRemoveContactArgs(arguments_)),
|
|
3850
|
+
band_list_contact_requests: async (arguments_) => this.listContactRequests({
|
|
3141
3851
|
page: coercePositiveInt(arguments_.page, 1),
|
|
3142
3852
|
pageSize: coercePositiveInt(arguments_.page_size, 50),
|
|
3143
3853
|
sentStatus: String(arguments_.sent_status ?? "pending")
|
|
3144
3854
|
}),
|
|
3145
|
-
|
|
3855
|
+
band_respond_contact_request: async (arguments_) => this.respondContactRequest(this.toRespondContactRequestArgs(arguments_))
|
|
3146
3856
|
};
|
|
3147
3857
|
}
|
|
3148
3858
|
buildMemoryToolHandlers() {
|
|
3149
3859
|
return {
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3860
|
+
band_list_memories: async (arguments_) => this.listMemories(this.toListMemoriesArgs(arguments_)),
|
|
3861
|
+
band_store_memory: async (arguments_) => this.storeMemory(this.toStoreMemoryArgs(arguments_)),
|
|
3862
|
+
band_get_memory: async (arguments_) => this.getMemory(String(arguments_.memory_id ?? "")),
|
|
3863
|
+
band_supersede_memory: async (arguments_) => this.supersedeMemory(String(arguments_.memory_id ?? "")),
|
|
3864
|
+
band_archive_memory: async (arguments_) => this.archiveMemory(String(arguments_.memory_id ?? ""))
|
|
3155
3865
|
};
|
|
3156
3866
|
}
|
|
3157
3867
|
toRemoveContactArgs(arguments_) {
|
|
@@ -3203,6 +3913,9 @@ var AgentTools = class {
|
|
|
3203
3913
|
const status = this.normalizeOptionalMemoryStatus(arguments_.status);
|
|
3204
3914
|
const subjectId = this.normalizeOptionalString(arguments_.subject_id);
|
|
3205
3915
|
const contentQuery = this.normalizeOptionalString(arguments_.content_query);
|
|
3916
|
+
if (system && type && !isMemoryTypeForSystem(system, type)) {
|
|
3917
|
+
throw new ValidationError(memoryTypeForSystemError(system));
|
|
3918
|
+
}
|
|
3206
3919
|
return {
|
|
3207
3920
|
...subjectId ? { subject_id: subjectId } : {},
|
|
3208
3921
|
...scope ? { scope } : {},
|
|
@@ -3224,13 +3937,21 @@ var AgentTools = class {
|
|
|
3224
3937
|
const subjectId = this.normalizeOptionalString(arguments_.subject_id);
|
|
3225
3938
|
const metadata = this.normalizeOptionalMetadata(arguments_.metadata);
|
|
3226
3939
|
if (!system) {
|
|
3227
|
-
throw new ValidationError(
|
|
3940
|
+
throw new ValidationError(`system must be one of: ${expectedList(MEMORY_SYSTEMS)}`);
|
|
3228
3941
|
}
|
|
3229
3942
|
if (!type) {
|
|
3230
|
-
throw new ValidationError(
|
|
3943
|
+
throw new ValidationError(`type must be one of: ${expectedList(MEMORY_TYPES)}`);
|
|
3944
|
+
}
|
|
3945
|
+
if (!isMemoryTypeForSystem(system, type)) {
|
|
3946
|
+
throw new ValidationError(memoryTypeForSystemError(system));
|
|
3231
3947
|
}
|
|
3232
3948
|
if (!segment) {
|
|
3233
|
-
throw new ValidationError(
|
|
3949
|
+
throw new ValidationError(`segment must be one of: ${expectedList(MEMORY_SEGMENTS)}`);
|
|
3950
|
+
}
|
|
3951
|
+
if (scope === "subject" && !subjectId) {
|
|
3952
|
+
throw new ValidationError(
|
|
3953
|
+
'scope="subject" requires a subject_id (the UUID of the person or agent the memory is about). If you do not have a concrete subject UUID, retry with scope="organization" and omit subject_id. Do not invent a UUID.'
|
|
3954
|
+
);
|
|
3234
3955
|
}
|
|
3235
3956
|
return {
|
|
3236
3957
|
content,
|
|
@@ -3310,8 +4031,8 @@ var AgentTools = class {
|
|
|
3310
4031
|
if (!normalized) {
|
|
3311
4032
|
return void 0;
|
|
3312
4033
|
}
|
|
3313
|
-
if (!
|
|
3314
|
-
throw new ValidationError(
|
|
4034
|
+
if (!isMemoryListScope(normalized)) {
|
|
4035
|
+
throw new ValidationError(`scope must be one of: ${expectedList(MEMORY_LIST_SCOPES)}`);
|
|
3315
4036
|
}
|
|
3316
4037
|
return normalized;
|
|
3317
4038
|
}
|
|
@@ -3321,7 +4042,7 @@ var AgentTools = class {
|
|
|
3321
4042
|
return void 0;
|
|
3322
4043
|
}
|
|
3323
4044
|
if (!isMemorySystem(normalized)) {
|
|
3324
|
-
throw new ValidationError(
|
|
4045
|
+
throw new ValidationError(`system must be one of: ${expectedList(MEMORY_SYSTEMS)}`);
|
|
3325
4046
|
}
|
|
3326
4047
|
return normalized;
|
|
3327
4048
|
}
|
|
@@ -3331,7 +4052,7 @@ var AgentTools = class {
|
|
|
3331
4052
|
return void 0;
|
|
3332
4053
|
}
|
|
3333
4054
|
if (!isMemoryType(normalized)) {
|
|
3334
|
-
throw new ValidationError(
|
|
4055
|
+
throw new ValidationError(`type must be one of: ${expectedList(MEMORY_TYPES)}`);
|
|
3335
4056
|
}
|
|
3336
4057
|
return normalized;
|
|
3337
4058
|
}
|
|
@@ -3341,7 +4062,7 @@ var AgentTools = class {
|
|
|
3341
4062
|
return void 0;
|
|
3342
4063
|
}
|
|
3343
4064
|
if (!isMemorySegment(normalized)) {
|
|
3344
|
-
throw new ValidationError(
|
|
4065
|
+
throw new ValidationError(`segment must be one of: ${expectedList(MEMORY_SEGMENTS)}`);
|
|
3345
4066
|
}
|
|
3346
4067
|
return normalized;
|
|
3347
4068
|
}
|
|
@@ -3351,7 +4072,7 @@ var AgentTools = class {
|
|
|
3351
4072
|
return void 0;
|
|
3352
4073
|
}
|
|
3353
4074
|
if (!isMemoryStatus(normalized)) {
|
|
3354
|
-
throw new ValidationError(
|
|
4075
|
+
throw new ValidationError(`status must be one of: ${expectedList(MEMORY_STATUSES)}`);
|
|
3355
4076
|
}
|
|
3356
4077
|
return normalized;
|
|
3357
4078
|
}
|
|
@@ -3360,8 +4081,8 @@ var AgentTools = class {
|
|
|
3360
4081
|
if (!normalized) {
|
|
3361
4082
|
return void 0;
|
|
3362
4083
|
}
|
|
3363
|
-
if (!
|
|
3364
|
-
throw new ValidationError(
|
|
4084
|
+
if (!isMemoryStoreScope(normalized)) {
|
|
4085
|
+
throw new ValidationError(`scope must be one of: ${expectedList(MEMORY_STORE_SCOPES)}`);
|
|
3365
4086
|
}
|
|
3366
4087
|
return normalized;
|
|
3367
4088
|
}
|
|
@@ -3369,24 +4090,6 @@ var AgentTools = class {
|
|
|
3369
4090
|
function isContactRequestAction(value) {
|
|
3370
4091
|
return CONTACT_REQUEST_ACTIONS.has(value);
|
|
3371
4092
|
}
|
|
3372
|
-
function isMemorySystem(value) {
|
|
3373
|
-
return MEMORY_SYSTEMS.has(value);
|
|
3374
|
-
}
|
|
3375
|
-
function isMemoryType(value) {
|
|
3376
|
-
return MEMORY_TYPES.has(value);
|
|
3377
|
-
}
|
|
3378
|
-
function isMemorySegment(value) {
|
|
3379
|
-
return MEMORY_SEGMENTS.has(value);
|
|
3380
|
-
}
|
|
3381
|
-
function isStoreMemoryScope(value) {
|
|
3382
|
-
return MEMORY_SCOPES.has(value);
|
|
3383
|
-
}
|
|
3384
|
-
function isListMemoryScope(value) {
|
|
3385
|
-
return LIST_MEMORY_SCOPES.has(value);
|
|
3386
|
-
}
|
|
3387
|
-
function isMemoryStatus(value) {
|
|
3388
|
-
return LIST_MEMORY_STATUSES.has(value);
|
|
3389
|
-
}
|
|
3390
4093
|
function coercePositiveInt(value, fallback) {
|
|
3391
4094
|
const num = Number(value ?? fallback);
|
|
3392
4095
|
return Number.isFinite(num) && num >= 1 ? Math.floor(num) : fallback;
|
|
@@ -3402,13 +4105,13 @@ function validateToolArgs(toolName, args) {
|
|
|
3402
4105
|
errors.push(`${field}: Field required`);
|
|
3403
4106
|
}
|
|
3404
4107
|
}
|
|
3405
|
-
if (toolName === "
|
|
4108
|
+
if (toolName === "band_send_message") {
|
|
3406
4109
|
const mentions = args.mentions;
|
|
3407
4110
|
if (Array.isArray(mentions) && mentions.length === 0) {
|
|
3408
4111
|
errors.push("mentions: At least one mention is required");
|
|
3409
4112
|
}
|
|
3410
4113
|
}
|
|
3411
|
-
if (toolName === "
|
|
4114
|
+
if (toolName === "band_send_event") {
|
|
3412
4115
|
const messageType = args.message_type;
|
|
3413
4116
|
if (typeof messageType === "string" && !CHAT_EVENT_TYPES.includes(messageType)) {
|
|
3414
4117
|
errors.push(
|
|
@@ -3416,7 +4119,7 @@ function validateToolArgs(toolName, args) {
|
|
|
3416
4119
|
);
|
|
3417
4120
|
}
|
|
3418
4121
|
}
|
|
3419
|
-
if (toolName === "
|
|
4122
|
+
if (toolName === "band_respond_contact_request") {
|
|
3420
4123
|
const action = args.action;
|
|
3421
4124
|
const validActions = ["approve", "reject", "cancel"];
|
|
3422
4125
|
if (typeof action === "string" && !validActions.includes(action)) {
|
|
@@ -3425,18 +4128,20 @@ function validateToolArgs(toolName, args) {
|
|
|
3425
4128
|
);
|
|
3426
4129
|
}
|
|
3427
4130
|
}
|
|
3428
|
-
if (toolName === "
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
const validSegments = ["user", "agent", "tool", "guideline"];
|
|
3432
|
-
if (typeof args.system === "string" && !validSystems.includes(args.system)) {
|
|
3433
|
-
errors.push(`system: Invalid value '${args.system}'. Expected one of: ${validSystems.join(", ")}`);
|
|
4131
|
+
if (toolName === "band_store_memory") {
|
|
4132
|
+
if (typeof args.system === "string" && !isMemorySystem(args.system)) {
|
|
4133
|
+
errors.push(`system: Invalid value '${args.system}'. Expected one of: ${expectedList(MEMORY_SYSTEMS)}`);
|
|
3434
4134
|
}
|
|
3435
|
-
if (typeof args.type === "string" && !
|
|
3436
|
-
errors.push(`type: Invalid value '${args.type}'. Expected one of: ${
|
|
4135
|
+
if (typeof args.type === "string" && !isMemoryType(args.type)) {
|
|
4136
|
+
errors.push(`type: Invalid value '${args.type}'. Expected one of: ${expectedList(MEMORY_TYPES)}`);
|
|
4137
|
+
}
|
|
4138
|
+
if (typeof args.system === "string" && isMemorySystem(args.system) && typeof args.type === "string" && isMemoryType(args.type) && !isMemoryTypeForSystem(args.system, args.type)) {
|
|
4139
|
+
errors.push(
|
|
4140
|
+
`type: Invalid value '${args.type}' for system '${args.system}'. Expected one of: ${expectedMemoryTypesForSystem(args.system)}`
|
|
4141
|
+
);
|
|
3437
4142
|
}
|
|
3438
|
-
if (typeof args.segment === "string" && !
|
|
3439
|
-
errors.push(`segment: Invalid value '${args.segment}'. Expected one of: ${
|
|
4143
|
+
if (typeof args.segment === "string" && !isMemorySegment(args.segment)) {
|
|
4144
|
+
errors.push(`segment: Invalid value '${args.segment}'. Expected one of: ${expectedList(MEMORY_SEGMENTS)}`);
|
|
3440
4145
|
}
|
|
3441
4146
|
}
|
|
3442
4147
|
if (errors.length > 0) {
|
|
@@ -3452,112 +4157,8 @@ function validateToolArgs(toolName, args) {
|
|
|
3452
4157
|
return null;
|
|
3453
4158
|
}
|
|
3454
4159
|
|
|
3455
|
-
// src/runtime/retryTracker.ts
|
|
3456
|
-
var DEFAULT_MAX_TRACKED = 1e4;
|
|
3457
|
-
var MessageRetryTracker = class {
|
|
3458
|
-
maxRetriesValue;
|
|
3459
|
-
maxTracked;
|
|
3460
|
-
attempts = /* @__PURE__ */ new Map();
|
|
3461
|
-
failed = /* @__PURE__ */ new Set();
|
|
3462
|
-
constructor(maxRetries = 1, maxTracked = DEFAULT_MAX_TRACKED) {
|
|
3463
|
-
this.maxRetriesValue = maxRetries;
|
|
3464
|
-
this.maxTracked = maxTracked;
|
|
3465
|
-
}
|
|
3466
|
-
get maxRetries() {
|
|
3467
|
-
return this.maxRetriesValue;
|
|
3468
|
-
}
|
|
3469
|
-
isPermanentlyFailed(messageId) {
|
|
3470
|
-
return this.failed.has(messageId);
|
|
3471
|
-
}
|
|
3472
|
-
recordAttempt(messageId) {
|
|
3473
|
-
const attempts = (this.attempts.get(messageId) ?? 0) + 1;
|
|
3474
|
-
this.attempts.set(messageId, attempts);
|
|
3475
|
-
const exceeded = attempts > this.maxRetriesValue;
|
|
3476
|
-
if (exceeded) {
|
|
3477
|
-
this.evictSetIfNeeded(this.failed);
|
|
3478
|
-
this.failed.add(messageId);
|
|
3479
|
-
}
|
|
3480
|
-
this.evictMapIfNeeded(this.attempts);
|
|
3481
|
-
return [attempts, exceeded];
|
|
3482
|
-
}
|
|
3483
|
-
markSuccess(messageId) {
|
|
3484
|
-
this.attempts.delete(messageId);
|
|
3485
|
-
}
|
|
3486
|
-
markPermanentlyFailed(messageId) {
|
|
3487
|
-
this.evictSetIfNeeded(this.failed);
|
|
3488
|
-
this.failed.add(messageId);
|
|
3489
|
-
}
|
|
3490
|
-
evictMapIfNeeded(map) {
|
|
3491
|
-
while (map.size >= this.maxTracked) {
|
|
3492
|
-
const first = map.keys().next();
|
|
3493
|
-
if (first.done) break;
|
|
3494
|
-
map.delete(first.value);
|
|
3495
|
-
}
|
|
3496
|
-
}
|
|
3497
|
-
evictSetIfNeeded(set) {
|
|
3498
|
-
while (set.size >= this.maxTracked) {
|
|
3499
|
-
const first = set.values().next();
|
|
3500
|
-
if (first.done) break;
|
|
3501
|
-
set.delete(first.value);
|
|
3502
|
-
}
|
|
3503
|
-
}
|
|
3504
|
-
};
|
|
3505
|
-
|
|
3506
|
-
// src/runtime/formatters.ts
|
|
3507
|
-
function isMetadataMap(value) {
|
|
3508
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3509
|
-
}
|
|
3510
|
-
function replaceUuidMentions(content, participants) {
|
|
3511
|
-
if (!content || participants.length === 0) {
|
|
3512
|
-
return content;
|
|
3513
|
-
}
|
|
3514
|
-
let next = content;
|
|
3515
|
-
for (const participant of participants) {
|
|
3516
|
-
const participantId = participant.id;
|
|
3517
|
-
const handle = participant.handle;
|
|
3518
|
-
if (typeof participantId === "string" && typeof handle === "string") {
|
|
3519
|
-
next = next.replaceAll(`@[[${participantId}]]`, `@${handle}`);
|
|
3520
|
-
}
|
|
3521
|
-
}
|
|
3522
|
-
return next;
|
|
3523
|
-
}
|
|
3524
|
-
function formatMessageForLlm(message, participants) {
|
|
3525
|
-
const senderType = String(message.sender_type ?? "");
|
|
3526
|
-
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
3527
|
-
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
3528
|
-
return {
|
|
3529
|
-
role: senderType === "Agent" ? "assistant" : "user",
|
|
3530
|
-
content,
|
|
3531
|
-
sender_name: senderName,
|
|
3532
|
-
sender_type: senderType,
|
|
3533
|
-
message_type: String(message.message_type ?? "text"),
|
|
3534
|
-
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
3535
|
-
};
|
|
3536
|
-
}
|
|
3537
|
-
function formatHistoryForLlm(messages, options) {
|
|
3538
|
-
const excludeId = options?.excludeId;
|
|
3539
|
-
const participants = options?.participants;
|
|
3540
|
-
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
3541
|
-
}
|
|
3542
|
-
function buildParticipantsMessage(participants) {
|
|
3543
|
-
if (participants.length === 0) {
|
|
3544
|
-
return "## Current Participants\nNo other participants in this room.";
|
|
3545
|
-
}
|
|
3546
|
-
const lines = ["## Current Participants"];
|
|
3547
|
-
for (const participant of participants) {
|
|
3548
|
-
const participantType = String(participant.type ?? "Unknown");
|
|
3549
|
-
const participantName = String(participant.name ?? "Unknown");
|
|
3550
|
-
const participantHandle = String(participant.handle ?? "Unknown");
|
|
3551
|
-
lines.push(`- @${participantHandle} \u2014 ${participantName} (${participantType})`);
|
|
3552
|
-
}
|
|
3553
|
-
lines.push("");
|
|
3554
|
-
lines.push(
|
|
3555
|
-
"IMPORTANT: In thenvoi_send_message mentions, always use the exact handle shown above (e.g. '@john' for users, '@john/weather-agent' for agents), NOT the display name. Handles are lowercase with no spaces."
|
|
3556
|
-
);
|
|
3557
|
-
return lines.join("\n");
|
|
3558
|
-
}
|
|
3559
|
-
|
|
3560
4160
|
// src/runtime/ExecutionContext.ts
|
|
4161
|
+
var import_band_sdk_core2 = require("@band-ai/band-sdk-core");
|
|
3561
4162
|
var DEDUP_CACHE_MAX = 500;
|
|
3562
4163
|
var ExecutionContext = class {
|
|
3563
4164
|
roomId;
|
|
@@ -3569,11 +4170,10 @@ var ExecutionContext = class {
|
|
|
3569
4170
|
history = [];
|
|
3570
4171
|
messageIds = /* @__PURE__ */ new Set();
|
|
3571
4172
|
dedupCache = /* @__PURE__ */ new Map();
|
|
3572
|
-
|
|
4173
|
+
roster = new import_band_sdk_core2.ParticipantRoster();
|
|
3573
4174
|
tools;
|
|
3574
4175
|
adapterTools;
|
|
3575
4176
|
participantsMessage = null;
|
|
3576
|
-
lastSentParticipantIds = null;
|
|
3577
4177
|
contactsMessage = null;
|
|
3578
4178
|
contextCache = null;
|
|
3579
4179
|
contextCacheExpiresAt = 0;
|
|
@@ -3588,11 +4188,11 @@ var ExecutionContext = class {
|
|
|
3588
4188
|
this.enableContextCache = options.enableContextCache ?? true;
|
|
3589
4189
|
this.contextCacheTtlMs = Math.max(0, (options.contextCacheTtlSeconds ?? 300) * 1e3);
|
|
3590
4190
|
this.enableContextHydration = options.enableContextHydration ?? true;
|
|
3591
|
-
this.retryTrackerInstance = new
|
|
4191
|
+
this.retryTrackerInstance = new import_band_sdk_core2.RetryTracker(options.maxMessageRetries ?? 1);
|
|
3592
4192
|
this.tools = new AgentTools({
|
|
3593
4193
|
roomId: this.roomId,
|
|
3594
4194
|
rest: this.link.rest,
|
|
3595
|
-
|
|
4195
|
+
roster: this.roster,
|
|
3596
4196
|
capabilities: this.link.capabilities
|
|
3597
4197
|
});
|
|
3598
4198
|
this.adapterTools = this.tools.getAdapterTools();
|
|
@@ -3660,23 +4260,20 @@ var ExecutionContext = class {
|
|
|
3660
4260
|
}));
|
|
3661
4261
|
}
|
|
3662
4262
|
setParticipants(participants) {
|
|
3663
|
-
this.
|
|
4263
|
+
this.roster.setAll(participants);
|
|
3664
4264
|
this.updateCachedParticipants();
|
|
3665
4265
|
}
|
|
3666
4266
|
addParticipant(participant) {
|
|
3667
|
-
const
|
|
3668
|
-
if (
|
|
3669
|
-
|
|
4267
|
+
const isNew = this.roster.add(participant);
|
|
4268
|
+
if (isNew) {
|
|
4269
|
+
const name = String(participant.name ?? "unknown");
|
|
4270
|
+
this.participantsMessage = `${name} joined the room.`;
|
|
3670
4271
|
}
|
|
3671
|
-
this.participants.push(participant);
|
|
3672
|
-
const name = String(participant.name ?? "unknown");
|
|
3673
|
-
this.participantsMessage = `${name} joined the room.`;
|
|
3674
4272
|
this.updateCachedParticipants();
|
|
3675
4273
|
}
|
|
3676
4274
|
removeParticipant(participantId) {
|
|
3677
|
-
const removed = this.
|
|
3678
|
-
|
|
3679
|
-
this.replaceParticipants(next);
|
|
4275
|
+
const removed = this.roster.list().find((entry) => entry.id === participantId);
|
|
4276
|
+
this.roster.remove(participantId);
|
|
3680
4277
|
if (removed) {
|
|
3681
4278
|
this.participantsMessage = `${String(removed.name ?? participantId)} left the room.`;
|
|
3682
4279
|
}
|
|
@@ -3686,16 +4283,7 @@ var ExecutionContext = class {
|
|
|
3686
4283
|
this.contactsMessage = message;
|
|
3687
4284
|
}
|
|
3688
4285
|
consumeParticipantsMessage() {
|
|
3689
|
-
const
|
|
3690
|
-
let changed = !this.lastSentParticipantIds || currentIds.size !== this.lastSentParticipantIds.size;
|
|
3691
|
-
if (!changed) {
|
|
3692
|
-
for (const id of currentIds) {
|
|
3693
|
-
if (!this.lastSentParticipantIds.has(id)) {
|
|
3694
|
-
changed = true;
|
|
3695
|
-
break;
|
|
3696
|
-
}
|
|
3697
|
-
}
|
|
3698
|
-
}
|
|
4286
|
+
const changed = this.roster.changed();
|
|
3699
4287
|
if (!changed && !this.participantsMessage) {
|
|
3700
4288
|
return null;
|
|
3701
4289
|
}
|
|
@@ -3705,15 +4293,9 @@ var ExecutionContext = class {
|
|
|
3705
4293
|
this.participantsMessage = null;
|
|
3706
4294
|
}
|
|
3707
4295
|
if (changed) {
|
|
3708
|
-
|
|
3709
|
-
id: p.id,
|
|
3710
|
-
name: p.name,
|
|
3711
|
-
type: p.type,
|
|
3712
|
-
handle: p.handle ?? null
|
|
3713
|
-
}));
|
|
3714
|
-
parts.push(buildParticipantsMessage(asRecords));
|
|
4296
|
+
parts.push(buildParticipantsMessage(this.roster.list().map((p) => ({ ...toParticipantRecord(p) }))));
|
|
3715
4297
|
}
|
|
3716
|
-
this.
|
|
4298
|
+
this.roster.markSent();
|
|
3717
4299
|
return parts.length > 0 ? parts.join("\n") : null;
|
|
3718
4300
|
}
|
|
3719
4301
|
consumeContactsMessage() {
|
|
@@ -3764,27 +4346,19 @@ var ExecutionContext = class {
|
|
|
3764
4346
|
return fallback;
|
|
3765
4347
|
}
|
|
3766
4348
|
}
|
|
3767
|
-
replaceParticipants(participants) {
|
|
3768
|
-
this.participants.splice(0, this.participants.length, ...participants);
|
|
3769
|
-
}
|
|
3770
4349
|
buildLocalContext() {
|
|
3771
4350
|
return {
|
|
3772
4351
|
roomId: this.roomId,
|
|
3773
4352
|
messages: this.getRawHistory(),
|
|
3774
|
-
participants:
|
|
4353
|
+
participants: this.roster.list().map(toParticipantRecord),
|
|
3775
4354
|
hydratedAt: /* @__PURE__ */ new Date()
|
|
3776
4355
|
};
|
|
3777
4356
|
}
|
|
3778
4357
|
async loadParticipants() {
|
|
3779
4358
|
const participants = await this.link.rest.listChatParticipants(this.roomId, DEFAULT_REQUEST_OPTIONS);
|
|
3780
|
-
const normalized = participants.map(
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
type: participant.type,
|
|
3784
|
-
handle: participant.handle ?? null
|
|
3785
|
-
}));
|
|
3786
|
-
this.replaceParticipants(normalized);
|
|
3787
|
-
return [...this.participants];
|
|
4359
|
+
const normalized = participants.map(toParticipantRecordFromRest);
|
|
4360
|
+
this.roster.setAll(normalized);
|
|
4361
|
+
return this.roster.list().map(toParticipantRecord);
|
|
3788
4362
|
}
|
|
3789
4363
|
async loadHydratedMessages() {
|
|
3790
4364
|
const messages = [];
|
|
@@ -3826,7 +4400,7 @@ var ExecutionContext = class {
|
|
|
3826
4400
|
if (!this.contextCache) {
|
|
3827
4401
|
return;
|
|
3828
4402
|
}
|
|
3829
|
-
this.contextCache.participants =
|
|
4403
|
+
this.contextCache.participants = this.roster.list().map(toParticipantRecord);
|
|
3830
4404
|
this.contextCache.hydratedAt = /* @__PURE__ */ new Date();
|
|
3831
4405
|
this.contextCacheExpiresAt = this.nextCacheExpiry();
|
|
3832
4406
|
}
|
|
@@ -4028,7 +4602,7 @@ var AgentRuntime = class {
|
|
|
4028
4602
|
await this.link.disconnect();
|
|
4029
4603
|
}
|
|
4030
4604
|
async stop(timeoutMs) {
|
|
4031
|
-
if (!this.running
|
|
4605
|
+
if (this.stopping || !this.running && !this.fatalError) {
|
|
4032
4606
|
return true;
|
|
4033
4607
|
}
|
|
4034
4608
|
this.stopping = true;
|
|
@@ -4048,7 +4622,8 @@ var AgentRuntime = class {
|
|
|
4048
4622
|
}
|
|
4049
4623
|
}
|
|
4050
4624
|
for (const roomId of [...this.subscribedRooms]) {
|
|
4051
|
-
|
|
4625
|
+
const remaining = deadline === void 0 ? void 0 : Math.max(0, deadline - Date.now());
|
|
4626
|
+
await this.leaveTrackedRoom(roomId, remaining);
|
|
4052
4627
|
}
|
|
4053
4628
|
for (const roomId of [...this.contexts.keys()]) {
|
|
4054
4629
|
await this.onSessionCleanup(roomId);
|
|
@@ -4084,7 +4659,13 @@ var AgentRuntime = class {
|
|
|
4084
4659
|
}
|
|
4085
4660
|
async consumeLoop(signal) {
|
|
4086
4661
|
while (!signal.aborted) {
|
|
4087
|
-
|
|
4662
|
+
let event;
|
|
4663
|
+
try {
|
|
4664
|
+
event = await this.link.nextEvent(signal);
|
|
4665
|
+
} catch (error) {
|
|
4666
|
+
await this.failRuntime(error, syntheticRuntimeFailureEvent(this.agentId));
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4088
4669
|
if (!event) {
|
|
4089
4670
|
return;
|
|
4090
4671
|
}
|
|
@@ -4247,13 +4828,13 @@ var AgentRuntime = class {
|
|
|
4247
4828
|
}
|
|
4248
4829
|
});
|
|
4249
4830
|
}
|
|
4250
|
-
async leaveTrackedRoom(roomId) {
|
|
4831
|
+
async leaveTrackedRoom(roomId, timeoutMs) {
|
|
4251
4832
|
await trackRoomLeave({
|
|
4252
4833
|
link: this.link,
|
|
4253
4834
|
roomId,
|
|
4254
4835
|
trackedRooms: this.subscribedRooms,
|
|
4255
4836
|
onLeft: async (leftRoomId) => {
|
|
4256
|
-
await this.executions.get(leftRoomId)?.stop();
|
|
4837
|
+
await this.executions.get(leftRoomId)?.stop(timeoutMs);
|
|
4257
4838
|
this.contexts.delete(leftRoomId);
|
|
4258
4839
|
this.executions.delete(leftRoomId);
|
|
4259
4840
|
await this.onSessionCleanup(leftRoomId);
|
|
@@ -4290,27 +4871,27 @@ var AgentRuntime = class {
|
|
|
4290
4871
|
}
|
|
4291
4872
|
}
|
|
4292
4873
|
};
|
|
4874
|
+
function syntheticRuntimeFailureEvent(agentId) {
|
|
4875
|
+
return {
|
|
4876
|
+
type: "message_created",
|
|
4877
|
+
roomId: null,
|
|
4878
|
+
payload: {
|
|
4879
|
+
id: "runtime-failed",
|
|
4880
|
+
content: "",
|
|
4881
|
+
sender_id: agentId,
|
|
4882
|
+
sender_type: "Agent",
|
|
4883
|
+
sender_name: null,
|
|
4884
|
+
message_type: "text",
|
|
4885
|
+
metadata: {},
|
|
4886
|
+
inserted_at: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
4887
|
+
updated_at: (/* @__PURE__ */ new Date(0)).toISOString()
|
|
4888
|
+
}
|
|
4889
|
+
};
|
|
4890
|
+
}
|
|
4293
4891
|
function assertNever(value) {
|
|
4294
4892
|
throw new Error(`Unhandled platform event: ${JSON.stringify(value)}`);
|
|
4295
4893
|
}
|
|
4296
4894
|
|
|
4297
|
-
// src/runtime/types.ts
|
|
4298
|
-
var HistoryProvider = class {
|
|
4299
|
-
raw;
|
|
4300
|
-
constructor(raw) {
|
|
4301
|
-
this.raw = raw;
|
|
4302
|
-
}
|
|
4303
|
-
convert(converter) {
|
|
4304
|
-
return converter.convert(this.raw);
|
|
4305
|
-
}
|
|
4306
|
-
get length() {
|
|
4307
|
-
return this.raw.length;
|
|
4308
|
-
}
|
|
4309
|
-
};
|
|
4310
|
-
var SYNTHETIC_SENDER_TYPE = "System";
|
|
4311
|
-
var SYNTHETIC_CONTACT_EVENTS_SENDER_ID = "contact-events";
|
|
4312
|
-
var SYNTHETIC_CONTACT_EVENTS_SENDER_NAME = "Contact Events";
|
|
4313
|
-
|
|
4314
4895
|
// src/runtime/PlatformRuntime.ts
|
|
4315
4896
|
init_errors();
|
|
4316
4897
|
|
|
@@ -4465,14 +5046,6 @@ var ContactToolsImpl = class {
|
|
|
4465
5046
|
};
|
|
4466
5047
|
|
|
4467
5048
|
// src/runtime/tools/ContactCallbackTools.ts
|
|
4468
|
-
function toParticipantRecord(participant) {
|
|
4469
|
-
return {
|
|
4470
|
-
id: participant.id,
|
|
4471
|
-
name: participant.name,
|
|
4472
|
-
type: participant.type,
|
|
4473
|
-
handle: participant.handle ?? null
|
|
4474
|
-
};
|
|
4475
|
-
}
|
|
4476
5049
|
function normalizePage(value, fallback) {
|
|
4477
5050
|
return Number.isInteger(value) && value && value > 0 ? value : fallback;
|
|
4478
5051
|
}
|
|
@@ -4516,8 +5089,7 @@ var ContactCallbackTools = class {
|
|
|
4516
5089
|
{
|
|
4517
5090
|
content,
|
|
4518
5091
|
...normalizedMentions ? { mentions: normalizedMentions } : {}
|
|
4519
|
-
}
|
|
4520
|
-
DEFAULT_REQUEST_OPTIONS
|
|
5092
|
+
}
|
|
4521
5093
|
);
|
|
4522
5094
|
}
|
|
4523
5095
|
async sendEvent(content, messageType, metadata) {
|
|
@@ -4531,8 +5103,7 @@ var ContactCallbackTools = class {
|
|
|
4531
5103
|
content,
|
|
4532
5104
|
messageType,
|
|
4533
5105
|
...metadata ? { metadata } : {}
|
|
4534
|
-
}
|
|
4535
|
-
DEFAULT_REQUEST_OPTIONS
|
|
5106
|
+
}
|
|
4536
5107
|
);
|
|
4537
5108
|
}
|
|
4538
5109
|
async addParticipant() {
|
|
@@ -4546,7 +5117,7 @@ var ContactCallbackTools = class {
|
|
|
4546
5117
|
if (!this.rest.listChatParticipants) {
|
|
4547
5118
|
throw new UnsupportedFeatureError("Participant listing is not available in current REST adapter");
|
|
4548
5119
|
}
|
|
4549
|
-
return (await this.rest.listChatParticipants(roomId, DEFAULT_REQUEST_OPTIONS)).map(
|
|
5120
|
+
return (await this.rest.listChatParticipants(roomId, DEFAULT_REQUEST_OPTIONS)).map(toParticipantRecordFromRest);
|
|
4550
5121
|
}
|
|
4551
5122
|
async createChatroom(taskId) {
|
|
4552
5123
|
const chat = await this.rest.createChat(taskId, DEFAULT_REQUEST_OPTIONS);
|
|
@@ -4636,48 +5207,48 @@ var ContactCallbackTools = class {
|
|
|
4636
5207
|
}
|
|
4637
5208
|
async executeToolCall(toolName, toolArgs) {
|
|
4638
5209
|
switch (toolName) {
|
|
4639
|
-
case "
|
|
5210
|
+
case "band_send_message":
|
|
4640
5211
|
return this.sendMessage(
|
|
4641
5212
|
String(toolArgs.content ?? ""),
|
|
4642
5213
|
toolArgs.mentions
|
|
4643
5214
|
);
|
|
4644
|
-
case "
|
|
5215
|
+
case "band_send_event":
|
|
4645
5216
|
return this.sendEvent(
|
|
4646
5217
|
String(toolArgs.content ?? ""),
|
|
4647
5218
|
String(toolArgs.message_type ?? "task"),
|
|
4648
5219
|
toolArgs.metadata
|
|
4649
5220
|
);
|
|
4650
|
-
case "
|
|
5221
|
+
case "band_get_participants":
|
|
4651
5222
|
return this.getParticipants();
|
|
4652
|
-
case "
|
|
5223
|
+
case "band_create_chatroom":
|
|
4653
5224
|
return this.createChatroom(typeof toolArgs.task_id === "string" ? toolArgs.task_id : void 0);
|
|
4654
|
-
case "
|
|
5225
|
+
case "band_lookup_peers":
|
|
4655
5226
|
return this.lookupPeers(
|
|
4656
5227
|
typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
4657
5228
|
typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0
|
|
4658
5229
|
);
|
|
4659
|
-
case "
|
|
5230
|
+
case "band_list_contacts":
|
|
4660
5231
|
return this.listContacts({
|
|
4661
5232
|
page: typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
4662
5233
|
pageSize: typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0
|
|
4663
5234
|
});
|
|
4664
|
-
case "
|
|
5235
|
+
case "band_add_contact":
|
|
4665
5236
|
return this.addContact({
|
|
4666
5237
|
handle: String(toolArgs.handle ?? ""),
|
|
4667
5238
|
...typeof toolArgs.message === "string" ? { message: toolArgs.message } : {}
|
|
4668
5239
|
});
|
|
4669
|
-
case "
|
|
5240
|
+
case "band_remove_contact":
|
|
4670
5241
|
if (typeof toolArgs.contact_id === "string") {
|
|
4671
5242
|
return this.removeContact({ target: "contactId", contactId: toolArgs.contact_id });
|
|
4672
5243
|
}
|
|
4673
5244
|
return this.removeContact({ target: "handle", handle: String(toolArgs.handle ?? "") });
|
|
4674
|
-
case "
|
|
5245
|
+
case "band_list_contact_requests":
|
|
4675
5246
|
return this.listContactRequests({
|
|
4676
5247
|
page: typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
4677
5248
|
pageSize: typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0,
|
|
4678
5249
|
sentStatus: typeof toolArgs.sent_status === "string" ? toolArgs.sent_status : void 0
|
|
4679
5250
|
});
|
|
4680
|
-
case "
|
|
5251
|
+
case "band_respond_contact_request":
|
|
4681
5252
|
if (typeof toolArgs.request_id === "string") {
|
|
4682
5253
|
return this.respondContactRequest({
|
|
4683
5254
|
action: String(toolArgs.action ?? "approve"),
|
|
@@ -4690,15 +5261,15 @@ var ContactCallbackTools = class {
|
|
|
4690
5261
|
target: "handle",
|
|
4691
5262
|
handle: String(toolArgs.handle ?? "")
|
|
4692
5263
|
});
|
|
4693
|
-
case "
|
|
5264
|
+
case "band_list_memories":
|
|
4694
5265
|
return this.listMemories(toolArgs);
|
|
4695
|
-
case "
|
|
5266
|
+
case "band_store_memory":
|
|
4696
5267
|
return this.storeMemory(toolArgs);
|
|
4697
|
-
case "
|
|
5268
|
+
case "band_get_memory":
|
|
4698
5269
|
return this.getMemory(String(toolArgs.memory_id ?? ""));
|
|
4699
|
-
case "
|
|
5270
|
+
case "band_supersede_memory":
|
|
4700
5271
|
return this.supersedeMemory(String(toolArgs.memory_id ?? ""));
|
|
4701
|
-
case "
|
|
5272
|
+
case "band_archive_memory":
|
|
4702
5273
|
return this.archiveMemory(String(toolArgs.memory_id ?? ""));
|
|
4703
5274
|
default:
|
|
4704
5275
|
throw new UnsupportedFeatureError(`Unsupported tool call for contact callback: ${toolName}`);
|
|
@@ -4712,14 +5283,14 @@ var HUB_ROOM_SYSTEM_PROMPT = `## OVERRIDE: Contact Management Mode
|
|
|
4712
5283
|
|
|
4713
5284
|
This is your CONTACTS HUB - a dedicated room for managing contact requests.
|
|
4714
5285
|
|
|
4715
|
-
**IMPORTANT: Do NOT delegate or add participants here.** You handle contact events DIRECTLY using the contact tools below. Do NOT call
|
|
5286
|
+
**IMPORTANT: Do NOT delegate or add participants here.** You handle contact events DIRECTLY using the contact tools below. Do NOT call band_lookup_peers() or band_add_participant() in this room.
|
|
4716
5287
|
|
|
4717
5288
|
## Your Role
|
|
4718
5289
|
|
|
4719
5290
|
1. **Review incoming contact requests** - When you see a [Contact Request] message, evaluate it
|
|
4720
5291
|
2. **Take action** - Use the contact tools to respond:
|
|
4721
|
-
- \`
|
|
4722
|
-
- \`
|
|
5292
|
+
- \`band_respond_contact_request(action="approve", request_id="...")\` to accept
|
|
5293
|
+
- \`band_respond_contact_request(action="reject", request_id="...")\` to decline
|
|
4723
5294
|
3. **Report your decision** - Send a thought event explaining what you did
|
|
4724
5295
|
|
|
4725
5296
|
## Example
|
|
@@ -4728,14 +5299,14 @@ This is your CONTACTS HUB - a dedicated room for managing contact requests.
|
|
|
4728
5299
|
Request ID: abc-123
|
|
4729
5300
|
|
|
4730
5301
|
Your response:
|
|
4731
|
-
1.
|
|
4732
|
-
2.
|
|
4733
|
-
3.
|
|
5302
|
+
1. band_send_event("Received contact request from Alice. Approving.", message_type="thought")
|
|
5303
|
+
2. band_respond_contact_request(action="approve", request_id="abc-123")
|
|
5304
|
+
3. band_send_event("Approved contact request from Alice (@alice)", message_type="thought")
|
|
4734
5305
|
|
|
4735
5306
|
## Contact Tools (use these, NOT participant tools)
|
|
4736
|
-
- \`
|
|
4737
|
-
- \`
|
|
4738
|
-
- \`
|
|
5307
|
+
- \`band_respond_contact_request(action, request_id)\` - Approve/reject requests
|
|
5308
|
+
- \`band_list_contact_requests()\` - List pending requests
|
|
5309
|
+
- \`band_list_contacts()\` - List current contacts`;
|
|
4739
5310
|
var ContactEventHandlerError = class extends Error {
|
|
4740
5311
|
retryable;
|
|
4741
5312
|
stage;
|
|
@@ -5063,6 +5634,8 @@ function normalizeHandle(handle) {
|
|
|
5063
5634
|
}
|
|
5064
5635
|
|
|
5065
5636
|
// src/runtime/PlatformRuntime.ts
|
|
5637
|
+
var MAX_MESSAGE_RETRIES = 4294967295;
|
|
5638
|
+
var isValidRetryCount = (value) => Number.isInteger(value) && value >= 0 && value <= MAX_MESSAGE_RETRIES;
|
|
5066
5639
|
var PlatformRuntime = class {
|
|
5067
5640
|
_agentId;
|
|
5068
5641
|
_apiKey;
|
|
@@ -5099,6 +5672,12 @@ var PlatformRuntime = class {
|
|
|
5099
5672
|
"apiKey is required and must be a non-empty string. Use loadAgentConfig() to load credentials from agent_config.yaml."
|
|
5100
5673
|
);
|
|
5101
5674
|
}
|
|
5675
|
+
const maxMessageRetries = options.sessionConfig?.maxMessageRetries;
|
|
5676
|
+
if (maxMessageRetries !== void 0 && !isValidRetryCount(maxMessageRetries)) {
|
|
5677
|
+
throw new ValidationError(
|
|
5678
|
+
`sessionConfig.maxMessageRetries must be an integer between 0 and ${MAX_MESSAGE_RETRIES}, got ${maxMessageRetries}.`
|
|
5679
|
+
);
|
|
5680
|
+
}
|
|
5102
5681
|
this._agentId = options.agentId;
|
|
5103
5682
|
this._apiKey = options.apiKey;
|
|
5104
5683
|
this._wsUrl = options.wsUrl;
|
|
@@ -5151,12 +5730,13 @@ var PlatformRuntime = class {
|
|
|
5151
5730
|
}
|
|
5152
5731
|
async doInitialize() {
|
|
5153
5732
|
if (!this.linkInstance) {
|
|
5154
|
-
this.linkInstance = new
|
|
5733
|
+
this.linkInstance = new BandLink({
|
|
5155
5734
|
...this.linkOptions,
|
|
5156
5735
|
agentId: this._agentId,
|
|
5157
5736
|
apiKey: this._apiKey,
|
|
5158
5737
|
wsUrl: this._wsUrl,
|
|
5159
|
-
restUrl: this._restUrl
|
|
5738
|
+
restUrl: this._restUrl,
|
|
5739
|
+
logger: this.logger
|
|
5160
5740
|
});
|
|
5161
5741
|
}
|
|
5162
5742
|
if (this.configuredIdentity) {
|
|
@@ -5485,7 +6065,21 @@ var import_node_fs = require("fs");
|
|
|
5485
6065
|
var import_js_yaml = __toESM(require("js-yaml"), 1);
|
|
5486
6066
|
init_errors();
|
|
5487
6067
|
var DEFAULT_CONFIG_PATH = "./agent_config.yaml";
|
|
5488
|
-
var DEFAULT_ENV_PREFIX = "
|
|
6068
|
+
var DEFAULT_ENV_PREFIX = "BAND_";
|
|
6069
|
+
var LEGACY_ENV_PREFIX = "THENVOI_";
|
|
6070
|
+
var _warnedLegacyEnvVars = /* @__PURE__ */ new Set();
|
|
6071
|
+
function readBandFirstEnv(env, field) {
|
|
6072
|
+
const bandVar = `${DEFAULT_ENV_PREFIX}${field}`;
|
|
6073
|
+
const bandValue = env[bandVar];
|
|
6074
|
+
if (bandValue !== void 0) return bandValue;
|
|
6075
|
+
const legacyVar = `${LEGACY_ENV_PREFIX}${field}`;
|
|
6076
|
+
const legacyValue = env[legacyVar];
|
|
6077
|
+
if (legacyValue !== void 0 && !_warnedLegacyEnvVars.has(legacyVar)) {
|
|
6078
|
+
_warnedLegacyEnvVars.add(legacyVar);
|
|
6079
|
+
console.warn(`[band] ${legacyVar} is deprecated; use ${bandVar} instead`);
|
|
6080
|
+
}
|
|
6081
|
+
return legacyValue;
|
|
6082
|
+
}
|
|
5489
6083
|
var REQUIRED_FIELDS = ["agent_id", "api_key"];
|
|
5490
6084
|
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype", "toString", "valueOf"]);
|
|
5491
6085
|
function toSnakeCase(key) {
|
|
@@ -5569,19 +6163,32 @@ function loadAgentConfig(agentKey, configPath) {
|
|
|
5569
6163
|
}
|
|
5570
6164
|
function loadAgentConfigFromEnv(options) {
|
|
5571
6165
|
const env = options?.env ?? process.env;
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
6166
|
+
let section;
|
|
6167
|
+
let requiredHint;
|
|
6168
|
+
if (options?.prefix === void 0) {
|
|
6169
|
+
section = normalizeKeys({
|
|
6170
|
+
agent_id: readBandFirstEnv(env, "AGENT_ID"),
|
|
6171
|
+
api_key: readBandFirstEnv(env, "API_KEY"),
|
|
6172
|
+
ws_url: readBandFirstEnv(env, "WS_URL"),
|
|
6173
|
+
rest_url: readBandFirstEnv(env, "REST_URL")
|
|
6174
|
+
});
|
|
6175
|
+
requiredHint = `${DEFAULT_ENV_PREFIX}AGENT_ID and ${DEFAULT_ENV_PREFIX}API_KEY (legacy ${LEGACY_ENV_PREFIX}* still accepted)`;
|
|
6176
|
+
} else {
|
|
6177
|
+
const prefix = options.prefix === "" || options.prefix.endsWith("_") ? options.prefix : `${options.prefix}_`;
|
|
6178
|
+
section = normalizeKeys({
|
|
6179
|
+
agent_id: env[`${prefix}AGENT_ID`],
|
|
6180
|
+
api_key: env[`${prefix}API_KEY`],
|
|
6181
|
+
ws_url: env[`${prefix}WS_URL`],
|
|
6182
|
+
rest_url: env[`${prefix}REST_URL`]
|
|
6183
|
+
});
|
|
6184
|
+
requiredHint = `${prefix}AGENT_ID and ${prefix}API_KEY`;
|
|
6185
|
+
}
|
|
5579
6186
|
try {
|
|
5580
|
-
return toAgentConfigResult(section, `environment variables (${
|
|
6187
|
+
return toAgentConfigResult(section, `environment variables (${requiredHint})`);
|
|
5581
6188
|
} catch (error) {
|
|
5582
6189
|
if (error instanceof ValidationError) {
|
|
5583
6190
|
throw new ValidationError(
|
|
5584
|
-
`${error.message}. Set ${
|
|
6191
|
+
`${error.message}. Set ${requiredHint}, or use loadAgentConfig() for agent_config.yaml.`
|
|
5585
6192
|
);
|
|
5586
6193
|
}
|
|
5587
6194
|
throw error;
|
|
@@ -5659,26 +6266,25 @@ var GenericAdapter = class extends SimpleAdapter {
|
|
|
5659
6266
|
// src/adapters/codex/CodexAdapter.ts
|
|
5660
6267
|
init_protocols();
|
|
5661
6268
|
|
|
5662
|
-
// src/runtime/prompts.ts
|
|
5663
|
-
var
|
|
6269
|
+
// src/runtime/prompts/base.ts
|
|
6270
|
+
var ENVIRONMENT_SECTION = `
|
|
5664
6271
|
## Environment
|
|
5665
6272
|
|
|
5666
6273
|
Multi-participant chat. Messages show sender: [Name]: content.
|
|
5667
6274
|
Messages prefixed with [System]: are platform updates (participant changes, contact updates, etc.) \u2014 not messages from users.
|
|
5668
|
-
Use \`
|
|
5669
|
-
Mentions use handles: @<username> for users, @<username>/<agent-name> for agents
|
|
5670
|
-
|
|
5671
|
-
## CRITICAL: Delegate When You Cannot Help Directly
|
|
6275
|
+
Use \`band_send_message(content, mentions)\` to respond. Plain text output is not delivered.
|
|
6276
|
+
Mentions use handles: @<username> for users, @<username>/<agent-name> for agents.`;
|
|
6277
|
+
var MULTI_AGENT_RULES_SECTION = `## CRITICAL: Delegate When You Cannot Help Directly
|
|
5672
6278
|
|
|
5673
6279
|
You have NO internet access and NO real-time data. When asked about weather, news, stock prices,
|
|
5674
6280
|
or any current information you cannot answer directly:
|
|
5675
6281
|
|
|
5676
|
-
1. Call \`
|
|
5677
|
-
2. If a relevant agent exists, call \`
|
|
5678
|
-
3. Ask that agent using \`
|
|
6282
|
+
1. Call \`band_lookup_peers()\` to find available specialized agents
|
|
6283
|
+
2. If a relevant agent exists, call \`band_add_participant(name)\` to add them
|
|
6284
|
+
3. Ask that agent using \`band_send_message(question, mentions=[agent_handle])\`
|
|
5679
6285
|
4. Wait for their response and relay it back to the user
|
|
5680
6286
|
|
|
5681
|
-
NEVER say "I can't do that" without first checking if another agent can help via \`
|
|
6287
|
+
NEVER say "I can't do that" without first checking if another agent can help via \`band_lookup_peers()\`.
|
|
5682
6288
|
|
|
5683
6289
|
## CRITICAL: Do NOT Remove Agents Automatically
|
|
5684
6290
|
|
|
@@ -5694,48 +6300,113 @@ Only remove agents if the user explicitly requests it.
|
|
|
5694
6300
|
When someone asks you to get information from another agent:
|
|
5695
6301
|
1. Ask the other agent for the information
|
|
5696
6302
|
2. When you receive the response, IMMEDIATELY relay it back to the ORIGINAL REQUESTER
|
|
5697
|
-
3. Do NOT just thank the helper agent - the requester is waiting for their answer
|
|
5698
|
-
|
|
5699
|
-
## IMPORTANT: Always Share Your Thinking
|
|
6303
|
+
3. Do NOT just thank the helper agent - the requester is waiting for their answer!`;
|
|
6304
|
+
var THINKING_SECTION = `## IMPORTANT: Always Share Your Thinking
|
|
5700
6305
|
|
|
5701
|
-
You MUST call \`
|
|
5702
|
-
This is required so users can see your reasoning process
|
|
5703
|
-
|
|
5704
|
-
## Examples
|
|
6306
|
+
You MUST call \`band_send_event(content, message_type="thought")\` BEFORE every action.
|
|
6307
|
+
This is required so users can see your reasoning process.`;
|
|
6308
|
+
var EXAMPLES_SECTION = `## Examples
|
|
5705
6309
|
|
|
5706
6310
|
### Simple question - answer directly
|
|
5707
6311
|
[John Doe]: What's 2+2?
|
|
5708
|
-
->
|
|
5709
|
-
->
|
|
6312
|
+
-> band_send_event("Simple arithmetic, answering directly.", message_type="thought")
|
|
6313
|
+
-> band_send_message("4", mentions=["@john"])
|
|
5710
6314
|
|
|
5711
6315
|
### User asks about weather (you cannot answer directly)
|
|
5712
6316
|
[John Doe]: What's the weather in Tokyo?
|
|
5713
|
-
->
|
|
5714
|
-
->
|
|
5715
|
-
->
|
|
5716
|
-
->
|
|
5717
|
-
->
|
|
6317
|
+
-> band_send_event("I can't check weather directly. Looking for a Weather Agent.", message_type="thought")
|
|
6318
|
+
-> band_lookup_peers()
|
|
6319
|
+
-> band_send_event("Found Weather Agent. Adding to room.", message_type="thought")
|
|
6320
|
+
-> band_add_participant("Weather Agent")
|
|
6321
|
+
-> band_send_message("What's the weather in Tokyo?", mentions=["@john/weather-agent"])
|
|
5718
6322
|
|
|
5719
6323
|
[Weather Agent]: Tokyo is 15\xB0C and cloudy.
|
|
5720
|
-
->
|
|
5721
|
-
->
|
|
6324
|
+
-> band_send_event("Got weather response. Relaying back to John Doe.", message_type="thought")
|
|
6325
|
+
-> band_send_message("The weather in Tokyo is 15\xB0C and cloudy.", mentions=["@john"])
|
|
5722
6326
|
|
|
5723
6327
|
### No suitable agent available
|
|
5724
6328
|
[John Doe]: What's the stock price of AAPL?
|
|
5725
|
-
->
|
|
5726
|
-
->
|
|
5727
|
-
->
|
|
5728
|
-
->
|
|
6329
|
+
-> band_send_event("I can't check stock prices. Looking for a Stock Agent.", message_type="thought")
|
|
6330
|
+
-> band_lookup_peers()
|
|
6331
|
+
-> band_send_event("No stock agent available. Must inform user.", message_type="thought")
|
|
6332
|
+
-> band_send_message("I don't have access to stock prices, and there's no specialized agent available to help with that.", mentions=["@john"])
|
|
5729
6333
|
|
|
5730
6334
|
### Follow-up question in same conversation
|
|
5731
6335
|
[John Doe]: What about London?
|
|
5732
|
-
->
|
|
5733
|
-
->
|
|
6336
|
+
-> band_send_event("Follow-up weather question. Asking Weather Agent.", message_type="thought")
|
|
6337
|
+
-> band_send_message("What's the weather in London?", mentions=["@john/weather-agent"])
|
|
5734
6338
|
|
|
5735
6339
|
[Weather Agent]: London is 8\xB0C and rainy.
|
|
5736
|
-
->
|
|
5737
|
-
->
|
|
5738
|
-
|
|
6340
|
+
-> band_send_event("Got London weather. Relaying to John Doe.", message_type="thought")
|
|
6341
|
+
-> band_send_message("London is 8\xB0C and rainy.", mentions=["@john"])`;
|
|
6342
|
+
var BASE_INSTRUCTIONS = [
|
|
6343
|
+
ENVIRONMENT_SECTION,
|
|
6344
|
+
MULTI_AGENT_RULES_SECTION,
|
|
6345
|
+
THINKING_SECTION,
|
|
6346
|
+
EXAMPLES_SECTION
|
|
6347
|
+
].join("\n\n") + "\n";
|
|
6348
|
+
|
|
6349
|
+
// src/runtime/prompts/memory.ts
|
|
6350
|
+
init_memory();
|
|
6351
|
+
init_schemas();
|
|
6352
|
+
var MEMORY_INTRO = `## Memory Tools
|
|
6353
|
+
|
|
6354
|
+
You have access to memory tools for storing and retrieving information
|
|
6355
|
+
across conversations. Use \`band_store_memory\` to persist important
|
|
6356
|
+
information and \`band_list_memories\` / \`band_get_memory\` to recall it.
|
|
6357
|
+
Use \`band_supersede_memory\` to mark outdated memories and
|
|
6358
|
+
\`band_archive_memory\` to hide memories that should be preserved.`;
|
|
6359
|
+
function longTermPattern(label, type, segment, scope) {
|
|
6360
|
+
return {
|
|
6361
|
+
label,
|
|
6362
|
+
system: MEMORY_SYSTEM.long_term,
|
|
6363
|
+
type,
|
|
6364
|
+
segment,
|
|
6365
|
+
scope
|
|
6366
|
+
};
|
|
6367
|
+
}
|
|
6368
|
+
var COMMON_MEMORY_PATTERNS = [
|
|
6369
|
+
longTermPattern("Facts learned about a specific agent/entity", MEMORY_TYPE.semantic, MEMORY_SEGMENT.agent, MEMORY_STORE_SCOPE.subject),
|
|
6370
|
+
longTermPattern("Events involving a specific person/agent", MEMORY_TYPE.episodic, MEMORY_SEGMENT.agent, MEMORY_STORE_SCOPE.subject),
|
|
6371
|
+
longTermPattern("A user's preferences or profile info", MEMORY_TYPE.semantic, MEMORY_SEGMENT.user, MEMORY_STORE_SCOPE.subject),
|
|
6372
|
+
longTermPattern("Org-wide knowledge or how to perform a task", MEMORY_TYPE.procedural, MEMORY_SEGMENT.tool, MEMORY_STORE_SCOPE.organization)
|
|
6373
|
+
];
|
|
6374
|
+
function renderMemoryPattern(pattern) {
|
|
6375
|
+
return `- ${pattern.label}: \`system="${pattern.system}"\`, \`type="${pattern.type}"\`, \`segment="${pattern.segment}"\`, \`scope="${pattern.scope}"\``;
|
|
6376
|
+
}
|
|
6377
|
+
var MEMORY_COMMON_PATTERNS = [
|
|
6378
|
+
"Common patterns:",
|
|
6379
|
+
...COMMON_MEMORY_PATTERNS.map(renderMemoryPattern)
|
|
6380
|
+
].join("\n");
|
|
6381
|
+
var MEMORY_SCOPE_GUIDANCE = `Prefer \`scope="${MEMORY_STORE_SCOPE.subject}"\` whenever the memory is about a specific person or agent, so it
|
|
6382
|
+
stays attached to that subject rather than leaking org-wide. Storing with \`scope="${MEMORY_STORE_SCOPE.subject}"\` requires a
|
|
6383
|
+
real \`subject_id\` UUID, so resolve it first via \`band_lookup_peers\` or the participant list.
|
|
6384
|
+
Reserve \`scope="${MEMORY_STORE_SCOPE.organization}"\` for knowledge that is genuinely shared across the whole organization and
|
|
6385
|
+
is not about any one subject.`;
|
|
6386
|
+
function quoteChoices(values) {
|
|
6387
|
+
return values.map((value) => `\`"${value}"\``).join(" | ");
|
|
6388
|
+
}
|
|
6389
|
+
function memoryTypeLines() {
|
|
6390
|
+
return Object.entries(MEMORY_SYSTEM_TYPES).map(([system, types]) => ` - ${system}: ${quoteChoices(types)}`).join("\n");
|
|
6391
|
+
}
|
|
6392
|
+
function buildMemorySection() {
|
|
6393
|
+
const storeMemoryProps = TOOL_MODELS.band_store_memory.properties;
|
|
6394
|
+
const systems = storeMemoryProps.system.enum;
|
|
6395
|
+
const segments = storeMemoryProps.segment.enum;
|
|
6396
|
+
const scopes = storeMemoryProps.scope.enum;
|
|
6397
|
+
const fieldRules = `When calling \`band_store_memory\`, the \`system\`, \`type\`, \`segment\`, and \`scope\` fields
|
|
6398
|
+
must use these exact values (case-sensitive):
|
|
6399
|
+
|
|
6400
|
+
- **system**: ${quoteChoices(systems)}
|
|
6401
|
+
- **type** (must match the chosen system):
|
|
6402
|
+
${memoryTypeLines()}
|
|
6403
|
+
- **segment**: ${quoteChoices(segments)}
|
|
6404
|
+
- **scope**: ${quoteChoices(scopes)}`;
|
|
6405
|
+
return [MEMORY_INTRO, fieldRules, MEMORY_COMMON_PATTERNS, MEMORY_SCOPE_GUIDANCE].join("\n\n");
|
|
6406
|
+
}
|
|
6407
|
+
var MEMORY_SECTION = buildMemorySection();
|
|
6408
|
+
|
|
6409
|
+
// src/runtime/prompts/templates.ts
|
|
5739
6410
|
var TEMPLATES = {
|
|
5740
6411
|
default: `You are {agent_name}, {agent_description}.
|
|
5741
6412
|
|
|
@@ -5754,11 +6425,20 @@ ${customSection}`.trim();
|
|
|
5754
6425
|
}
|
|
5755
6426
|
const template = options?.template ?? "default";
|
|
5756
6427
|
const templateString = TEMPLATES[template] ?? TEMPLATES.default;
|
|
5757
|
-
|
|
6428
|
+
const parts = [
|
|
6429
|
+
templateString.replaceAll("{agent_name}", agentName).replaceAll("{agent_description}", agentDescription).replaceAll("{custom_section}", customSection)
|
|
6430
|
+
];
|
|
6431
|
+
if (options?.capabilities?.memory) {
|
|
6432
|
+
parts.push(MEMORY_SECTION);
|
|
6433
|
+
}
|
|
6434
|
+
return parts.join("\n\n");
|
|
5758
6435
|
}
|
|
5759
6436
|
|
|
6437
|
+
// src/adapters/codex/CodexAdapter.ts
|
|
6438
|
+
init_schemas();
|
|
6439
|
+
|
|
5760
6440
|
// src/runtime/tools/customTools.ts
|
|
5761
|
-
var
|
|
6441
|
+
var import_zod3 = require("zod");
|
|
5762
6442
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
5763
6443
|
var CustomToolDefinitionError = class extends Error {
|
|
5764
6444
|
constructor(message) {
|
|
@@ -6180,8 +6860,8 @@ var CODEX_WEB_SEARCH_MODES = ["disabled", "cached", "live"];
|
|
|
6180
6860
|
var CODEX_REASONING_SUMMARIES = ["auto", "concise", "detailed", "none"];
|
|
6181
6861
|
var CODEX_REASONING_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
6182
6862
|
var SILENT_REPORTING_TOOLS = /* @__PURE__ */ new Set([
|
|
6183
|
-
|
|
6184
|
-
|
|
6863
|
+
SEND_MESSAGE_TOOL_NAME,
|
|
6864
|
+
SEND_EVENT_TOOL_NAME
|
|
6185
6865
|
]);
|
|
6186
6866
|
var CodexAdapter = class extends SimpleAdapter {
|
|
6187
6867
|
baseConfig;
|
|
@@ -6211,8 +6891,8 @@ var CodexAdapter = class extends SimpleAdapter {
|
|
|
6211
6891
|
includeBaseInstructions: true,
|
|
6212
6892
|
experimentalApi: true,
|
|
6213
6893
|
fallbackSendAgentText: true,
|
|
6214
|
-
clientName: "
|
|
6215
|
-
clientTitle: "
|
|
6894
|
+
clientName: "band_codex_adapter",
|
|
6895
|
+
clientTitle: "Band Codex Adapter",
|
|
6216
6896
|
clientVersion: "0.1.0",
|
|
6217
6897
|
turnTimeoutMs: 18e4,
|
|
6218
6898
|
...options?.config
|
|
@@ -6453,7 +7133,8 @@ var CodexAdapter = class extends SimpleAdapter {
|
|
|
6453
7133
|
agentName: this.agentName,
|
|
6454
7134
|
agentDescription: this.agentDescription,
|
|
6455
7135
|
customSection,
|
|
6456
|
-
includeBaseInstructions: this.baseConfig.includeBaseInstructions ?? true
|
|
7136
|
+
includeBaseInstructions: this.baseConfig.includeBaseInstructions ?? true,
|
|
7137
|
+
capabilities: { memory: this.includeMemoryTools }
|
|
6457
7138
|
}).trim();
|
|
6458
7139
|
this.systemPrompt = prompt.length > 0 ? prompt : null;
|
|
6459
7140
|
}
|
|
@@ -6477,8 +7158,8 @@ var CodexAdapter = class extends SimpleAdapter {
|
|
|
6477
7158
|
await client.connect();
|
|
6478
7159
|
await client.initialize({
|
|
6479
7160
|
clientInfo: {
|
|
6480
|
-
name: this.baseConfig.clientName ?? "
|
|
6481
|
-
title: this.baseConfig.clientTitle ?? "
|
|
7161
|
+
name: this.baseConfig.clientName ?? "band_codex_adapter",
|
|
7162
|
+
title: this.baseConfig.clientTitle ?? "Band Codex Adapter",
|
|
6482
7163
|
version: this.baseConfig.clientVersion ?? "0.1.0"
|
|
6483
7164
|
},
|
|
6484
7165
|
capabilities: {
|
|
@@ -6751,7 +7432,7 @@ var CodexAdapter = class extends SimpleAdapter {
|
|
|
6751
7432
|
tool_call_id: callId
|
|
6752
7433
|
}), "tool_result");
|
|
6753
7434
|
}
|
|
6754
|
-
return !isError && toolName ===
|
|
7435
|
+
return !isError && toolName === SEND_MESSAGE_TOOL_NAME;
|
|
6755
7436
|
} catch (error) {
|
|
6756
7437
|
const output = {
|
|
6757
7438
|
ok: false,
|
|
@@ -8476,7 +9157,7 @@ var GoogleADKHistoryConverter = class {
|
|
|
8476
9157
|
};
|
|
8477
9158
|
|
|
8478
9159
|
// src/adapters/google-adk/GoogleADKAdapter.ts
|
|
8479
|
-
var APP_NAME = "
|
|
9160
|
+
var APP_NAME = "band";
|
|
8480
9161
|
var DEFAULT_MAX_HISTORY_MESSAGES = 50;
|
|
8481
9162
|
var DEFAULT_MAX_TRANSCRIPT_CHARS = 1e5;
|
|
8482
9163
|
var MAX_TOOL_OUTPUT_PREVIEW = 200;
|
|
@@ -8576,7 +9257,8 @@ var GoogleADKAdapter = class extends SimpleAdapter {
|
|
|
8576
9257
|
this.systemPrompt = this.systemPromptOverride ?? renderSystemPrompt({
|
|
8577
9258
|
agentName,
|
|
8578
9259
|
agentDescription,
|
|
8579
|
-
customSection: this.customSection
|
|
9260
|
+
customSection: this.customSection,
|
|
9261
|
+
capabilities: { memory: this.enableMemoryTools }
|
|
8580
9262
|
});
|
|
8581
9263
|
}
|
|
8582
9264
|
async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
|
|
@@ -8649,7 +9331,7 @@ var GoogleADKAdapter = class extends SimpleAdapter {
|
|
|
8649
9331
|
}
|
|
8650
9332
|
buildAgent(sdk, tools) {
|
|
8651
9333
|
return sdk.createAgent({
|
|
8652
|
-
name: this.agentName || "
|
|
9334
|
+
name: this.agentName || "band_agent",
|
|
8653
9335
|
model: this.model,
|
|
8654
9336
|
instruction: this.systemPrompt,
|
|
8655
9337
|
tools: this.buildTools(sdk, tools)
|
|
@@ -8816,7 +9498,8 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8816
9498
|
this.renderedSystemPrompt = this.systemPromptOverride ?? renderSystemPrompt({
|
|
8817
9499
|
agentName,
|
|
8818
9500
|
agentDescription,
|
|
8819
|
-
customSection: this.customSection
|
|
9501
|
+
customSection: this.customSection,
|
|
9502
|
+
capabilities: { memory: this.includeMemoryTools }
|
|
8820
9503
|
});
|
|
8821
9504
|
}
|
|
8822
9505
|
async onMessage(message, tools, history, participantsMessage, contactsMessage, context) {
|
|
@@ -8835,14 +9518,17 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8835
9518
|
];
|
|
8836
9519
|
}
|
|
8837
9520
|
const graph = await this.resolveGraph(sdk, langGraphTools);
|
|
8838
|
-
const
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
context.
|
|
8844
|
-
|
|
8845
|
-
|
|
9521
|
+
const usesCheckpointer = Boolean(this.checkpointer);
|
|
9522
|
+
const isFirstBootstrap = context.isSessionBootstrap && !this.bootstrappedRooms.has(context.roomId);
|
|
9523
|
+
const replayHistory = !usesCheckpointer || isFirstBootstrap;
|
|
9524
|
+
const includeSystemPrompt = this.usesCustomGraph && (!usesCheckpointer || isFirstBootstrap);
|
|
9525
|
+
if (context.isSessionBootstrap) {
|
|
9526
|
+
this.bootstrappedRooms.add(context.roomId);
|
|
9527
|
+
}
|
|
9528
|
+
const messages = this.buildMessages(history, message, participantsMessage, contactsMessage, {
|
|
9529
|
+
replayHistory,
|
|
9530
|
+
includeSystemPrompt
|
|
9531
|
+
});
|
|
8846
9532
|
const input = { messages };
|
|
8847
9533
|
const graphConfig = {
|
|
8848
9534
|
configurable: {
|
|
@@ -8869,6 +9555,10 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8869
9555
|
async onCleanup(roomId) {
|
|
8870
9556
|
this.bootstrappedRooms.delete(roomId);
|
|
8871
9557
|
}
|
|
9558
|
+
/** A caller-supplied graph rather than the built-in createReactAgent. */
|
|
9559
|
+
get usesCustomGraph() {
|
|
9560
|
+
return Boolean(this.graph || this.graphFactory);
|
|
9561
|
+
}
|
|
8872
9562
|
resolveGraph(sdk, langGraphTools) {
|
|
8873
9563
|
if (this.graphFactory) {
|
|
8874
9564
|
return Promise.resolve(this.graphFactory(langGraphTools));
|
|
@@ -8889,14 +9579,13 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8889
9579
|
prompt: this.renderedSystemPrompt
|
|
8890
9580
|
}));
|
|
8891
9581
|
}
|
|
8892
|
-
buildMessages(history, message, participantsMessage, contactsMessage,
|
|
9582
|
+
buildMessages(history, message, participantsMessage, contactsMessage, options) {
|
|
8893
9583
|
const messages = [];
|
|
8894
|
-
if (
|
|
9584
|
+
if (options.includeSystemPrompt) {
|
|
8895
9585
|
messages.push(["system", this.renderedSystemPrompt]);
|
|
8896
|
-
this.bootstrappedRooms.add(roomId);
|
|
8897
9586
|
}
|
|
8898
|
-
if (
|
|
8899
|
-
const historical = history.raw.slice(-this.maxHistoryMessages);
|
|
9587
|
+
if (options.replayHistory && history.length > 0) {
|
|
9588
|
+
const historical = history.raw.filter((item) => item.id !== message.id).slice(-this.maxHistoryMessages);
|
|
8900
9589
|
for (const item of historical) {
|
|
8901
9590
|
const role = String(item.sender_type ?? "") === "Agent" ? "assistant" : "user";
|
|
8902
9591
|
const content = String(item.content ?? "");
|
|
@@ -8915,7 +9604,7 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8915
9604
|
return messages;
|
|
8916
9605
|
}
|
|
8917
9606
|
async forwardStreamEvents(graph, input, config, tools) {
|
|
8918
|
-
const stream = graph.streamEvents?.(input, config,
|
|
9607
|
+
const stream = graph.streamEvents?.(input, { ...config, version: "v2" });
|
|
8919
9608
|
if (!stream) {
|
|
8920
9609
|
return null;
|
|
8921
9610
|
}
|
|
@@ -8942,6 +9631,10 @@ var LangGraphAdapter = class extends SimpleAdapter {
|
|
|
8942
9631
|
);
|
|
8943
9632
|
}
|
|
8944
9633
|
if (eventType === "on_chain_end") {
|
|
9634
|
+
const chainName = String(data.name ?? "");
|
|
9635
|
+
if (!this.usesCustomGraph && chainName !== "LangGraph" && chainName !== "agent") {
|
|
9636
|
+
continue;
|
|
9637
|
+
}
|
|
8945
9638
|
const output = asOptionalRecord(data.data) ?? {};
|
|
8946
9639
|
const text = extractAssistantText(output.output);
|
|
8947
9640
|
if (text) {
|
|
@@ -9003,18 +9696,25 @@ function stringifyToolResult2(value, logger, toolName) {
|
|
|
9003
9696
|
});
|
|
9004
9697
|
}
|
|
9005
9698
|
function extractAssistantText(result) {
|
|
9006
|
-
if (typeof result === "string"
|
|
9007
|
-
|
|
9699
|
+
if (typeof result === "string") {
|
|
9700
|
+
const trimmed = result.trim();
|
|
9701
|
+
return trimmed.length > 0 && !isInternalLangGraphMarker(trimmed) ? trimmed : null;
|
|
9008
9702
|
}
|
|
9009
9703
|
const record = asOptionalRecord(result) ?? {};
|
|
9704
|
+
if (isLangChainAssistantMessage(record)) {
|
|
9705
|
+
const text = asLangChainMessageContent(record);
|
|
9706
|
+
if (text && !isInternalLangGraphMarker(text)) {
|
|
9707
|
+
return text;
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9010
9710
|
const directContent = asMessageContent(record.content);
|
|
9011
|
-
if (directContent) {
|
|
9711
|
+
if (directContent && !isInternalLangGraphMarker(directContent)) {
|
|
9012
9712
|
return directContent;
|
|
9013
9713
|
}
|
|
9014
9714
|
const messages = Array.isArray(record.messages) ? record.messages : [];
|
|
9015
9715
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
9016
9716
|
const text = asMessageText(messages[index]);
|
|
9017
|
-
if (text) {
|
|
9717
|
+
if (text && !isInternalLangGraphMarker(text)) {
|
|
9018
9718
|
return text;
|
|
9019
9719
|
}
|
|
9020
9720
|
}
|
|
@@ -9031,12 +9731,40 @@ function asMessageText(value) {
|
|
|
9031
9731
|
if (!record) {
|
|
9032
9732
|
return null;
|
|
9033
9733
|
}
|
|
9734
|
+
if (isLangChainAssistantMessage(record)) {
|
|
9735
|
+
return asLangChainMessageContent(record);
|
|
9736
|
+
}
|
|
9034
9737
|
const role = String(record.role ?? "");
|
|
9035
9738
|
if (role !== "assistant") {
|
|
9036
9739
|
return null;
|
|
9037
9740
|
}
|
|
9038
9741
|
return asMessageContent(record.content);
|
|
9039
9742
|
}
|
|
9743
|
+
function isLangChainAssistantMessage(record) {
|
|
9744
|
+
const id = record.id;
|
|
9745
|
+
if (Array.isArray(id)) {
|
|
9746
|
+
const typeName = String(id[id.length - 1] ?? "");
|
|
9747
|
+
if (typeName === "AIMessage" || typeName === "AIMessageChunk") {
|
|
9748
|
+
return true;
|
|
9749
|
+
}
|
|
9750
|
+
}
|
|
9751
|
+
const getType = record.getType;
|
|
9752
|
+
if (typeof getType === "function") {
|
|
9753
|
+
try {
|
|
9754
|
+
return getType.call(record) === "ai";
|
|
9755
|
+
} catch {
|
|
9756
|
+
return false;
|
|
9757
|
+
}
|
|
9758
|
+
}
|
|
9759
|
+
return false;
|
|
9760
|
+
}
|
|
9761
|
+
function asLangChainMessageContent(record) {
|
|
9762
|
+
const kwargs = asOptionalRecord(record.kwargs);
|
|
9763
|
+
return asMessageContent(kwargs?.content ?? record.content);
|
|
9764
|
+
}
|
|
9765
|
+
function isInternalLangGraphMarker(text) {
|
|
9766
|
+
return text === "__end__" || text === "__start__";
|
|
9767
|
+
}
|
|
9040
9768
|
function asMessageContent(value) {
|
|
9041
9769
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
9042
9770
|
return value.trim();
|
|
@@ -9966,7 +10694,7 @@ function buildAgentCard(peer, gatewayUrl) {
|
|
|
9966
10694
|
id: "default",
|
|
9967
10695
|
name: peer.name,
|
|
9968
10696
|
description: peer.description,
|
|
9969
|
-
tags: ["
|
|
10697
|
+
tags: ["band", "gateway"]
|
|
9970
10698
|
}
|
|
9971
10699
|
],
|
|
9972
10700
|
defaultInputModes: ["text/plain"],
|
|
@@ -10148,7 +10876,7 @@ var DEFAULT_RESPONSE_TIMEOUT_MS = 12e4;
|
|
|
10148
10876
|
var DEFAULT_PEER_PAGE_SIZE = 100;
|
|
10149
10877
|
var DEFAULT_MAX_PEER_PAGES = 25;
|
|
10150
10878
|
var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
10151
|
-
|
|
10879
|
+
bandRest;
|
|
10152
10880
|
gatewayUrl;
|
|
10153
10881
|
host;
|
|
10154
10882
|
port;
|
|
@@ -10169,7 +10897,7 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10169
10897
|
super({
|
|
10170
10898
|
historyConverter: new GatewayHistoryConverter()
|
|
10171
10899
|
});
|
|
10172
|
-
this.
|
|
10900
|
+
this.bandRest = options.bandRest;
|
|
10173
10901
|
this.gatewayUrl = options.gatewayUrl ?? DEFAULT_GATEWAY_URL;
|
|
10174
10902
|
this.host = options.host ?? DEFAULT_HOST;
|
|
10175
10903
|
this.port = options.port ?? DEFAULT_PORT;
|
|
@@ -10249,13 +10977,13 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10249
10977
|
async refreshPeers() {
|
|
10250
10978
|
this.peersBySlug.clear();
|
|
10251
10979
|
this.peersById.clear();
|
|
10252
|
-
if (!this.
|
|
10980
|
+
if (!this.bandRest.listPeers) {
|
|
10253
10981
|
throw new UnsupportedFeatureError(
|
|
10254
10982
|
"Peer listing is not available in current REST adapter"
|
|
10255
10983
|
);
|
|
10256
10984
|
}
|
|
10257
10985
|
for (let page = 1; page <= this.maxPeerPages; page += 1) {
|
|
10258
|
-
const response = await this.
|
|
10986
|
+
const response = await this.bandRest.listPeers({
|
|
10259
10987
|
page,
|
|
10260
10988
|
pageSize: this.peerPageSize,
|
|
10261
10989
|
notInChat: ""
|
|
@@ -10325,7 +11053,7 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10325
11053
|
try {
|
|
10326
11054
|
await this.emitContextEvent(roomId, contextId);
|
|
10327
11055
|
const content = extractMessageText2(request.message) ?? "";
|
|
10328
|
-
await this.
|
|
11056
|
+
await this.bandRest.createChatMessage(roomId, {
|
|
10329
11057
|
content: buildMentionedContent(peer.name, content),
|
|
10330
11058
|
mentions: buildMentions(peer),
|
|
10331
11059
|
metadata: {
|
|
@@ -10356,7 +11084,7 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10356
11084
|
contextId: pending.contextId,
|
|
10357
11085
|
state: "failed",
|
|
10358
11086
|
final: true,
|
|
10359
|
-
text: "Timed out waiting for a
|
|
11087
|
+
text: "Timed out waiting for a Band peer response."
|
|
10360
11088
|
});
|
|
10361
11089
|
return;
|
|
10362
11090
|
}
|
|
@@ -10443,7 +11171,7 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10443
11171
|
if (existingRoom) {
|
|
10444
11172
|
const participants = this.roomParticipants.get(existingRoom) ?? /* @__PURE__ */ new Set();
|
|
10445
11173
|
if (!participants.has(targetPeerId)) {
|
|
10446
|
-
await this.
|
|
11174
|
+
await this.bandRest.addChatParticipant(existingRoom, {
|
|
10447
11175
|
participantId: targetPeerId,
|
|
10448
11176
|
role: "member"
|
|
10449
11177
|
});
|
|
@@ -10453,11 +11181,11 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10453
11181
|
return [existingRoom, contextId];
|
|
10454
11182
|
}
|
|
10455
11183
|
const normalizedContextId = contextId && contextId.length > 0 ? contextId : (0, import_node_crypto5.randomUUID)();
|
|
10456
|
-
const created = await this.
|
|
11184
|
+
const created = await this.bandRest.createChat(
|
|
10457
11185
|
`a2a:gateway:${normalizedContextId}`
|
|
10458
11186
|
);
|
|
10459
11187
|
const roomId = created.id;
|
|
10460
|
-
await this.
|
|
11188
|
+
await this.bandRest.addChatParticipant(roomId, {
|
|
10461
11189
|
participantId: targetPeerId,
|
|
10462
11190
|
role: "member"
|
|
10463
11191
|
});
|
|
@@ -10466,7 +11194,7 @@ var A2AGatewayAdapter = class extends SimpleAdapter {
|
|
|
10466
11194
|
return [roomId, normalizedContextId];
|
|
10467
11195
|
}
|
|
10468
11196
|
async emitContextEvent(roomId, contextId) {
|
|
10469
|
-
await this.
|
|
11197
|
+
await this.bandRest.createChatEvent(roomId, {
|
|
10470
11198
|
content: "A2A gateway context",
|
|
10471
11199
|
messageType: "task",
|
|
10472
11200
|
metadata: {
|
|
@@ -10644,10 +11372,10 @@ function toStatusUpdateEvent(message, taskId, contextId) {
|
|
|
10644
11372
|
final,
|
|
10645
11373
|
text: message.content,
|
|
10646
11374
|
metadata: {
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
11375
|
+
band_message_id: message.id,
|
|
11376
|
+
band_message_type: message.messageType,
|
|
11377
|
+
band_sender_id: message.senderId,
|
|
11378
|
+
band_room_id: message.roomId
|
|
10651
11379
|
}
|
|
10652
11380
|
});
|
|
10653
11381
|
}
|
|
@@ -10817,8 +11545,8 @@ var ParlantAdapter = class extends SimpleAdapter {
|
|
|
10817
11545
|
message: userMessage,
|
|
10818
11546
|
moderation: "none",
|
|
10819
11547
|
metadata: {
|
|
10820
|
-
|
|
10821
|
-
|
|
11548
|
+
band_source: "band-sdk-typescript",
|
|
11549
|
+
band_room_id: context.roomId
|
|
10822
11550
|
}
|
|
10823
11551
|
},
|
|
10824
11552
|
this.requestOptions()
|
|
@@ -10893,9 +11621,9 @@ var ParlantAdapter = class extends SimpleAdapter {
|
|
|
10893
11621
|
{
|
|
10894
11622
|
agentId: this.agentId,
|
|
10895
11623
|
customerId,
|
|
10896
|
-
title: `
|
|
11624
|
+
title: `Band Room ${roomId.slice(0, 8)}`,
|
|
10897
11625
|
metadata: {
|
|
10898
|
-
|
|
11626
|
+
band_room_id: roomId
|
|
10899
11627
|
}
|
|
10900
11628
|
},
|
|
10901
11629
|
this.requestOptions()
|
|
@@ -10908,7 +11636,7 @@ var ParlantAdapter = class extends SimpleAdapter {
|
|
|
10908
11636
|
source: "system",
|
|
10909
11637
|
message: this.systemPrompt,
|
|
10910
11638
|
metadata: {
|
|
10911
|
-
|
|
11639
|
+
band_system_prompt: true
|
|
10912
11640
|
}
|
|
10913
11641
|
},
|
|
10914
11642
|
this.requestOptions()
|
|
@@ -10962,7 +11690,7 @@ var ParlantAdapter = class extends SimpleAdapter {
|
|
|
10962
11690
|
{
|
|
10963
11691
|
name: customerName,
|
|
10964
11692
|
metadata: {
|
|
10965
|
-
|
|
11693
|
+
band_room_id: roomId
|
|
10966
11694
|
}
|
|
10967
11695
|
},
|
|
10968
11696
|
this.requestOptions()
|
|
@@ -11512,7 +12240,7 @@ var LettaAdapter = class extends SimpleAdapter {
|
|
|
11512
12240
|
const agent = await this.raceTimeout(
|
|
11513
12241
|
(s) => client.agents.create(
|
|
11514
12242
|
{
|
|
11515
|
-
name: `
|
|
12243
|
+
name: `band-room-${roomId.slice(0, 16)}`,
|
|
11516
12244
|
model: this.model,
|
|
11517
12245
|
...this.embedding ? { embedding: this.embedding } : {},
|
|
11518
12246
|
system: this.systemPrompt || void 0,
|
|
@@ -11926,10 +12654,31 @@ async function loadLettaClientFactory(config) {
|
|
|
11926
12654
|
init_schemas();
|
|
11927
12655
|
init_registrations();
|
|
11928
12656
|
|
|
12657
|
+
// src/mcp/auth.ts
|
|
12658
|
+
var import_node_crypto6 = require("crypto");
|
|
12659
|
+
function generateAuthToken() {
|
|
12660
|
+
return (0, import_node_crypto6.randomBytes)(32).toString("hex");
|
|
12661
|
+
}
|
|
12662
|
+
function isAuthorizedRequest(authorizationHeader, authToken) {
|
|
12663
|
+
if (!authToken) {
|
|
12664
|
+
return true;
|
|
12665
|
+
}
|
|
12666
|
+
if (!authorizationHeader) {
|
|
12667
|
+
return false;
|
|
12668
|
+
}
|
|
12669
|
+
const expected = Buffer.from(`Bearer ${authToken}`);
|
|
12670
|
+
const actual = Buffer.from(authorizationHeader);
|
|
12671
|
+
if (expected.length !== actual.length) {
|
|
12672
|
+
return false;
|
|
12673
|
+
}
|
|
12674
|
+
return (0, import_node_crypto6.timingSafeEqual)(expected, actual);
|
|
12675
|
+
}
|
|
12676
|
+
|
|
11929
12677
|
// src/mcp/stdio.ts
|
|
11930
12678
|
init_registrations();
|
|
11931
12679
|
init_zod();
|
|
11932
|
-
|
|
12680
|
+
init_schemas();
|
|
12681
|
+
var BandMcpStdioServer = class {
|
|
11933
12682
|
options;
|
|
11934
12683
|
registrations;
|
|
11935
12684
|
mcpServer = null;
|
|
@@ -11956,12 +12705,12 @@ var ThenvoiMcpStdioServer = class {
|
|
|
11956
12705
|
}
|
|
11957
12706
|
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
11958
12707
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
11959
|
-
const { z:
|
|
12708
|
+
const { z: z6 } = await import("zod");
|
|
11960
12709
|
const mcpServer = new McpServer({
|
|
11961
|
-
name: this.options.name ??
|
|
12710
|
+
name: this.options.name ?? MCP_SERVER_NAME,
|
|
11962
12711
|
version: "1.0.0"
|
|
11963
12712
|
});
|
|
11964
|
-
registerTools(mcpServer,
|
|
12713
|
+
registerTools(mcpServer, z6, this.registrations);
|
|
11965
12714
|
const transport = new StdioServerTransport(this.options.stdin, this.options.stdout);
|
|
11966
12715
|
await mcpServer.connect(transport);
|
|
11967
12716
|
this.mcpServer = mcpServer;
|
|
@@ -11973,14 +12722,14 @@ var ThenvoiMcpStdioServer = class {
|
|
|
11973
12722
|
this.mcpServer = null;
|
|
11974
12723
|
}
|
|
11975
12724
|
};
|
|
11976
|
-
function registerTools(mcpServer,
|
|
12725
|
+
function registerTools(mcpServer, z6, registrations) {
|
|
11977
12726
|
for (const reg of registrations) {
|
|
11978
|
-
const zodShape = buildZodShape(
|
|
12727
|
+
const zodShape = buildZodShape(z6, reg.inputSchema.properties, new Set(reg.inputSchema.required));
|
|
11979
12728
|
mcpServer.registerTool(
|
|
11980
12729
|
reg.name,
|
|
11981
12730
|
{
|
|
11982
12731
|
description: reg.description,
|
|
11983
|
-
inputSchema:
|
|
12732
|
+
inputSchema: z6.object(zodShape)
|
|
11984
12733
|
},
|
|
11985
12734
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
|
|
11986
12735
|
async (args) => reg.execute(args)
|
|
@@ -11991,12 +12740,13 @@ function registerTools(mcpServer, z5, registrations) {
|
|
|
11991
12740
|
// src/mcp/server.ts
|
|
11992
12741
|
init_registrations();
|
|
11993
12742
|
init_zod();
|
|
12743
|
+
init_schemas();
|
|
11994
12744
|
var PORT_RANGE_START = 5e4;
|
|
11995
12745
|
var PORT_RANGE_END = 6e4;
|
|
11996
12746
|
var MCP_SERVER_VERSION = "1.0.0";
|
|
11997
12747
|
var SESSION_IDLE_TTL_MS = 15 * 60 * 1e3;
|
|
11998
12748
|
var SESSION_SWEEP_INTERVAL_MS = 60 * 1e3;
|
|
11999
|
-
var
|
|
12749
|
+
var BandMcpServer = class {
|
|
12000
12750
|
options;
|
|
12001
12751
|
registrations;
|
|
12002
12752
|
httpServer = null;
|
|
@@ -12039,8 +12789,8 @@ var ThenvoiMcpServer = class {
|
|
|
12039
12789
|
const express = expressModule.default ?? expressModule;
|
|
12040
12790
|
const http = await import("http");
|
|
12041
12791
|
const { randomUUID: randomUUID6 } = await import("crypto");
|
|
12042
|
-
const { z:
|
|
12043
|
-
const serverName = this.options.name ??
|
|
12792
|
+
const { z: z6 } = await import("zod");
|
|
12793
|
+
const serverName = this.options.name ?? MCP_SERVER_NAME;
|
|
12044
12794
|
const app = express();
|
|
12045
12795
|
app.use(express.json());
|
|
12046
12796
|
app.get("/healthz", (_req, res) => {
|
|
@@ -12048,6 +12798,10 @@ var ThenvoiMcpServer = class {
|
|
|
12048
12798
|
});
|
|
12049
12799
|
const handleMcpRequest = async (req, res) => {
|
|
12050
12800
|
try {
|
|
12801
|
+
if (!isAuthorizedRequest(req.headers.authorization, this.options.authToken)) {
|
|
12802
|
+
sendMcpError(res, 401, "Unauthorized");
|
|
12803
|
+
return;
|
|
12804
|
+
}
|
|
12051
12805
|
const sessionId = getSessionIdHeader(req.headers["mcp-session-id"]);
|
|
12052
12806
|
let session = sessionId ? this.sessions.get(sessionId) : void 0;
|
|
12053
12807
|
if (!session) {
|
|
@@ -12060,7 +12814,7 @@ var ThenvoiMcpServer = class {
|
|
|
12060
12814
|
StreamableHTTPServerTransport,
|
|
12061
12815
|
serverName,
|
|
12062
12816
|
sessionIdGenerator: randomUUID6,
|
|
12063
|
-
z:
|
|
12817
|
+
z: z6
|
|
12064
12818
|
});
|
|
12065
12819
|
}
|
|
12066
12820
|
session.lastSeenAt = Date.now();
|
|
@@ -12186,14 +12940,14 @@ function sendMcpError(res, status, message) {
|
|
|
12186
12940
|
id: null
|
|
12187
12941
|
});
|
|
12188
12942
|
}
|
|
12189
|
-
function registerTools2(mcpServer,
|
|
12943
|
+
function registerTools2(mcpServer, z6, registrations) {
|
|
12190
12944
|
for (const reg of registrations) {
|
|
12191
|
-
const zodShape = buildZodShape(
|
|
12945
|
+
const zodShape = buildZodShape(z6, reg.inputSchema.properties, new Set(reg.inputSchema.required));
|
|
12192
12946
|
mcpServer.registerTool(
|
|
12193
12947
|
reg.name,
|
|
12194
12948
|
{
|
|
12195
12949
|
description: reg.description,
|
|
12196
|
-
inputSchema:
|
|
12950
|
+
inputSchema: z6.object(zodShape)
|
|
12197
12951
|
},
|
|
12198
12952
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
|
|
12199
12953
|
async (args) => reg.execute(args)
|
|
@@ -12223,11 +12977,12 @@ function checkPort(http, port) {
|
|
|
12223
12977
|
// src/mcp/sse.ts
|
|
12224
12978
|
init_registrations();
|
|
12225
12979
|
init_zod();
|
|
12980
|
+
init_schemas();
|
|
12226
12981
|
var PORT_RANGE_START2 = 5e4;
|
|
12227
12982
|
var PORT_RANGE_END2 = 6e4;
|
|
12228
12983
|
var SESSION_IDLE_TTL_MS2 = 15 * 60 * 1e3;
|
|
12229
12984
|
var SESSION_SWEEP_INTERVAL_MS2 = 60 * 1e3;
|
|
12230
|
-
var
|
|
12985
|
+
var BandMcpSseServer = class {
|
|
12231
12986
|
options;
|
|
12232
12987
|
registrations;
|
|
12233
12988
|
httpServer = null;
|
|
@@ -12268,19 +13023,23 @@ var ThenvoiMcpSseServer = class {
|
|
|
12268
13023
|
const expressModule = await import("express");
|
|
12269
13024
|
const express = expressModule.default ?? expressModule;
|
|
12270
13025
|
const http = await import("http");
|
|
12271
|
-
const { z:
|
|
13026
|
+
const { z: z6 } = await import("zod");
|
|
12272
13027
|
const app = express();
|
|
12273
13028
|
app.use(express.json());
|
|
12274
13029
|
app.get("/healthz", (_req, res) => {
|
|
12275
13030
|
res.json({ status: "ok" });
|
|
12276
13031
|
});
|
|
12277
|
-
app.get("/sse", async (
|
|
13032
|
+
app.get("/sse", async (req, res) => {
|
|
13033
|
+
if (!isAuthorizedRequest(req.headers.authorization, this.options.authToken)) {
|
|
13034
|
+
res.status(401).send("Unauthorized");
|
|
13035
|
+
return;
|
|
13036
|
+
}
|
|
12278
13037
|
const transport = new SSEServerTransport("/messages", res);
|
|
12279
13038
|
const mcpServer = new McpServer({
|
|
12280
|
-
name: this.options.name ??
|
|
13039
|
+
name: this.options.name ?? MCP_SERVER_NAME,
|
|
12281
13040
|
version: "1.0.0"
|
|
12282
13041
|
});
|
|
12283
|
-
registerTools3(mcpServer,
|
|
13042
|
+
registerTools3(mcpServer, z6, this.registrations);
|
|
12284
13043
|
await mcpServer.connect(transport);
|
|
12285
13044
|
const sessionId = transport.sessionId;
|
|
12286
13045
|
this.sessions.set(sessionId, {
|
|
@@ -12299,6 +13058,10 @@ var ThenvoiMcpSseServer = class {
|
|
|
12299
13058
|
});
|
|
12300
13059
|
});
|
|
12301
13060
|
app.post("/messages", async (req, res) => {
|
|
13061
|
+
if (!isAuthorizedRequest(req.headers.authorization, this.options.authToken)) {
|
|
13062
|
+
res.status(401).send("Unauthorized");
|
|
13063
|
+
return;
|
|
13064
|
+
}
|
|
12302
13065
|
const sessionId = typeof req.query.sessionId === "string" ? req.query.sessionId : null;
|
|
12303
13066
|
if (!sessionId) {
|
|
12304
13067
|
res.status(400).send("Missing sessionId");
|
|
@@ -12372,10 +13135,10 @@ var ThenvoiMcpSseServer = class {
|
|
|
12372
13135
|
}
|
|
12373
13136
|
}
|
|
12374
13137
|
};
|
|
12375
|
-
function registerTools3(mcpServer,
|
|
13138
|
+
function registerTools3(mcpServer, z6, registrations) {
|
|
12376
13139
|
for (const registration of registrations) {
|
|
12377
13140
|
const zodShape = buildZodShape(
|
|
12378
|
-
|
|
13141
|
+
z6,
|
|
12379
13142
|
registration.inputSchema.properties,
|
|
12380
13143
|
new Set(registration.inputSchema.required)
|
|
12381
13144
|
);
|
|
@@ -12383,7 +13146,7 @@ function registerTools3(mcpServer, z5, registrations) {
|
|
|
12383
13146
|
registration.name,
|
|
12384
13147
|
{
|
|
12385
13148
|
description: registration.description,
|
|
12386
|
-
inputSchema:
|
|
13149
|
+
inputSchema: z6.object(zodShape)
|
|
12387
13150
|
},
|
|
12388
13151
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler signature is complex; our McpToolResult is compatible
|
|
12389
13152
|
async (args) => registration.execute(args)
|
|
@@ -12412,21 +13175,18 @@ function checkPort2(http, port) {
|
|
|
12412
13175
|
}
|
|
12413
13176
|
|
|
12414
13177
|
// src/mcp/backends.ts
|
|
12415
|
-
async function
|
|
12416
|
-
const
|
|
12417
|
-
options.
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
additionalTools: options.additionalTools
|
|
12422
|
-
}
|
|
12423
|
-
);
|
|
12424
|
-
const allowedTools = mcpToolNames(new Set(registrations.map((registration) => registration.name)));
|
|
13178
|
+
async function createBandMcpBackend(options) {
|
|
13179
|
+
const registrationOptions = {
|
|
13180
|
+
enableMemoryTools: options.enableMemoryTools,
|
|
13181
|
+
enableContactTools: true,
|
|
13182
|
+
additionalTools: options.additionalTools
|
|
13183
|
+
};
|
|
12425
13184
|
if (options.kind === "sdk") {
|
|
12426
|
-
const {
|
|
12427
|
-
const server2 =
|
|
12428
|
-
enableMemoryTools: options.enableMemoryTools,
|
|
13185
|
+
const { createBandSdkMcpServer: createBandSdkMcpServer2 } = await Promise.resolve().then(() => (init_sdk(), sdk_exports));
|
|
13186
|
+
const server2 = createBandSdkMcpServer2({
|
|
12429
13187
|
getToolsForRoom: options.getToolsForRoom,
|
|
13188
|
+
multiRoom: options.multiRoom,
|
|
13189
|
+
enableMemoryTools: options.enableMemoryTools,
|
|
12430
13190
|
additionalTools: options.additionalTools
|
|
12431
13191
|
});
|
|
12432
13192
|
return {
|
|
@@ -12436,9 +13196,12 @@ async function createThenvoiMcpBackend(options) {
|
|
|
12436
13196
|
stop: async () => void 0
|
|
12437
13197
|
};
|
|
12438
13198
|
}
|
|
13199
|
+
const resolvedTools = options.multiRoom === false ? resolveSingleRoomTools(options.getToolsForRoom) : options.getToolsForRoom;
|
|
13200
|
+
const registrations = options.multiRoom === false ? buildSingleContextRegistrations(resolvedTools, registrationOptions) : buildRoomScopedRegistrations(resolvedTools, registrationOptions);
|
|
13201
|
+
const allowedTools = mcpToolNames(new Set(registrations.map((registration) => registration.name)));
|
|
12439
13202
|
if (options.kind === "stdio") {
|
|
12440
|
-
const server2 = new
|
|
12441
|
-
tools:
|
|
13203
|
+
const server2 = new BandMcpStdioServer({
|
|
13204
|
+
tools: resolvedTools,
|
|
12442
13205
|
enableMemoryTools: options.enableMemoryTools,
|
|
12443
13206
|
enableContactTools: true,
|
|
12444
13207
|
additionalTools: options.additionalTools
|
|
@@ -12453,34 +13216,39 @@ async function createThenvoiMcpBackend(options) {
|
|
|
12453
13216
|
}
|
|
12454
13217
|
};
|
|
12455
13218
|
}
|
|
13219
|
+
const authToken = generateAuthToken();
|
|
12456
13220
|
if (options.kind === "sse") {
|
|
12457
|
-
const server2 = new
|
|
12458
|
-
tools:
|
|
13221
|
+
const server2 = new BandMcpSseServer({
|
|
13222
|
+
tools: resolvedTools,
|
|
12459
13223
|
enableMemoryTools: options.enableMemoryTools,
|
|
12460
13224
|
enableContactTools: true,
|
|
12461
|
-
additionalTools: options.additionalTools
|
|
13225
|
+
additionalTools: options.additionalTools,
|
|
13226
|
+
authToken
|
|
12462
13227
|
});
|
|
12463
13228
|
await server2.start();
|
|
12464
13229
|
return {
|
|
12465
13230
|
kind: "sse",
|
|
12466
13231
|
server: server2,
|
|
12467
13232
|
allowedTools,
|
|
13233
|
+
authToken,
|
|
12468
13234
|
stop: async () => {
|
|
12469
13235
|
await server2.stop();
|
|
12470
13236
|
}
|
|
12471
13237
|
};
|
|
12472
13238
|
}
|
|
12473
|
-
const server = new
|
|
12474
|
-
tools:
|
|
13239
|
+
const server = new BandMcpServer({
|
|
13240
|
+
tools: resolvedTools,
|
|
12475
13241
|
enableMemoryTools: options.enableMemoryTools,
|
|
12476
13242
|
enableContactTools: true,
|
|
12477
|
-
additionalTools: options.additionalTools
|
|
13243
|
+
additionalTools: options.additionalTools,
|
|
13244
|
+
authToken
|
|
12478
13245
|
});
|
|
12479
13246
|
await server.start();
|
|
12480
13247
|
return {
|
|
12481
13248
|
kind: "http",
|
|
12482
13249
|
server,
|
|
12483
13250
|
allowedTools,
|
|
13251
|
+
authToken,
|
|
12484
13252
|
stop: async () => {
|
|
12485
13253
|
await server.stop();
|
|
12486
13254
|
}
|
|
@@ -12489,6 +13257,7 @@ async function createThenvoiMcpBackend(options) {
|
|
|
12489
13257
|
|
|
12490
13258
|
// src/adapters/opencode/OpencodeAdapter.ts
|
|
12491
13259
|
init_registrations();
|
|
13260
|
+
init_schemas();
|
|
12492
13261
|
|
|
12493
13262
|
// src/converters/opencode.ts
|
|
12494
13263
|
var OpencodeHistoryConverter = class {
|
|
@@ -12622,7 +13391,7 @@ var SdkOpencodeClientBase = class {
|
|
|
12622
13391
|
const result = await runtime.client.mcp.add({
|
|
12623
13392
|
...this.scope(),
|
|
12624
13393
|
name: input.name,
|
|
12625
|
-
config: { type: "remote", url: input.url }
|
|
13394
|
+
config: { type: "remote", url: input.url, headers: input.headers }
|
|
12626
13395
|
});
|
|
12627
13396
|
return expectRecord(result);
|
|
12628
13397
|
}
|
|
@@ -12710,7 +13479,7 @@ var SdkOpencodeClientBase = class {
|
|
|
12710
13479
|
}
|
|
12711
13480
|
const response = await fetch(url, { method: "DELETE" });
|
|
12712
13481
|
if (!response.ok && response.status !== 404) {
|
|
12713
|
-
throw new HttpStatusError(response.status, await
|
|
13482
|
+
throw new HttpStatusError(response.status, await readResponseBody2(response));
|
|
12714
13483
|
}
|
|
12715
13484
|
}
|
|
12716
13485
|
};
|
|
@@ -12799,7 +13568,7 @@ async function findAvailablePort3() {
|
|
|
12799
13568
|
});
|
|
12800
13569
|
});
|
|
12801
13570
|
}
|
|
12802
|
-
async function
|
|
13571
|
+
async function readResponseBody2(response) {
|
|
12803
13572
|
const contentType = response.headers.get("content-type") ?? "";
|
|
12804
13573
|
if (contentType.includes("application/json")) {
|
|
12805
13574
|
try {
|
|
@@ -12813,8 +13582,8 @@ async function readResponseBody(response) {
|
|
|
12813
13582
|
|
|
12814
13583
|
// src/adapters/opencode/OpencodeAdapter.ts
|
|
12815
13584
|
var OPENCODE_SYSTEM_NOTE = [
|
|
12816
|
-
"Responses are relayed back into the
|
|
12817
|
-
"Use the
|
|
13585
|
+
"Responses are relayed back into the Band room by the adapter.",
|
|
13586
|
+
"Use the band_ prefixed tools (for example band_send_message) for Band platform actions when available.",
|
|
12818
13587
|
"When you need approval or clarification, ask clearly and wait for the user's next room message."
|
|
12819
13588
|
].join("\n");
|
|
12820
13589
|
function createDeferred() {
|
|
@@ -12845,8 +13614,8 @@ function withDefaults(config) {
|
|
|
12845
13614
|
approvalTimeoutReply: "reject",
|
|
12846
13615
|
questionMode: "manual",
|
|
12847
13616
|
questionWaitTimeoutMs: 3e5,
|
|
12848
|
-
sessionTitlePrefix: "
|
|
12849
|
-
mcpServerName:
|
|
13617
|
+
sessionTitlePrefix: "Band",
|
|
13618
|
+
mcpServerName: MCP_SERVER_NAME,
|
|
12850
13619
|
...config
|
|
12851
13620
|
};
|
|
12852
13621
|
}
|
|
@@ -12902,7 +13671,7 @@ var OpencodeAdapter = class extends SimpleAdapter {
|
|
|
12902
13671
|
directory: config.directory || void 0,
|
|
12903
13672
|
workspace: config.workspace || void 0
|
|
12904
13673
|
}));
|
|
12905
|
-
this.mcpBackendFactory = options.mcpBackendFactory ??
|
|
13674
|
+
this.mcpBackendFactory = options.mcpBackendFactory ?? createBandMcpBackend;
|
|
12906
13675
|
this.logger = options.logger ?? new NoopLogger();
|
|
12907
13676
|
}
|
|
12908
13677
|
async onStarted(agentName, agentDescription) {
|
|
@@ -12911,7 +13680,8 @@ var OpencodeAdapter = class extends SimpleAdapter {
|
|
|
12911
13680
|
agentName,
|
|
12912
13681
|
agentDescription,
|
|
12913
13682
|
customSection: this.config.customSection,
|
|
12914
|
-
includeBaseInstructions: this.config.includeBaseInstructions
|
|
13683
|
+
includeBaseInstructions: this.config.includeBaseInstructions,
|
|
13684
|
+
capabilities: { memory: this.config.enableMemoryTools }
|
|
12915
13685
|
}).trim();
|
|
12916
13686
|
this.systemPrompt = `${systemPrompt}
|
|
12917
13687
|
|
|
@@ -13055,7 +13825,8 @@ ${OPENCODE_SYSTEM_NOTE}`.trim();
|
|
|
13055
13825
|
}
|
|
13056
13826
|
await client.registerMcpServer({
|
|
13057
13827
|
name: this.config.mcpServerName,
|
|
13058
|
-
url: server.url
|
|
13828
|
+
url: server.url,
|
|
13829
|
+
headers: backend.authToken ? { Authorization: `Bearer ${backend.authToken}` } : void 0
|
|
13059
13830
|
});
|
|
13060
13831
|
} catch (error) {
|
|
13061
13832
|
this.logger.warn("Failed to register OpenCode MCP backend", { error });
|
|
@@ -13691,9 +14462,9 @@ function extractClaudeSessionId(raw) {
|
|
|
13691
14462
|
// src/adapters/claude-sdk/ClaudeSDKAdapter.ts
|
|
13692
14463
|
init_registrations();
|
|
13693
14464
|
init_zod();
|
|
13694
|
-
var
|
|
14465
|
+
var import_zod10 = require("zod");
|
|
13695
14466
|
var DEFAULT_MODEL2 = "claude-sonnet-4-6";
|
|
13696
|
-
var
|
|
14467
|
+
var bandMcpBridgeFactory = new LazyAsyncValue({
|
|
13697
14468
|
load: async () => {
|
|
13698
14469
|
const module2 = await import("@anthropic-ai/claude-agent-sdk").catch((error) => {
|
|
13699
14470
|
throw new UnsupportedFeatureError(
|
|
@@ -13718,7 +14489,7 @@ var thenvoiMcpBridgeFactory = new LazyAsyncValue({
|
|
|
13718
14489
|
);
|
|
13719
14490
|
const toolDefinitions = registrations.map((registration) => {
|
|
13720
14491
|
const shape = buildZodShape(
|
|
13721
|
-
|
|
14492
|
+
import_zod10.z,
|
|
13722
14493
|
registration.inputSchema.properties,
|
|
13723
14494
|
new Set(registration.inputSchema.required)
|
|
13724
14495
|
);
|
|
@@ -13731,7 +14502,7 @@ var thenvoiMcpBridgeFactory = new LazyAsyncValue({
|
|
|
13731
14502
|
});
|
|
13732
14503
|
return {
|
|
13733
14504
|
serverConfig: createSdkMcpServer2({
|
|
13734
|
-
name:
|
|
14505
|
+
name: MCP_SERVER_NAME,
|
|
13735
14506
|
tools: toolDefinitions
|
|
13736
14507
|
}),
|
|
13737
14508
|
allowedTools: mcpToolNames(new Set(registrations.map((registration) => registration.name)))
|
|
@@ -13778,11 +14549,12 @@ var ClaudeSDKAdapter = class extends SimpleAdapter {
|
|
|
13778
14549
|
agentName,
|
|
13779
14550
|
agentDescription,
|
|
13780
14551
|
customSection: this.customSection,
|
|
13781
|
-
includeBaseInstructions: this.includeBaseInstructions
|
|
14552
|
+
includeBaseInstructions: this.includeBaseInstructions,
|
|
14553
|
+
capabilities: { memory: this.enableMemoryTools }
|
|
13782
14554
|
});
|
|
13783
14555
|
if (this.enableMcpTools) {
|
|
13784
|
-
const
|
|
13785
|
-
this.mcpBridge =
|
|
14556
|
+
const createBandMcpBridge = await bandMcpBridgeFactory.get();
|
|
14557
|
+
this.mcpBridge = createBandMcpBridge({
|
|
13786
14558
|
enableMemoryTools: this.enableMemoryTools,
|
|
13787
14559
|
getToolsForRoom: (roomId) => this.roomTools.get(roomId),
|
|
13788
14560
|
additionalTools: this.additionalMcpTools.length > 0 ? this.additionalMcpTools : void 0
|
|
@@ -13830,14 +14602,14 @@ var ClaudeSDKAdapter = class extends SimpleAdapter {
|
|
|
13830
14602
|
}
|
|
13831
14603
|
if (this.mcpBridge && this.enableMcpTools) {
|
|
13832
14604
|
options.mcpServers = {
|
|
13833
|
-
|
|
14605
|
+
[MCP_SERVER_NAME]: this.mcpBridge.serverConfig
|
|
13834
14606
|
};
|
|
13835
14607
|
options.allowedTools = this.mcpBridge.allowedTools;
|
|
13836
14608
|
this.roomTools.set(context.roomId, tools);
|
|
13837
14609
|
}
|
|
13838
14610
|
const roomToolHint = this.enableMcpTools ? `
|
|
13839
14611
|
|
|
13840
|
-
[Tooling note]: For any
|
|
14612
|
+
[Tooling note]: For any mcp__band__* tool call, pass room_id="${context.roomId}".` : "";
|
|
13841
14613
|
const query = queryFn({
|
|
13842
14614
|
prompt: buildConversationPrompt({
|
|
13843
14615
|
history,
|
|
@@ -13933,6 +14705,7 @@ init_schemas();
|
|
|
13933
14705
|
Agent,
|
|
13934
14706
|
AgentRuntime,
|
|
13935
14707
|
AnthropicAdapter,
|
|
14708
|
+
BandLink,
|
|
13936
14709
|
CODEX_REASONING_EFFORTS,
|
|
13937
14710
|
CODEX_REASONING_SUMMARIES,
|
|
13938
14711
|
CODEX_WEB_SEARCH_MODES,
|
|
@@ -13944,6 +14717,7 @@ init_schemas();
|
|
|
13944
14717
|
GoogleADKAdapter,
|
|
13945
14718
|
LangGraphAdapter,
|
|
13946
14719
|
LettaAdapter,
|
|
14720
|
+
MCP_SERVER_NAME,
|
|
13947
14721
|
MCP_TOOL_PREFIX,
|
|
13948
14722
|
OpenAIAdapter,
|
|
13949
14723
|
OpencodeAdapter,
|
|
@@ -13951,8 +14725,9 @@ init_schemas();
|
|
|
13951
14725
|
PlatformRuntime,
|
|
13952
14726
|
SimpleAdapter,
|
|
13953
14727
|
TOOL_MODELS,
|
|
13954
|
-
ThenvoiLink,
|
|
13955
14728
|
VercelAISDKAdapter,
|
|
14729
|
+
WebSocketDisconnectError,
|
|
14730
|
+
deriveDefaultRestUrl,
|
|
13956
14731
|
isDirectExecution,
|
|
13957
14732
|
loadAgentConfig,
|
|
13958
14733
|
loadAgentConfigFromEnv
|