@band-ai/sdk 0.1.10 → 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 +54 -54
- package/dist/{ClaudeSDKAdapter-DfjaI5ke.d.cts → ClaudeSDKAdapter-BY4zEbCl.d.cts} +12 -10
- package/dist/{ClaudeSDKAdapter-DonPGJ43.d.ts → ClaudeSDKAdapter-Cna5P1dR.d.ts} +12 -10
- package/dist/{acp-server-NZAeg-WO.d.ts → acp-server-CiUqN3G3.d.ts} +2 -2
- package/dist/{acp-server-CUBXIiG6.d.cts → acp-server-Dlj7D563.d.cts} +2 -2
- package/dist/adapters.cjs +250 -183
- 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-2BHHR6YW.js → chunk-4IAXZBXX.js} +62 -23
- package/dist/{chunk-SG4WLD2H.js → chunk-EAI2M3WM.js} +38 -94
- package/dist/{chunk-YR3BOQNW.js → chunk-JY75VSQK.js} +7 -7
- package/dist/{chunk-RDM4TE4B.js → chunk-LBWKISBS.js} +19 -1
- package/dist/{chunk-FP237EAG.js → chunk-N2QTUMGO.js} +112 -195
- package/dist/{chunk-J3M3PFFY.js → chunk-NMZLX7TP.js} +35 -31
- package/dist/{chunk-6RXWL6TC.js → chunk-NT7TBFX2.js} +1 -1
- package/dist/{chunk-MLROFDKR.js → chunk-RV76SKFT.js} +39 -33
- package/dist/{chunk-XA4N2JPH.js → chunk-TLBCKDQO.js} +23 -23
- package/dist/{chunk-IZPV6QS6.js → chunk-WL2HNJZ6.js} +38 -11
- package/dist/{chunk-DNPVCR3S.js → chunk-WLCM2OXG.js} +31 -31
- 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 +61 -61
- package/dist/converters.d.cts +5 -5
- package/dist/converters.d.ts +5 -5
- package/dist/converters.js +4 -4
- package/dist/core.cjs +8 -8
- package/dist/core.d.cts +9 -9
- package/dist/core.d.ts +9 -9
- package/dist/core.js +3 -3
- package/dist/{dtos-Dd_fTfLn.d.cts → dtos-B8KU_q4d.d.cts} +2 -2
- package/dist/{dtos-Dd_fTfLn.d.ts → dtos-B8KU_q4d.d.ts} +2 -2
- package/dist/index.cjs +459 -504
- package/dist/index.d.cts +16 -15
- package/dist/index.d.ts +16 -15
- package/dist/index.js +15 -13
- package/dist/linear.cjs +74 -74
- package/dist/linear.d.cts +14 -14
- package/dist/linear.d.ts +14 -14
- package/dist/linear.js +72 -72
- package/dist/mcp-claude.cjs +37 -36
- package/dist/mcp-claude.d.cts +3 -3
- package/dist/mcp-claude.d.ts +3 -3
- package/dist/mcp-claude.js +7 -6
- package/dist/mcp.cjs +103 -62
- package/dist/mcp.d.cts +29 -16
- package/dist/mcp.d.ts +29 -16
- package/dist/mcp.js +14 -14
- package/dist/{opencode--iA5-KYk.d.cts → opencode-2YdscIc1.d.cts} +5 -5
- package/dist/{opencode-YNacv-eJ.d.ts → opencode-Bld62x5t.d.ts} +5 -5
- package/dist/{pagination-BBLsYLhT.d.ts → pagination-BgEx-HeL.d.ts} +2 -2
- package/dist/{pagination-CqidD-L_.d.cts → pagination-DqdkQArT.d.cts} +2 -2
- package/dist/{protocols-BF6jamIl.d.ts → protocols-Bwwcql0h.d.ts} +1 -1
- package/dist/{protocols-D2bTrQ_t.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 +293 -464
- package/dist/runtime.d.cts +16 -28
- package/dist/runtime.d.ts +16 -28
- package/dist/runtime.js +12 -63
- package/dist/{schemas-CI0qgcp_.d.cts → schemas-BotL3ZLH.d.cts} +40 -54
- package/dist/{schemas-B1Fd3oUM.d.ts → schemas-DBsC4J1g.d.ts} +40 -54
- package/dist/{sdk-D2rTDU_o.d.cts → sdk-BTciSLRQ.d.cts} +5 -5
- package/dist/{sdk-CyqN1W5g.d.ts → sdk-qKJtMma_.d.ts} +5 -5
- package/dist/{simpleAdapter-qQt-tSz4.d.ts → simpleAdapter--wznuoOw.d.ts} +1 -1
- package/dist/{simpleAdapter-C_f-01Cu.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-DNySTI_8.d.ts → types-BTN_ZETM.d.ts} +2 -2
- package/dist/{types-D3AsUnd0.d.ts → types-BgYFd_Yw.d.cts} +5 -5
- package/dist/{types-DtMms5Fi.d.cts → types-BivGO7I9.d.ts} +5 -5
- package/dist/{types-CKqrhGB1.d.cts → types-D958TC71.d.cts} +2 -2
- package/package.json +6 -5
- package/dist/backends-DYtEhCZG.d.cts +0 -25
- package/dist/backends-oYAb7EU-.d.ts +0 -25
package/dist/runtime.cjs
CHANGED
|
@@ -37,12 +37,13 @@ __export(runtime_exports, {
|
|
|
37
37
|
GracefulShutdown: () => GracefulShutdown,
|
|
38
38
|
HUB_ROOM_SYSTEM_PROMPT: () => HUB_ROOM_SYSTEM_PROMPT,
|
|
39
39
|
HistoryProvider: () => HistoryProvider,
|
|
40
|
+
MCP_SERVER_NAME: () => MCP_SERVER_NAME,
|
|
40
41
|
MCP_TOOL_PREFIX: () => MCP_TOOL_PREFIX,
|
|
41
42
|
MEMORY_SECTION: () => MEMORY_SECTION,
|
|
42
43
|
MEMORY_TOOL_NAMES: () => MEMORY_TOOL_NAMES,
|
|
43
|
-
|
|
44
|
-
ParticipantTracker: () => ParticipantTracker,
|
|
44
|
+
ParticipantRoster: () => import_band_sdk_core3.ParticipantRoster,
|
|
45
45
|
PlatformRuntime: () => PlatformRuntime,
|
|
46
|
+
RetryTracker: () => import_band_sdk_core3.RetryTracker,
|
|
46
47
|
RoomPresence: () => RoomPresence,
|
|
47
48
|
SYNTHETIC_CONTACT_EVENTS_SENDER_ID: () => SYNTHETIC_CONTACT_EVENTS_SENDER_ID,
|
|
48
49
|
SYNTHETIC_CONTACT_EVENTS_SENDER_NAME: () => SYNTHETIC_CONTACT_EVENTS_SENDER_NAME,
|
|
@@ -99,39 +100,112 @@ var NoopLogger = class {
|
|
|
99
100
|
var DEFAULT_REQUEST_OPTIONS = {
|
|
100
101
|
maxRetries: 3
|
|
101
102
|
};
|
|
103
|
+
var MESSAGE_SEND_MAX_RETRIES = 2;
|
|
102
104
|
|
|
103
105
|
// src/core/errors.ts
|
|
104
|
-
var
|
|
106
|
+
var BandSdkError = class extends Error {
|
|
105
107
|
constructor(message, cause) {
|
|
106
108
|
super(message, cause !== void 0 ? { cause } : void 0);
|
|
107
|
-
this.name = "
|
|
109
|
+
this.name = "BandSdkError";
|
|
108
110
|
}
|
|
109
111
|
};
|
|
110
|
-
var UnsupportedFeatureError = class extends
|
|
112
|
+
var UnsupportedFeatureError = class extends BandSdkError {
|
|
111
113
|
constructor(message) {
|
|
112
114
|
super(message);
|
|
113
115
|
this.name = "UnsupportedFeatureError";
|
|
114
116
|
}
|
|
115
117
|
};
|
|
116
|
-
var ValidationError = class extends
|
|
118
|
+
var ValidationError = class extends BandSdkError {
|
|
117
119
|
constructor(message, cause) {
|
|
118
120
|
super(message, cause);
|
|
119
121
|
this.name = "ValidationError";
|
|
120
122
|
}
|
|
121
123
|
};
|
|
122
|
-
var TransportError = class extends
|
|
124
|
+
var TransportError = class extends BandSdkError {
|
|
123
125
|
constructor(message, cause) {
|
|
124
126
|
super(message, cause);
|
|
125
127
|
this.name = "TransportError";
|
|
126
128
|
}
|
|
127
129
|
};
|
|
128
|
-
var RuntimeStateError = class extends
|
|
130
|
+
var RuntimeStateError = class extends BandSdkError {
|
|
129
131
|
constructor(message) {
|
|
130
132
|
super(message);
|
|
131
133
|
this.name = "RuntimeStateError";
|
|
132
134
|
}
|
|
133
135
|
};
|
|
134
136
|
|
|
137
|
+
// src/runtime/formatters.ts
|
|
138
|
+
function isMetadataMap(value) {
|
|
139
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
140
|
+
}
|
|
141
|
+
function replaceUuidMentions(content, participants) {
|
|
142
|
+
if (!content || participants.length === 0) {
|
|
143
|
+
return content;
|
|
144
|
+
}
|
|
145
|
+
let next = content;
|
|
146
|
+
for (const participant of participants) {
|
|
147
|
+
const participantId = participant.id;
|
|
148
|
+
const handle = participant.handle;
|
|
149
|
+
if (typeof participantId === "string" && typeof handle === "string") {
|
|
150
|
+
next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return next;
|
|
154
|
+
}
|
|
155
|
+
function formatMessageForLlm(message, participants) {
|
|
156
|
+
const senderType = String(message.sender_type ?? "");
|
|
157
|
+
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
158
|
+
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
159
|
+
return {
|
|
160
|
+
role: senderType === "Agent" ? "assistant" : "user",
|
|
161
|
+
content,
|
|
162
|
+
sender_name: senderName,
|
|
163
|
+
sender_type: senderType,
|
|
164
|
+
message_type: String(message.message_type ?? "text"),
|
|
165
|
+
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function formatHistoryForLlm(messages, options) {
|
|
169
|
+
const excludeId = options?.excludeId;
|
|
170
|
+
const participants = options?.participants;
|
|
171
|
+
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
172
|
+
}
|
|
173
|
+
function toParticipantRecord(fields) {
|
|
174
|
+
return {
|
|
175
|
+
id: fields.id,
|
|
176
|
+
name: fields.name ?? "unknown",
|
|
177
|
+
type: fields.type ?? "unknown",
|
|
178
|
+
handle: fields.handle ?? null
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function toParticipantRecordFromRest(participant) {
|
|
182
|
+
return {
|
|
183
|
+
id: participant.id,
|
|
184
|
+
name: participant.name,
|
|
185
|
+
type: participant.type,
|
|
186
|
+
handle: participant.handle ?? null
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function buildParticipantsMessage(participants) {
|
|
190
|
+
if (participants.length === 0) {
|
|
191
|
+
return "## Current Participants\nNo other participants in this room.";
|
|
192
|
+
}
|
|
193
|
+
const lines = ["## Current Participants"];
|
|
194
|
+
for (const participant of participants) {
|
|
195
|
+
const participantType = String(participant.type ?? "Unknown");
|
|
196
|
+
const participantName = String(participant.name ?? "Unknown");
|
|
197
|
+
const participantHandle = String(participant.handle ?? "Unknown");
|
|
198
|
+
lines.push(
|
|
199
|
+
`- ${ensureHandlePrefix(participantHandle) ?? ""} \u2014 ${participantName} (${participantType})`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
lines.push("");
|
|
203
|
+
lines.push(
|
|
204
|
+
"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."
|
|
205
|
+
);
|
|
206
|
+
return lines.join("\n");
|
|
207
|
+
}
|
|
208
|
+
|
|
135
209
|
// src/runtime/tools/ContactToolsImpl.ts
|
|
136
210
|
var ContactToolsImpl = class {
|
|
137
211
|
rest;
|
|
@@ -228,14 +302,6 @@ var ContactToolsImpl = class {
|
|
|
228
302
|
};
|
|
229
303
|
|
|
230
304
|
// src/runtime/tools/ContactCallbackTools.ts
|
|
231
|
-
function toParticipantRecord(participant) {
|
|
232
|
-
return {
|
|
233
|
-
id: participant.id,
|
|
234
|
-
name: participant.name,
|
|
235
|
-
type: participant.type,
|
|
236
|
-
handle: participant.handle ?? null
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
305
|
function normalizePage(value, fallback) {
|
|
240
306
|
return Number.isInteger(value) && value && value > 0 ? value : fallback;
|
|
241
307
|
}
|
|
@@ -279,8 +345,7 @@ var ContactCallbackTools = class {
|
|
|
279
345
|
{
|
|
280
346
|
content,
|
|
281
347
|
...normalizedMentions ? { mentions: normalizedMentions } : {}
|
|
282
|
-
}
|
|
283
|
-
DEFAULT_REQUEST_OPTIONS
|
|
348
|
+
}
|
|
284
349
|
);
|
|
285
350
|
}
|
|
286
351
|
async sendEvent(content, messageType, metadata) {
|
|
@@ -294,8 +359,7 @@ var ContactCallbackTools = class {
|
|
|
294
359
|
content,
|
|
295
360
|
messageType,
|
|
296
361
|
...metadata ? { metadata } : {}
|
|
297
|
-
}
|
|
298
|
-
DEFAULT_REQUEST_OPTIONS
|
|
362
|
+
}
|
|
299
363
|
);
|
|
300
364
|
}
|
|
301
365
|
async addParticipant() {
|
|
@@ -309,7 +373,7 @@ var ContactCallbackTools = class {
|
|
|
309
373
|
if (!this.rest.listChatParticipants) {
|
|
310
374
|
throw new UnsupportedFeatureError("Participant listing is not available in current REST adapter");
|
|
311
375
|
}
|
|
312
|
-
return (await this.rest.listChatParticipants(roomId, DEFAULT_REQUEST_OPTIONS)).map(
|
|
376
|
+
return (await this.rest.listChatParticipants(roomId, DEFAULT_REQUEST_OPTIONS)).map(toParticipantRecordFromRest);
|
|
313
377
|
}
|
|
314
378
|
async createChatroom(taskId) {
|
|
315
379
|
const chat = await this.rest.createChat(taskId, DEFAULT_REQUEST_OPTIONS);
|
|
@@ -399,48 +463,48 @@ var ContactCallbackTools = class {
|
|
|
399
463
|
}
|
|
400
464
|
async executeToolCall(toolName, toolArgs) {
|
|
401
465
|
switch (toolName) {
|
|
402
|
-
case "
|
|
466
|
+
case "band_send_message":
|
|
403
467
|
return this.sendMessage(
|
|
404
468
|
String(toolArgs.content ?? ""),
|
|
405
469
|
toolArgs.mentions
|
|
406
470
|
);
|
|
407
|
-
case "
|
|
471
|
+
case "band_send_event":
|
|
408
472
|
return this.sendEvent(
|
|
409
473
|
String(toolArgs.content ?? ""),
|
|
410
474
|
String(toolArgs.message_type ?? "task"),
|
|
411
475
|
toolArgs.metadata
|
|
412
476
|
);
|
|
413
|
-
case "
|
|
477
|
+
case "band_get_participants":
|
|
414
478
|
return this.getParticipants();
|
|
415
|
-
case "
|
|
479
|
+
case "band_create_chatroom":
|
|
416
480
|
return this.createChatroom(typeof toolArgs.task_id === "string" ? toolArgs.task_id : void 0);
|
|
417
|
-
case "
|
|
481
|
+
case "band_lookup_peers":
|
|
418
482
|
return this.lookupPeers(
|
|
419
483
|
typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
420
484
|
typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0
|
|
421
485
|
);
|
|
422
|
-
case "
|
|
486
|
+
case "band_list_contacts":
|
|
423
487
|
return this.listContacts({
|
|
424
488
|
page: typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
425
489
|
pageSize: typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0
|
|
426
490
|
});
|
|
427
|
-
case "
|
|
491
|
+
case "band_add_contact":
|
|
428
492
|
return this.addContact({
|
|
429
493
|
handle: String(toolArgs.handle ?? ""),
|
|
430
494
|
...typeof toolArgs.message === "string" ? { message: toolArgs.message } : {}
|
|
431
495
|
});
|
|
432
|
-
case "
|
|
496
|
+
case "band_remove_contact":
|
|
433
497
|
if (typeof toolArgs.contact_id === "string") {
|
|
434
498
|
return this.removeContact({ target: "contactId", contactId: toolArgs.contact_id });
|
|
435
499
|
}
|
|
436
500
|
return this.removeContact({ target: "handle", handle: String(toolArgs.handle ?? "") });
|
|
437
|
-
case "
|
|
501
|
+
case "band_list_contact_requests":
|
|
438
502
|
return this.listContactRequests({
|
|
439
503
|
page: typeof toolArgs.page === "number" ? toolArgs.page : void 0,
|
|
440
504
|
pageSize: typeof toolArgs.page_size === "number" ? toolArgs.page_size : void 0,
|
|
441
505
|
sentStatus: typeof toolArgs.sent_status === "string" ? toolArgs.sent_status : void 0
|
|
442
506
|
});
|
|
443
|
-
case "
|
|
507
|
+
case "band_respond_contact_request":
|
|
444
508
|
if (typeof toolArgs.request_id === "string") {
|
|
445
509
|
return this.respondContactRequest({
|
|
446
510
|
action: String(toolArgs.action ?? "approve"),
|
|
@@ -453,15 +517,15 @@ var ContactCallbackTools = class {
|
|
|
453
517
|
target: "handle",
|
|
454
518
|
handle: String(toolArgs.handle ?? "")
|
|
455
519
|
});
|
|
456
|
-
case "
|
|
520
|
+
case "band_list_memories":
|
|
457
521
|
return this.listMemories(toolArgs);
|
|
458
|
-
case "
|
|
522
|
+
case "band_store_memory":
|
|
459
523
|
return this.storeMemory(toolArgs);
|
|
460
|
-
case "
|
|
524
|
+
case "band_get_memory":
|
|
461
525
|
return this.getMemory(String(toolArgs.memory_id ?? ""));
|
|
462
|
-
case "
|
|
526
|
+
case "band_supersede_memory":
|
|
463
527
|
return this.supersedeMemory(String(toolArgs.memory_id ?? ""));
|
|
464
|
-
case "
|
|
528
|
+
case "band_archive_memory":
|
|
465
529
|
return this.archiveMemory(String(toolArgs.memory_id ?? ""));
|
|
466
530
|
default:
|
|
467
531
|
throw new UnsupportedFeatureError(`Unsupported tool call for contact callback: ${toolName}`);
|
|
@@ -475,14 +539,14 @@ var HUB_ROOM_SYSTEM_PROMPT = `## OVERRIDE: Contact Management Mode
|
|
|
475
539
|
|
|
476
540
|
This is your CONTACTS HUB - a dedicated room for managing contact requests.
|
|
477
541
|
|
|
478
|
-
**IMPORTANT: Do NOT delegate or add participants here.** You handle contact events DIRECTLY using the contact tools below. Do NOT call
|
|
542
|
+
**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.
|
|
479
543
|
|
|
480
544
|
## Your Role
|
|
481
545
|
|
|
482
546
|
1. **Review incoming contact requests** - When you see a [Contact Request] message, evaluate it
|
|
483
547
|
2. **Take action** - Use the contact tools to respond:
|
|
484
|
-
- \`
|
|
485
|
-
- \`
|
|
548
|
+
- \`band_respond_contact_request(action="approve", request_id="...")\` to accept
|
|
549
|
+
- \`band_respond_contact_request(action="reject", request_id="...")\` to decline
|
|
486
550
|
3. **Report your decision** - Send a thought event explaining what you did
|
|
487
551
|
|
|
488
552
|
## Example
|
|
@@ -491,14 +555,14 @@ This is your CONTACTS HUB - a dedicated room for managing contact requests.
|
|
|
491
555
|
Request ID: abc-123
|
|
492
556
|
|
|
493
557
|
Your response:
|
|
494
|
-
1.
|
|
495
|
-
2.
|
|
496
|
-
3.
|
|
558
|
+
1. band_send_event("Received contact request from Alice. Approving.", message_type="thought")
|
|
559
|
+
2. band_respond_contact_request(action="approve", request_id="abc-123")
|
|
560
|
+
3. band_send_event("Approved contact request from Alice (@alice)", message_type="thought")
|
|
497
561
|
|
|
498
562
|
## Contact Tools (use these, NOT participant tools)
|
|
499
|
-
- \`
|
|
500
|
-
- \`
|
|
501
|
-
- \`
|
|
563
|
+
- \`band_respond_contact_request(action, request_id)\` - Approve/reject requests
|
|
564
|
+
- \`band_list_contact_requests()\` - List pending requests
|
|
565
|
+
- \`band_list_contacts()\` - List current contacts`;
|
|
502
566
|
var ContactEventHandlerError = class extends Error {
|
|
503
567
|
retryable;
|
|
504
568
|
stage;
|
|
@@ -1118,6 +1182,9 @@ var Execution = class {
|
|
|
1118
1182
|
}
|
|
1119
1183
|
};
|
|
1120
1184
|
|
|
1185
|
+
// src/runtime/tools/AgentTools.ts
|
|
1186
|
+
var import_band_sdk_core = require("@band-ai/band-sdk-core");
|
|
1187
|
+
|
|
1121
1188
|
// src/contracts/capabilities.ts
|
|
1122
1189
|
var CAPABILITY_LABELS = {
|
|
1123
1190
|
peers: "Peer lookup",
|
|
@@ -1234,9 +1301,9 @@ var MEMORY_STATUSES = [
|
|
|
1234
1301
|
"active",
|
|
1235
1302
|
// Normal, visible memories
|
|
1236
1303
|
"superseded",
|
|
1237
|
-
// Outdated; soft-deleted via
|
|
1304
|
+
// Outdated; soft-deleted via band_supersede_memory
|
|
1238
1305
|
"archived",
|
|
1239
|
-
// Hidden but preserved via
|
|
1306
|
+
// Hidden but preserved via band_archive_memory
|
|
1240
1307
|
"all"
|
|
1241
1308
|
// Any status (no filter)
|
|
1242
1309
|
];
|
|
@@ -1277,7 +1344,7 @@ function memoryTypeForSystemError(system) {
|
|
|
1277
1344
|
|
|
1278
1345
|
// src/runtime/tools/schemas.ts
|
|
1279
1346
|
var TOOL_MODELS = {
|
|
1280
|
-
|
|
1347
|
+
band_send_message: {
|
|
1281
1348
|
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.",
|
|
1282
1349
|
properties: {
|
|
1283
1350
|
content: {
|
|
@@ -1293,7 +1360,7 @@ var TOOL_MODELS = {
|
|
|
1293
1360
|
},
|
|
1294
1361
|
required: ["content", "mentions"]
|
|
1295
1362
|
},
|
|
1296
|
-
|
|
1363
|
+
band_send_event: {
|
|
1297
1364
|
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.",
|
|
1298
1365
|
properties: {
|
|
1299
1366
|
content: {
|
|
@@ -1312,12 +1379,12 @@ var TOOL_MODELS = {
|
|
|
1312
1379
|
},
|
|
1313
1380
|
required: ["content", "message_type"]
|
|
1314
1381
|
},
|
|
1315
|
-
|
|
1316
|
-
description: "Add a participant (agent or user) to the chat room by name. IMPORTANT: Use
|
|
1382
|
+
band_add_participant: {
|
|
1383
|
+
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'.",
|
|
1317
1384
|
properties: {
|
|
1318
1385
|
name: {
|
|
1319
1386
|
type: "string",
|
|
1320
|
-
description: "Name of participant to add (must match a name from
|
|
1387
|
+
description: "Name of participant to add (must match a name from band_lookup_peers)."
|
|
1321
1388
|
},
|
|
1322
1389
|
role: {
|
|
1323
1390
|
type: "string",
|
|
@@ -1327,7 +1394,7 @@ var TOOL_MODELS = {
|
|
|
1327
1394
|
},
|
|
1328
1395
|
required: ["name"]
|
|
1329
1396
|
},
|
|
1330
|
-
|
|
1397
|
+
band_remove_participant: {
|
|
1331
1398
|
description: "Remove a participant from the chat room by name.",
|
|
1332
1399
|
properties: {
|
|
1333
1400
|
name: {
|
|
@@ -1337,12 +1404,12 @@ var TOOL_MODELS = {
|
|
|
1337
1404
|
},
|
|
1338
1405
|
required: ["name"]
|
|
1339
1406
|
},
|
|
1340
|
-
|
|
1407
|
+
band_get_participants: {
|
|
1341
1408
|
description: "Get a list of all participants in the current chat room.",
|
|
1342
1409
|
properties: {},
|
|
1343
1410
|
required: []
|
|
1344
1411
|
},
|
|
1345
|
-
|
|
1412
|
+
band_lookup_peers: {
|
|
1346
1413
|
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.",
|
|
1347
1414
|
properties: {
|
|
1348
1415
|
page: {
|
|
@@ -1357,7 +1424,7 @@ var TOOL_MODELS = {
|
|
|
1357
1424
|
},
|
|
1358
1425
|
required: []
|
|
1359
1426
|
},
|
|
1360
|
-
|
|
1427
|
+
band_create_chatroom: {
|
|
1361
1428
|
description: "Create a new chat room for a specific task or conversation.",
|
|
1362
1429
|
properties: {
|
|
1363
1430
|
task_id: {
|
|
@@ -1367,7 +1434,7 @@ var TOOL_MODELS = {
|
|
|
1367
1434
|
},
|
|
1368
1435
|
required: []
|
|
1369
1436
|
},
|
|
1370
|
-
|
|
1437
|
+
band_list_contacts: {
|
|
1371
1438
|
description: "List agent's contacts with pagination.",
|
|
1372
1439
|
properties: {
|
|
1373
1440
|
page: {
|
|
@@ -1384,7 +1451,7 @@ var TOOL_MODELS = {
|
|
|
1384
1451
|
},
|
|
1385
1452
|
required: []
|
|
1386
1453
|
},
|
|
1387
|
-
|
|
1454
|
+
band_add_contact: {
|
|
1388
1455
|
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.",
|
|
1389
1456
|
properties: {
|
|
1390
1457
|
handle: {
|
|
@@ -1398,7 +1465,7 @@ var TOOL_MODELS = {
|
|
|
1398
1465
|
},
|
|
1399
1466
|
required: ["handle"]
|
|
1400
1467
|
},
|
|
1401
|
-
|
|
1468
|
+
band_remove_contact: {
|
|
1402
1469
|
description: "Remove an existing contact by handle or ID.",
|
|
1403
1470
|
properties: {
|
|
1404
1471
|
handle: {
|
|
@@ -1412,7 +1479,7 @@ var TOOL_MODELS = {
|
|
|
1412
1479
|
},
|
|
1413
1480
|
required: []
|
|
1414
1481
|
},
|
|
1415
|
-
|
|
1482
|
+
band_list_contact_requests: {
|
|
1416
1483
|
description: "List both received and sent contact requests. Received requests are always filtered to pending status. Sent requests can be filtered by status.",
|
|
1417
1484
|
properties: {
|
|
1418
1485
|
page: {
|
|
@@ -1434,7 +1501,7 @@ var TOOL_MODELS = {
|
|
|
1434
1501
|
},
|
|
1435
1502
|
required: []
|
|
1436
1503
|
},
|
|
1437
|
-
|
|
1504
|
+
band_respond_contact_request: {
|
|
1438
1505
|
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).",
|
|
1439
1506
|
properties: {
|
|
1440
1507
|
action: {
|
|
@@ -1453,7 +1520,7 @@ var TOOL_MODELS = {
|
|
|
1453
1520
|
},
|
|
1454
1521
|
required: ["action"]
|
|
1455
1522
|
},
|
|
1456
|
-
|
|
1523
|
+
band_list_memories: {
|
|
1457
1524
|
description: "List memories accessible to the agent. Returns memories about the specified subject (cross-agent sharing) and organization-wide shared memories.",
|
|
1458
1525
|
properties: {
|
|
1459
1526
|
subject_id: {
|
|
@@ -1498,7 +1565,7 @@ var TOOL_MODELS = {
|
|
|
1498
1565
|
},
|
|
1499
1566
|
required: []
|
|
1500
1567
|
},
|
|
1501
|
-
|
|
1568
|
+
band_store_memory: {
|
|
1502
1569
|
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.",
|
|
1503
1570
|
properties: {
|
|
1504
1571
|
content: {
|
|
@@ -1540,7 +1607,7 @@ var TOOL_MODELS = {
|
|
|
1540
1607
|
},
|
|
1541
1608
|
required: ["content", "system", "type", "segment", "thought"]
|
|
1542
1609
|
},
|
|
1543
|
-
|
|
1610
|
+
band_get_memory: {
|
|
1544
1611
|
description: "Retrieve a specific memory by ID.",
|
|
1545
1612
|
properties: {
|
|
1546
1613
|
memory_id: {
|
|
@@ -1550,7 +1617,7 @@ var TOOL_MODELS = {
|
|
|
1550
1617
|
},
|
|
1551
1618
|
required: ["memory_id"]
|
|
1552
1619
|
},
|
|
1553
|
-
|
|
1620
|
+
band_supersede_memory: {
|
|
1554
1621
|
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.",
|
|
1555
1622
|
properties: {
|
|
1556
1623
|
memory_id: {
|
|
@@ -1560,7 +1627,7 @@ var TOOL_MODELS = {
|
|
|
1560
1627
|
},
|
|
1561
1628
|
required: ["memory_id"]
|
|
1562
1629
|
},
|
|
1563
|
-
|
|
1630
|
+
band_archive_memory: {
|
|
1564
1631
|
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.",
|
|
1565
1632
|
properties: {
|
|
1566
1633
|
memory_id: {
|
|
@@ -1573,18 +1640,18 @@ var TOOL_MODELS = {
|
|
|
1573
1640
|
};
|
|
1574
1641
|
var ALL_TOOL_NAMES = new Set(Object.keys(TOOL_MODELS));
|
|
1575
1642
|
var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1576
|
-
"
|
|
1577
|
-
"
|
|
1578
|
-
"
|
|
1579
|
-
"
|
|
1580
|
-
"
|
|
1643
|
+
"band_list_memories",
|
|
1644
|
+
"band_store_memory",
|
|
1645
|
+
"band_get_memory",
|
|
1646
|
+
"band_supersede_memory",
|
|
1647
|
+
"band_archive_memory"
|
|
1581
1648
|
]);
|
|
1582
1649
|
var CONTACT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1583
|
-
"
|
|
1584
|
-
"
|
|
1585
|
-
"
|
|
1586
|
-
"
|
|
1587
|
-
"
|
|
1650
|
+
"band_list_contacts",
|
|
1651
|
+
"band_add_contact",
|
|
1652
|
+
"band_remove_contact",
|
|
1653
|
+
"band_list_contact_requests",
|
|
1654
|
+
"band_respond_contact_request"
|
|
1588
1655
|
]);
|
|
1589
1656
|
var BASE_TOOL_NAMES = new Set(
|
|
1590
1657
|
[...ALL_TOOL_NAMES].filter((name) => !MEMORY_TOOL_NAMES.has(name))
|
|
@@ -1592,7 +1659,8 @@ var BASE_TOOL_NAMES = new Set(
|
|
|
1592
1659
|
var CHAT_TOOL_NAMES = new Set(
|
|
1593
1660
|
[...BASE_TOOL_NAMES].filter((name) => !CONTACT_TOOL_NAMES.has(name))
|
|
1594
1661
|
);
|
|
1595
|
-
var MCP_TOOL_PREFIX = "
|
|
1662
|
+
var MCP_TOOL_PREFIX = "mcp__band__";
|
|
1663
|
+
var MCP_SERVER_NAME = "band";
|
|
1596
1664
|
function mcpToolNames(names) {
|
|
1597
1665
|
return [...names].sort((a, b) => a.localeCompare(b)).map((name) => `${MCP_TOOL_PREFIX}${name}`);
|
|
1598
1666
|
}
|
|
@@ -1640,13 +1708,13 @@ var AgentTools = class {
|
|
|
1640
1708
|
roomId;
|
|
1641
1709
|
capabilities;
|
|
1642
1710
|
rest;
|
|
1643
|
-
|
|
1711
|
+
roster;
|
|
1644
1712
|
adapterTools;
|
|
1645
1713
|
toolHandlers;
|
|
1646
1714
|
constructor(options) {
|
|
1647
1715
|
this.roomId = options.roomId;
|
|
1648
1716
|
this.rest = options.rest;
|
|
1649
|
-
this.
|
|
1717
|
+
this.roster = options.roster ?? new import_band_sdk_core.ParticipantRoster();
|
|
1650
1718
|
this.capabilities = {
|
|
1651
1719
|
...DEFAULT_AGENT_TOOLS_CAPABILITIES,
|
|
1652
1720
|
...options.capabilities
|
|
@@ -1658,17 +1726,20 @@ var AgentTools = class {
|
|
|
1658
1726
|
return this.adapterTools;
|
|
1659
1727
|
}
|
|
1660
1728
|
async sendMessage(content, mentions = []) {
|
|
1661
|
-
|
|
1662
|
-
|
|
1729
|
+
let participants;
|
|
1730
|
+
if (mentions.length > 0 && typeof mentions[0] === "string") {
|
|
1731
|
+
participants = this.roster.list();
|
|
1732
|
+
if (participants.length === 0) {
|
|
1733
|
+
participants = await this.syncParticipants();
|
|
1734
|
+
}
|
|
1663
1735
|
}
|
|
1664
|
-
const resolvedMentions = this.resolveMentions(mentions);
|
|
1736
|
+
const resolvedMentions = this.resolveMentions(mentions, participants);
|
|
1665
1737
|
return this.rest.createChatMessage(
|
|
1666
1738
|
this.roomId,
|
|
1667
1739
|
{
|
|
1668
1740
|
content,
|
|
1669
1741
|
mentions: resolvedMentions
|
|
1670
|
-
}
|
|
1671
|
-
DEFAULT_REQUEST_OPTIONS
|
|
1742
|
+
}
|
|
1672
1743
|
);
|
|
1673
1744
|
}
|
|
1674
1745
|
async sendEvent(content, messageType, metadata) {
|
|
@@ -1679,8 +1750,7 @@ var AgentTools = class {
|
|
|
1679
1750
|
content,
|
|
1680
1751
|
messageType,
|
|
1681
1752
|
metadata
|
|
1682
|
-
}
|
|
1683
|
-
DEFAULT_REQUEST_OPTIONS
|
|
1753
|
+
}
|
|
1684
1754
|
);
|
|
1685
1755
|
}
|
|
1686
1756
|
async createChatroom(taskId) {
|
|
@@ -1719,7 +1789,7 @@ var AgentTools = class {
|
|
|
1719
1789
|
type: String(peer.type ?? "Agent"),
|
|
1720
1790
|
handle: typeof peer.handle === "string" ? peer.handle : null
|
|
1721
1791
|
};
|
|
1722
|
-
this.
|
|
1792
|
+
this.roster.add(participantRecord);
|
|
1723
1793
|
return {
|
|
1724
1794
|
...participantRecord,
|
|
1725
1795
|
status: "added"
|
|
@@ -1734,7 +1804,7 @@ var AgentTools = class {
|
|
|
1734
1804
|
throw new ValidationError(`Participant '${name}' not found in room`);
|
|
1735
1805
|
}
|
|
1736
1806
|
await this.rest.removeChatParticipant(this.roomId, String(participant.id), DEFAULT_REQUEST_OPTIONS);
|
|
1737
|
-
this.
|
|
1807
|
+
this.roster.remove(participant.id);
|
|
1738
1808
|
return {
|
|
1739
1809
|
id: participant.id,
|
|
1740
1810
|
name,
|
|
@@ -1762,17 +1832,12 @@ var AgentTools = class {
|
|
|
1762
1832
|
}
|
|
1763
1833
|
async fetchParticipants() {
|
|
1764
1834
|
const participants = await this.rest.listChatParticipants(this.roomId, DEFAULT_REQUEST_OPTIONS);
|
|
1765
|
-
return participants.map(
|
|
1766
|
-
id: participant.id,
|
|
1767
|
-
name: participant.name,
|
|
1768
|
-
type: participant.type,
|
|
1769
|
-
handle: participant.handle ?? null
|
|
1770
|
-
}));
|
|
1835
|
+
return participants.map(toParticipantRecordFromRest);
|
|
1771
1836
|
}
|
|
1772
1837
|
async syncParticipants() {
|
|
1773
1838
|
const participants = await this.fetchParticipants();
|
|
1774
|
-
this.
|
|
1775
|
-
return
|
|
1839
|
+
this.roster.setAll(participants);
|
|
1840
|
+
return this.roster.list().map(toParticipantRecord);
|
|
1776
1841
|
}
|
|
1777
1842
|
async executeToolCall(toolName, arguments_) {
|
|
1778
1843
|
const validationError = validateToolArgs(toolName, arguments_);
|
|
@@ -1820,7 +1885,7 @@ var AgentTools = class {
|
|
|
1820
1885
|
if (!CHAT_TOOL_NAMES.has(name) && !this.capabilities.contacts) {
|
|
1821
1886
|
return false;
|
|
1822
1887
|
}
|
|
1823
|
-
if (name === "
|
|
1888
|
+
if (name === "band_lookup_peers" && !this.capabilities.peers) {
|
|
1824
1889
|
return false;
|
|
1825
1890
|
}
|
|
1826
1891
|
return true;
|
|
@@ -2015,7 +2080,7 @@ var AgentTools = class {
|
|
|
2015
2080
|
}
|
|
2016
2081
|
return this.rest.archiveMemory(normalizedMemoryId, DEFAULT_REQUEST_OPTIONS);
|
|
2017
2082
|
}
|
|
2018
|
-
resolveMentions(mentions) {
|
|
2083
|
+
resolveMentions(mentions, participants) {
|
|
2019
2084
|
if (mentions.length === 0) {
|
|
2020
2085
|
return [];
|
|
2021
2086
|
}
|
|
@@ -2028,7 +2093,7 @@ var AgentTools = class {
|
|
|
2028
2093
|
const participantsByHandle = /* @__PURE__ */ new Map();
|
|
2029
2094
|
const participantsById = /* @__PURE__ */ new Map();
|
|
2030
2095
|
const participantsByName = /* @__PURE__ */ new Map();
|
|
2031
|
-
for (const participant of
|
|
2096
|
+
for (const participant of participants ?? []) {
|
|
2032
2097
|
const ref = {
|
|
2033
2098
|
id: String(participant.id),
|
|
2034
2099
|
handle: typeof participant.handle === "string" ? participant.handle : void 0
|
|
@@ -2084,9 +2149,6 @@ var AgentTools = class {
|
|
|
2084
2149
|
normalizeMentionHandle(handle) {
|
|
2085
2150
|
return handle.trim().replace(/^@+/, "").toLowerCase();
|
|
2086
2151
|
}
|
|
2087
|
-
replaceParticipants(participants) {
|
|
2088
|
-
this.participants.splice(0, this.participants.length, ...participants);
|
|
2089
|
-
}
|
|
2090
2152
|
buildAdapterTools() {
|
|
2091
2153
|
const tools = {
|
|
2092
2154
|
capabilities: this.capabilities
|
|
@@ -2117,51 +2179,51 @@ var AgentTools = class {
|
|
|
2117
2179
|
}
|
|
2118
2180
|
buildMessagingToolHandlers() {
|
|
2119
2181
|
return {
|
|
2120
|
-
|
|
2182
|
+
band_send_message: async (arguments_) => this.sendMessage(
|
|
2121
2183
|
String(arguments_.content ?? ""),
|
|
2122
2184
|
this.normalizeMentionInput(arguments_.mentions)
|
|
2123
2185
|
),
|
|
2124
|
-
|
|
2186
|
+
band_send_event: async (arguments_) => this.sendEvent(
|
|
2125
2187
|
String(arguments_.content ?? ""),
|
|
2126
2188
|
String(arguments_.message_type ?? "task"),
|
|
2127
2189
|
this.normalizeOptionalMetadata(arguments_.metadata)
|
|
2128
2190
|
),
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2191
|
+
band_add_participant: async (arguments_) => this.addParticipant(String(arguments_.name ?? ""), String(arguments_.role ?? "member")),
|
|
2192
|
+
band_remove_participant: async (arguments_) => this.removeParticipant(String(arguments_.name ?? "")),
|
|
2193
|
+
band_lookup_peers: async (arguments_) => this.lookupPeers(
|
|
2132
2194
|
coercePositiveInt(arguments_.page, 1),
|
|
2133
2195
|
coercePositiveInt(arguments_.page_size, 50)
|
|
2134
2196
|
),
|
|
2135
|
-
|
|
2136
|
-
|
|
2197
|
+
band_get_participants: async () => this.getParticipants(),
|
|
2198
|
+
band_create_chatroom: async (arguments_) => this.createChatroom(this.normalizeOptionalString(arguments_.task_id))
|
|
2137
2199
|
};
|
|
2138
2200
|
}
|
|
2139
2201
|
buildContactToolHandlers() {
|
|
2140
2202
|
return {
|
|
2141
|
-
|
|
2203
|
+
band_list_contacts: async (arguments_) => this.listContacts({
|
|
2142
2204
|
page: coercePositiveInt(arguments_.page, 1),
|
|
2143
2205
|
pageSize: coercePositiveInt(arguments_.page_size, 50)
|
|
2144
2206
|
}),
|
|
2145
|
-
|
|
2207
|
+
band_add_contact: async (arguments_) => this.addContact({
|
|
2146
2208
|
handle: String(arguments_.handle ?? ""),
|
|
2147
2209
|
...typeof arguments_.message === "string" ? { message: arguments_.message } : {}
|
|
2148
2210
|
}),
|
|
2149
|
-
|
|
2150
|
-
|
|
2211
|
+
band_remove_contact: async (arguments_) => this.removeContact(this.toRemoveContactArgs(arguments_)),
|
|
2212
|
+
band_list_contact_requests: async (arguments_) => this.listContactRequests({
|
|
2151
2213
|
page: coercePositiveInt(arguments_.page, 1),
|
|
2152
2214
|
pageSize: coercePositiveInt(arguments_.page_size, 50),
|
|
2153
2215
|
sentStatus: String(arguments_.sent_status ?? "pending")
|
|
2154
2216
|
}),
|
|
2155
|
-
|
|
2217
|
+
band_respond_contact_request: async (arguments_) => this.respondContactRequest(this.toRespondContactRequestArgs(arguments_))
|
|
2156
2218
|
};
|
|
2157
2219
|
}
|
|
2158
2220
|
buildMemoryToolHandlers() {
|
|
2159
2221
|
return {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2222
|
+
band_list_memories: async (arguments_) => this.listMemories(this.toListMemoriesArgs(arguments_)),
|
|
2223
|
+
band_store_memory: async (arguments_) => this.storeMemory(this.toStoreMemoryArgs(arguments_)),
|
|
2224
|
+
band_get_memory: async (arguments_) => this.getMemory(String(arguments_.memory_id ?? "")),
|
|
2225
|
+
band_supersede_memory: async (arguments_) => this.supersedeMemory(String(arguments_.memory_id ?? "")),
|
|
2226
|
+
band_archive_memory: async (arguments_) => this.archiveMemory(String(arguments_.memory_id ?? ""))
|
|
2165
2227
|
};
|
|
2166
2228
|
}
|
|
2167
2229
|
toRemoveContactArgs(arguments_) {
|
|
@@ -2405,13 +2467,13 @@ function validateToolArgs(toolName, args) {
|
|
|
2405
2467
|
errors.push(`${field}: Field required`);
|
|
2406
2468
|
}
|
|
2407
2469
|
}
|
|
2408
|
-
if (toolName === "
|
|
2470
|
+
if (toolName === "band_send_message") {
|
|
2409
2471
|
const mentions = args.mentions;
|
|
2410
2472
|
if (Array.isArray(mentions) && mentions.length === 0) {
|
|
2411
2473
|
errors.push("mentions: At least one mention is required");
|
|
2412
2474
|
}
|
|
2413
2475
|
}
|
|
2414
|
-
if (toolName === "
|
|
2476
|
+
if (toolName === "band_send_event") {
|
|
2415
2477
|
const messageType = args.message_type;
|
|
2416
2478
|
if (typeof messageType === "string" && !CHAT_EVENT_TYPES.includes(messageType)) {
|
|
2417
2479
|
errors.push(
|
|
@@ -2419,7 +2481,7 @@ function validateToolArgs(toolName, args) {
|
|
|
2419
2481
|
);
|
|
2420
2482
|
}
|
|
2421
2483
|
}
|
|
2422
|
-
if (toolName === "
|
|
2484
|
+
if (toolName === "band_respond_contact_request") {
|
|
2423
2485
|
const action = args.action;
|
|
2424
2486
|
const validActions = ["approve", "reject", "cancel"];
|
|
2425
2487
|
if (typeof action === "string" && !validActions.includes(action)) {
|
|
@@ -2428,7 +2490,7 @@ function validateToolArgs(toolName, args) {
|
|
|
2428
2490
|
);
|
|
2429
2491
|
}
|
|
2430
2492
|
}
|
|
2431
|
-
if (toolName === "
|
|
2493
|
+
if (toolName === "band_store_memory") {
|
|
2432
2494
|
if (typeof args.system === "string" && !isMemorySystem(args.system)) {
|
|
2433
2495
|
errors.push(`system: Invalid value '${args.system}'. Expected one of: ${expectedList(MEMORY_SYSTEMS)}`);
|
|
2434
2496
|
}
|
|
@@ -2457,114 +2519,8 @@ function validateToolArgs(toolName, args) {
|
|
|
2457
2519
|
return null;
|
|
2458
2520
|
}
|
|
2459
2521
|
|
|
2460
|
-
// src/runtime/retryTracker.ts
|
|
2461
|
-
var DEFAULT_MAX_TRACKED = 1e4;
|
|
2462
|
-
var MessageRetryTracker = class {
|
|
2463
|
-
maxRetriesValue;
|
|
2464
|
-
maxTracked;
|
|
2465
|
-
attempts = /* @__PURE__ */ new Map();
|
|
2466
|
-
failed = /* @__PURE__ */ new Set();
|
|
2467
|
-
constructor(maxRetries = 1, maxTracked = DEFAULT_MAX_TRACKED) {
|
|
2468
|
-
this.maxRetriesValue = maxRetries;
|
|
2469
|
-
this.maxTracked = maxTracked;
|
|
2470
|
-
}
|
|
2471
|
-
get maxRetries() {
|
|
2472
|
-
return this.maxRetriesValue;
|
|
2473
|
-
}
|
|
2474
|
-
isPermanentlyFailed(messageId) {
|
|
2475
|
-
return this.failed.has(messageId);
|
|
2476
|
-
}
|
|
2477
|
-
recordAttempt(messageId) {
|
|
2478
|
-
const attempts = (this.attempts.get(messageId) ?? 0) + 1;
|
|
2479
|
-
this.attempts.set(messageId, attempts);
|
|
2480
|
-
const exceeded = attempts > this.maxRetriesValue;
|
|
2481
|
-
if (exceeded) {
|
|
2482
|
-
this.evictSetIfNeeded(this.failed);
|
|
2483
|
-
this.failed.add(messageId);
|
|
2484
|
-
}
|
|
2485
|
-
this.evictMapIfNeeded(this.attempts);
|
|
2486
|
-
return [attempts, exceeded];
|
|
2487
|
-
}
|
|
2488
|
-
markSuccess(messageId) {
|
|
2489
|
-
this.attempts.delete(messageId);
|
|
2490
|
-
}
|
|
2491
|
-
markPermanentlyFailed(messageId) {
|
|
2492
|
-
this.evictSetIfNeeded(this.failed);
|
|
2493
|
-
this.failed.add(messageId);
|
|
2494
|
-
}
|
|
2495
|
-
evictMapIfNeeded(map) {
|
|
2496
|
-
while (map.size >= this.maxTracked) {
|
|
2497
|
-
const first = map.keys().next();
|
|
2498
|
-
if (first.done) break;
|
|
2499
|
-
map.delete(first.value);
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
evictSetIfNeeded(set) {
|
|
2503
|
-
while (set.size >= this.maxTracked) {
|
|
2504
|
-
const first = set.values().next();
|
|
2505
|
-
if (first.done) break;
|
|
2506
|
-
set.delete(first.value);
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
};
|
|
2510
|
-
|
|
2511
|
-
// src/runtime/formatters.ts
|
|
2512
|
-
function isMetadataMap(value) {
|
|
2513
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2514
|
-
}
|
|
2515
|
-
function replaceUuidMentions(content, participants) {
|
|
2516
|
-
if (!content || participants.length === 0) {
|
|
2517
|
-
return content;
|
|
2518
|
-
}
|
|
2519
|
-
let next = content;
|
|
2520
|
-
for (const participant of participants) {
|
|
2521
|
-
const participantId = participant.id;
|
|
2522
|
-
const handle = participant.handle;
|
|
2523
|
-
if (typeof participantId === "string" && typeof handle === "string") {
|
|
2524
|
-
next = next.replaceAll(`@[[${participantId}]]`, ensureHandlePrefix(handle) ?? "");
|
|
2525
|
-
}
|
|
2526
|
-
}
|
|
2527
|
-
return next;
|
|
2528
|
-
}
|
|
2529
|
-
function formatMessageForLlm(message, participants) {
|
|
2530
|
-
const senderType = String(message.sender_type ?? "");
|
|
2531
|
-
const senderName = String(message.sender_name ?? message.name ?? senderType);
|
|
2532
|
-
const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
|
|
2533
|
-
return {
|
|
2534
|
-
role: senderType === "Agent" ? "assistant" : "user",
|
|
2535
|
-
content,
|
|
2536
|
-
sender_name: senderName,
|
|
2537
|
-
sender_type: senderType,
|
|
2538
|
-
message_type: String(message.message_type ?? "text"),
|
|
2539
|
-
metadata: isMetadataMap(message.metadata) ? message.metadata : {}
|
|
2540
|
-
};
|
|
2541
|
-
}
|
|
2542
|
-
function formatHistoryForLlm(messages, options) {
|
|
2543
|
-
const excludeId = options?.excludeId;
|
|
2544
|
-
const participants = options?.participants;
|
|
2545
|
-
return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
|
|
2546
|
-
}
|
|
2547
|
-
function buildParticipantsMessage(participants) {
|
|
2548
|
-
if (participants.length === 0) {
|
|
2549
|
-
return "## Current Participants\nNo other participants in this room.";
|
|
2550
|
-
}
|
|
2551
|
-
const lines = ["## Current Participants"];
|
|
2552
|
-
for (const participant of participants) {
|
|
2553
|
-
const participantType = String(participant.type ?? "Unknown");
|
|
2554
|
-
const participantName = String(participant.name ?? "Unknown");
|
|
2555
|
-
const participantHandle = String(participant.handle ?? "Unknown");
|
|
2556
|
-
lines.push(
|
|
2557
|
-
`- ${ensureHandlePrefix(participantHandle) ?? ""} \u2014 ${participantName} (${participantType})`
|
|
2558
|
-
);
|
|
2559
|
-
}
|
|
2560
|
-
lines.push("");
|
|
2561
|
-
lines.push(
|
|
2562
|
-
"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."
|
|
2563
|
-
);
|
|
2564
|
-
return lines.join("\n");
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
2522
|
// src/runtime/ExecutionContext.ts
|
|
2523
|
+
var import_band_sdk_core2 = require("@band-ai/band-sdk-core");
|
|
2568
2524
|
var DEDUP_CACHE_MAX = 500;
|
|
2569
2525
|
var ExecutionContext = class {
|
|
2570
2526
|
roomId;
|
|
@@ -2576,11 +2532,10 @@ var ExecutionContext = class {
|
|
|
2576
2532
|
history = [];
|
|
2577
2533
|
messageIds = /* @__PURE__ */ new Set();
|
|
2578
2534
|
dedupCache = /* @__PURE__ */ new Map();
|
|
2579
|
-
|
|
2535
|
+
roster = new import_band_sdk_core2.ParticipantRoster();
|
|
2580
2536
|
tools;
|
|
2581
2537
|
adapterTools;
|
|
2582
2538
|
participantsMessage = null;
|
|
2583
|
-
lastSentParticipantIds = null;
|
|
2584
2539
|
contactsMessage = null;
|
|
2585
2540
|
contextCache = null;
|
|
2586
2541
|
contextCacheExpiresAt = 0;
|
|
@@ -2595,11 +2550,11 @@ var ExecutionContext = class {
|
|
|
2595
2550
|
this.enableContextCache = options.enableContextCache ?? true;
|
|
2596
2551
|
this.contextCacheTtlMs = Math.max(0, (options.contextCacheTtlSeconds ?? 300) * 1e3);
|
|
2597
2552
|
this.enableContextHydration = options.enableContextHydration ?? true;
|
|
2598
|
-
this.retryTrackerInstance = new
|
|
2553
|
+
this.retryTrackerInstance = new import_band_sdk_core2.RetryTracker(options.maxMessageRetries ?? 1);
|
|
2599
2554
|
this.tools = new AgentTools({
|
|
2600
2555
|
roomId: this.roomId,
|
|
2601
2556
|
rest: this.link.rest,
|
|
2602
|
-
|
|
2557
|
+
roster: this.roster,
|
|
2603
2558
|
capabilities: this.link.capabilities
|
|
2604
2559
|
});
|
|
2605
2560
|
this.adapterTools = this.tools.getAdapterTools();
|
|
@@ -2667,23 +2622,20 @@ var ExecutionContext = class {
|
|
|
2667
2622
|
}));
|
|
2668
2623
|
}
|
|
2669
2624
|
setParticipants(participants) {
|
|
2670
|
-
this.
|
|
2625
|
+
this.roster.setAll(participants);
|
|
2671
2626
|
this.updateCachedParticipants();
|
|
2672
2627
|
}
|
|
2673
2628
|
addParticipant(participant) {
|
|
2674
|
-
const
|
|
2675
|
-
if (
|
|
2676
|
-
|
|
2629
|
+
const isNew = this.roster.add(participant);
|
|
2630
|
+
if (isNew) {
|
|
2631
|
+
const name = String(participant.name ?? "unknown");
|
|
2632
|
+
this.participantsMessage = `${name} joined the room.`;
|
|
2677
2633
|
}
|
|
2678
|
-
this.participants.push(participant);
|
|
2679
|
-
const name = String(participant.name ?? "unknown");
|
|
2680
|
-
this.participantsMessage = `${name} joined the room.`;
|
|
2681
2634
|
this.updateCachedParticipants();
|
|
2682
2635
|
}
|
|
2683
2636
|
removeParticipant(participantId) {
|
|
2684
|
-
const removed = this.
|
|
2685
|
-
|
|
2686
|
-
this.replaceParticipants(next);
|
|
2637
|
+
const removed = this.roster.list().find((entry) => entry.id === participantId);
|
|
2638
|
+
this.roster.remove(participantId);
|
|
2687
2639
|
if (removed) {
|
|
2688
2640
|
this.participantsMessage = `${String(removed.name ?? participantId)} left the room.`;
|
|
2689
2641
|
}
|
|
@@ -2693,16 +2645,7 @@ var ExecutionContext = class {
|
|
|
2693
2645
|
this.contactsMessage = message;
|
|
2694
2646
|
}
|
|
2695
2647
|
consumeParticipantsMessage() {
|
|
2696
|
-
const
|
|
2697
|
-
let changed = !this.lastSentParticipantIds || currentIds.size !== this.lastSentParticipantIds.size;
|
|
2698
|
-
if (!changed) {
|
|
2699
|
-
for (const id of currentIds) {
|
|
2700
|
-
if (!this.lastSentParticipantIds.has(id)) {
|
|
2701
|
-
changed = true;
|
|
2702
|
-
break;
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2648
|
+
const changed = this.roster.changed();
|
|
2706
2649
|
if (!changed && !this.participantsMessage) {
|
|
2707
2650
|
return null;
|
|
2708
2651
|
}
|
|
@@ -2712,15 +2655,9 @@ var ExecutionContext = class {
|
|
|
2712
2655
|
this.participantsMessage = null;
|
|
2713
2656
|
}
|
|
2714
2657
|
if (changed) {
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
type: p.type,
|
|
2719
|
-
handle: p.handle ?? null
|
|
2720
|
-
}));
|
|
2721
|
-
parts.push(buildParticipantsMessage(asRecords));
|
|
2722
|
-
}
|
|
2723
|
-
this.lastSentParticipantIds = currentIds;
|
|
2658
|
+
parts.push(buildParticipantsMessage(this.roster.list().map((p) => ({ ...toParticipantRecord(p) }))));
|
|
2659
|
+
}
|
|
2660
|
+
this.roster.markSent();
|
|
2724
2661
|
return parts.length > 0 ? parts.join("\n") : null;
|
|
2725
2662
|
}
|
|
2726
2663
|
consumeContactsMessage() {
|
|
@@ -2771,27 +2708,19 @@ var ExecutionContext = class {
|
|
|
2771
2708
|
return fallback;
|
|
2772
2709
|
}
|
|
2773
2710
|
}
|
|
2774
|
-
replaceParticipants(participants) {
|
|
2775
|
-
this.participants.splice(0, this.participants.length, ...participants);
|
|
2776
|
-
}
|
|
2777
2711
|
buildLocalContext() {
|
|
2778
2712
|
return {
|
|
2779
2713
|
roomId: this.roomId,
|
|
2780
2714
|
messages: this.getRawHistory(),
|
|
2781
|
-
participants:
|
|
2715
|
+
participants: this.roster.list().map(toParticipantRecord),
|
|
2782
2716
|
hydratedAt: /* @__PURE__ */ new Date()
|
|
2783
2717
|
};
|
|
2784
2718
|
}
|
|
2785
2719
|
async loadParticipants() {
|
|
2786
2720
|
const participants = await this.link.rest.listChatParticipants(this.roomId, DEFAULT_REQUEST_OPTIONS);
|
|
2787
|
-
const normalized = participants.map(
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
type: participant.type,
|
|
2791
|
-
handle: participant.handle ?? null
|
|
2792
|
-
}));
|
|
2793
|
-
this.replaceParticipants(normalized);
|
|
2794
|
-
return [...this.participants];
|
|
2721
|
+
const normalized = participants.map(toParticipantRecordFromRest);
|
|
2722
|
+
this.roster.setAll(normalized);
|
|
2723
|
+
return this.roster.list().map(toParticipantRecord);
|
|
2795
2724
|
}
|
|
2796
2725
|
async loadHydratedMessages() {
|
|
2797
2726
|
const messages = [];
|
|
@@ -2833,7 +2762,7 @@ var ExecutionContext = class {
|
|
|
2833
2762
|
if (!this.contextCache) {
|
|
2834
2763
|
return;
|
|
2835
2764
|
}
|
|
2836
|
-
this.contextCache.participants =
|
|
2765
|
+
this.contextCache.participants = this.roster.list().map(toParticipantRecord);
|
|
2837
2766
|
this.contextCache.hydratedAt = /* @__PURE__ */ new Date();
|
|
2838
2767
|
this.contextCacheExpiresAt = this.nextCacheExpiry();
|
|
2839
2768
|
}
|
|
@@ -3545,54 +3474,16 @@ function normalizeContactRequestsResult(result) {
|
|
|
3545
3474
|
}
|
|
3546
3475
|
|
|
3547
3476
|
// src/client/rest/FernRestAdapter.ts
|
|
3548
|
-
function mergeOptions(options) {
|
|
3477
|
+
function mergeOptions(options, maxRetries) {
|
|
3549
3478
|
return {
|
|
3550
3479
|
...DEFAULT_REQUEST_OPTIONS,
|
|
3480
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
3551
3481
|
...options
|
|
3552
3482
|
};
|
|
3553
3483
|
}
|
|
3554
|
-
var AGENT_ME_RETRY_LIMIT = 4;
|
|
3555
|
-
var AGENT_ME_RETRY_BASE_DELAY_MS = 2e3;
|
|
3556
|
-
var MESSAGE_SEND_RETRY_LIMIT = 3;
|
|
3557
|
-
var MESSAGE_SEND_RETRY_BASE_DELAY_MS = 500;
|
|
3558
3484
|
function asMetadataMap2(value) {
|
|
3559
3485
|
return asOptionalRecord(value);
|
|
3560
3486
|
}
|
|
3561
|
-
function extractHttpStatus(error) {
|
|
3562
|
-
const record = asOptionalRecord(error);
|
|
3563
|
-
if (!record) {
|
|
3564
|
-
return void 0;
|
|
3565
|
-
}
|
|
3566
|
-
const response = asOptionalRecord(record.response);
|
|
3567
|
-
const status = record.statusCode ?? record.status ?? response?.statusCode ?? response?.status;
|
|
3568
|
-
return typeof status === "number" ? status : void 0;
|
|
3569
|
-
}
|
|
3570
|
-
function isFernRateLimitError(error) {
|
|
3571
|
-
return extractHttpStatus(error) === 429;
|
|
3572
|
-
}
|
|
3573
|
-
async function sleep(ms) {
|
|
3574
|
-
await new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
3575
|
-
}
|
|
3576
|
-
function computeRetryDelayMs(baseDelayMs, attempt) {
|
|
3577
|
-
const backoff = baseDelayMs * 2 ** (attempt - 1);
|
|
3578
|
-
const jitter = Math.floor(Math.random() * Math.max(1, Math.floor(backoff / 4)));
|
|
3579
|
-
return backoff + jitter;
|
|
3580
|
-
}
|
|
3581
|
-
async function withRateLimitRetry(operation, options) {
|
|
3582
|
-
let lastError;
|
|
3583
|
-
for (let attempt = 1; attempt <= options.retryLimit; attempt += 1) {
|
|
3584
|
-
try {
|
|
3585
|
-
return await operation();
|
|
3586
|
-
} catch (error) {
|
|
3587
|
-
lastError = error;
|
|
3588
|
-
if (!isFernRateLimitError(error) || attempt === options.retryLimit) {
|
|
3589
|
-
throw error;
|
|
3590
|
-
}
|
|
3591
|
-
await sleep(computeRetryDelayMs(options.baseDelayMs, attempt));
|
|
3592
|
-
}
|
|
3593
|
-
}
|
|
3594
|
-
throw lastError instanceof Error ? lastError : new Error("Rate-limit retry exhausted without a terminal error.");
|
|
3595
|
-
}
|
|
3596
3487
|
function requireNonEmptyStringField(value, field, source) {
|
|
3597
3488
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
3598
3489
|
throw new Error(`Invalid ${source} response: expected non-empty string AgentIdentity.${field}`);
|
|
@@ -3800,28 +3691,21 @@ var FernRestAdapter = class {
|
|
|
3800
3691
|
this.client = client;
|
|
3801
3692
|
}
|
|
3802
3693
|
async getAgentMe(options) {
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
"profile.getMyProfile"
|
|
3819
|
-
);
|
|
3820
|
-
},
|
|
3821
|
-
{
|
|
3822
|
-
retryLimit: AGENT_ME_RETRY_LIMIT,
|
|
3823
|
-
baseDelayMs: AGENT_ME_RETRY_BASE_DELAY_MS
|
|
3824
|
-
}
|
|
3694
|
+
const requestOptions = mergeOptions(options);
|
|
3695
|
+
if (this.client.agentApiIdentity?.getAgentMe) {
|
|
3696
|
+
const response = await this.client.agentApiIdentity.getAgentMe(requestOptions);
|
|
3697
|
+
return normalizeAgentIdentityEnvelope(response, "agentApiIdentity.getAgentMe");
|
|
3698
|
+
}
|
|
3699
|
+
const profileClient = this.client.myProfile ?? this.client.humanApiProfile;
|
|
3700
|
+
if (!profileClient?.getMyProfile) {
|
|
3701
|
+
throw new UnsupportedFeatureError(
|
|
3702
|
+
"Fern client missing agentApiIdentity.getAgentMe or humanApiProfile.getMyProfile"
|
|
3703
|
+
);
|
|
3704
|
+
}
|
|
3705
|
+
const profile = await profileClient.getMyProfile(requestOptions);
|
|
3706
|
+
return normalizeLegacyProfileIdentity(
|
|
3707
|
+
normalizeLegacyProfileEnvelope(profile),
|
|
3708
|
+
"profile.getMyProfile"
|
|
3825
3709
|
);
|
|
3826
3710
|
}
|
|
3827
3711
|
async createChatMessage(chatId, message, options) {
|
|
@@ -3829,45 +3713,33 @@ var FernRestAdapter = class {
|
|
|
3829
3713
|
if (!api) {
|
|
3830
3714
|
throw new UnsupportedFeatureError("Fern client missing chat message creation endpoint");
|
|
3831
3715
|
}
|
|
3832
|
-
const response = await
|
|
3833
|
-
|
|
3834
|
-
chatId,
|
|
3835
|
-
{
|
|
3836
|
-
message: {
|
|
3837
|
-
content: message.content,
|
|
3838
|
-
message_type: message.messageType,
|
|
3839
|
-
metadata: message.metadata,
|
|
3840
|
-
mentions: message.mentions
|
|
3841
|
-
}
|
|
3842
|
-
},
|
|
3843
|
-
mergeOptions(options)
|
|
3844
|
-
),
|
|
3716
|
+
const response = await api(
|
|
3717
|
+
chatId,
|
|
3845
3718
|
{
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3719
|
+
message: {
|
|
3720
|
+
content: message.content,
|
|
3721
|
+
message_type: message.messageType,
|
|
3722
|
+
metadata: message.metadata,
|
|
3723
|
+
mentions: message.mentions
|
|
3724
|
+
}
|
|
3725
|
+
},
|
|
3726
|
+
mergeOptions(options, MESSAGE_SEND_MAX_RETRIES)
|
|
3849
3727
|
);
|
|
3850
3728
|
return normalizeToolOperationResult(response);
|
|
3851
3729
|
}
|
|
3852
3730
|
async createChatEvent(chatId, event, options) {
|
|
3853
3731
|
const createAgentChatEvent = this.client.agentApiEvents?.createAgentChatEvent?.bind(this.client.agentApiEvents);
|
|
3854
3732
|
if (createAgentChatEvent) {
|
|
3855
|
-
const response = await
|
|
3856
|
-
|
|
3857
|
-
chatId,
|
|
3858
|
-
{
|
|
3859
|
-
event: {
|
|
3860
|
-
content: event.content,
|
|
3861
|
-
message_type: event.messageType,
|
|
3862
|
-
metadata: event.metadata
|
|
3863
|
-
}
|
|
3864
|
-
},
|
|
3865
|
-
mergeOptions(options)
|
|
3866
|
-
),
|
|
3733
|
+
const response = await createAgentChatEvent(
|
|
3734
|
+
chatId,
|
|
3867
3735
|
{
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3736
|
+
event: {
|
|
3737
|
+
content: event.content,
|
|
3738
|
+
message_type: event.messageType,
|
|
3739
|
+
metadata: event.metadata
|
|
3740
|
+
}
|
|
3741
|
+
},
|
|
3742
|
+
mergeOptions(options, MESSAGE_SEND_MAX_RETRIES)
|
|
3871
3743
|
);
|
|
3872
3744
|
return normalizeToolOperationResult(response);
|
|
3873
3745
|
}
|
|
@@ -4390,7 +4262,7 @@ function retryAfterFromHeaders(headers) {
|
|
|
4390
4262
|
var import_ws = require("ws");
|
|
4391
4263
|
function createNodeWebSocketFactory(headers) {
|
|
4392
4264
|
const Constructor = import_ws.WebSocket;
|
|
4393
|
-
class
|
|
4265
|
+
class BandNodeWebSocket {
|
|
4394
4266
|
constructor(address, protocols) {
|
|
4395
4267
|
const socket = new Constructor(address, protocols, headers ? { headers } : void 0);
|
|
4396
4268
|
socket.once("unexpected-response", (request, response) => {
|
|
@@ -4399,7 +4271,7 @@ function createNodeWebSocketFactory(headers) {
|
|
|
4399
4271
|
return socket;
|
|
4400
4272
|
}
|
|
4401
4273
|
}
|
|
4402
|
-
return
|
|
4274
|
+
return BandNodeWebSocket;
|
|
4403
4275
|
}
|
|
4404
4276
|
async function emitUpgradeError(websocket, request, response) {
|
|
4405
4277
|
const body = await readResponseBody(response);
|
|
@@ -4787,9 +4659,9 @@ function getSocketChannelCount(socket) {
|
|
|
4787
4659
|
return candidate.channels.length;
|
|
4788
4660
|
}
|
|
4789
4661
|
|
|
4790
|
-
// src/platform/
|
|
4791
|
-
var import_rest_client = require("@
|
|
4792
|
-
var DEFAULT_WS_URL = "wss://app.
|
|
4662
|
+
// src/platform/BandLink.ts
|
|
4663
|
+
var import_rest_client = require("@band-ai/rest-client");
|
|
4664
|
+
var DEFAULT_WS_URL = "wss://app.band.ai/api/v1/socket";
|
|
4793
4665
|
function deriveDefaultRestUrl(wsUrl) {
|
|
4794
4666
|
const parsed = new URL(wsUrl);
|
|
4795
4667
|
const protocol = parsed.protocol === "ws:" ? "http:" : "https:";
|
|
@@ -4814,7 +4686,7 @@ function toPlatformMessage(roomId, message) {
|
|
|
4814
4686
|
createdAt: new Date(message.inserted_at)
|
|
4815
4687
|
};
|
|
4816
4688
|
}
|
|
4817
|
-
var
|
|
4689
|
+
var BandLink = class {
|
|
4818
4690
|
agentId;
|
|
4819
4691
|
apiKey;
|
|
4820
4692
|
wsUrl;
|
|
@@ -4840,7 +4712,7 @@ var ThenvoiLink = class {
|
|
|
4840
4712
|
...options.capabilities
|
|
4841
4713
|
};
|
|
4842
4714
|
const restApi = options.restApi ?? new FernRestAdapter(
|
|
4843
|
-
new import_rest_client.
|
|
4715
|
+
new import_rest_client.BandClient({
|
|
4844
4716
|
apiKey: this.apiKey,
|
|
4845
4717
|
baseUrl: this.restUrl
|
|
4846
4718
|
})
|
|
@@ -5213,6 +5085,8 @@ var DefaultPreprocessor = class {
|
|
|
5213
5085
|
};
|
|
5214
5086
|
|
|
5215
5087
|
// src/runtime/PlatformRuntime.ts
|
|
5088
|
+
var MAX_MESSAGE_RETRIES = 4294967295;
|
|
5089
|
+
var isValidRetryCount = (value) => Number.isInteger(value) && value >= 0 && value <= MAX_MESSAGE_RETRIES;
|
|
5216
5090
|
var PlatformRuntime = class {
|
|
5217
5091
|
_agentId;
|
|
5218
5092
|
_apiKey;
|
|
@@ -5249,6 +5123,12 @@ var PlatformRuntime = class {
|
|
|
5249
5123
|
"apiKey is required and must be a non-empty string. Use loadAgentConfig() to load credentials from agent_config.yaml."
|
|
5250
5124
|
);
|
|
5251
5125
|
}
|
|
5126
|
+
const maxMessageRetries = options.sessionConfig?.maxMessageRetries;
|
|
5127
|
+
if (maxMessageRetries !== void 0 && !isValidRetryCount(maxMessageRetries)) {
|
|
5128
|
+
throw new ValidationError(
|
|
5129
|
+
`sessionConfig.maxMessageRetries must be an integer between 0 and ${MAX_MESSAGE_RETRIES}, got ${maxMessageRetries}.`
|
|
5130
|
+
);
|
|
5131
|
+
}
|
|
5252
5132
|
this._agentId = options.agentId;
|
|
5253
5133
|
this._apiKey = options.apiKey;
|
|
5254
5134
|
this._wsUrl = options.wsUrl;
|
|
@@ -5301,7 +5181,7 @@ var PlatformRuntime = class {
|
|
|
5301
5181
|
}
|
|
5302
5182
|
async doInitialize() {
|
|
5303
5183
|
if (!this.linkInstance) {
|
|
5304
|
-
this.linkInstance = new
|
|
5184
|
+
this.linkInstance = new BandLink({
|
|
5305
5185
|
...this.linkOptions,
|
|
5306
5186
|
agentId: this._agentId,
|
|
5307
5187
|
apiKey: this._apiKey,
|
|
@@ -5584,25 +5464,28 @@ var RoomPresence = class {
|
|
|
5584
5464
|
}
|
|
5585
5465
|
};
|
|
5586
5466
|
|
|
5467
|
+
// src/runtime/index.ts
|
|
5468
|
+
var import_band_sdk_core3 = require("@band-ai/band-sdk-core");
|
|
5469
|
+
|
|
5587
5470
|
// src/runtime/prompts/base.ts
|
|
5588
5471
|
var ENVIRONMENT_SECTION = `
|
|
5589
5472
|
## Environment
|
|
5590
5473
|
|
|
5591
5474
|
Multi-participant chat. Messages show sender: [Name]: content.
|
|
5592
5475
|
Messages prefixed with [System]: are platform updates (participant changes, contact updates, etc.) \u2014 not messages from users.
|
|
5593
|
-
Use \`
|
|
5476
|
+
Use \`band_send_message(content, mentions)\` to respond. Plain text output is not delivered.
|
|
5594
5477
|
Mentions use handles: @<username> for users, @<username>/<agent-name> for agents.`;
|
|
5595
5478
|
var MULTI_AGENT_RULES_SECTION = `## CRITICAL: Delegate When You Cannot Help Directly
|
|
5596
5479
|
|
|
5597
5480
|
You have NO internet access and NO real-time data. When asked about weather, news, stock prices,
|
|
5598
5481
|
or any current information you cannot answer directly:
|
|
5599
5482
|
|
|
5600
|
-
1. Call \`
|
|
5601
|
-
2. If a relevant agent exists, call \`
|
|
5602
|
-
3. Ask that agent using \`
|
|
5483
|
+
1. Call \`band_lookup_peers()\` to find available specialized agents
|
|
5484
|
+
2. If a relevant agent exists, call \`band_add_participant(name)\` to add them
|
|
5485
|
+
3. Ask that agent using \`band_send_message(question, mentions=[agent_handle])\`
|
|
5603
5486
|
4. Wait for their response and relay it back to the user
|
|
5604
5487
|
|
|
5605
|
-
NEVER say "I can't do that" without first checking if another agent can help via \`
|
|
5488
|
+
NEVER say "I can't do that" without first checking if another agent can help via \`band_lookup_peers()\`.
|
|
5606
5489
|
|
|
5607
5490
|
## CRITICAL: Do NOT Remove Agents Automatically
|
|
5608
5491
|
|
|
@@ -5621,42 +5504,42 @@ When someone asks you to get information from another agent:
|
|
|
5621
5504
|
3. Do NOT just thank the helper agent - the requester is waiting for their answer!`;
|
|
5622
5505
|
var THINKING_SECTION = `## IMPORTANT: Always Share Your Thinking
|
|
5623
5506
|
|
|
5624
|
-
You MUST call \`
|
|
5507
|
+
You MUST call \`band_send_event(content, message_type="thought")\` BEFORE every action.
|
|
5625
5508
|
This is required so users can see your reasoning process.`;
|
|
5626
5509
|
var EXAMPLES_SECTION = `## Examples
|
|
5627
5510
|
|
|
5628
5511
|
### Simple question - answer directly
|
|
5629
5512
|
[John Doe]: What's 2+2?
|
|
5630
|
-
->
|
|
5631
|
-
->
|
|
5513
|
+
-> band_send_event("Simple arithmetic, answering directly.", message_type="thought")
|
|
5514
|
+
-> band_send_message("4", mentions=["@john"])
|
|
5632
5515
|
|
|
5633
5516
|
### User asks about weather (you cannot answer directly)
|
|
5634
5517
|
[John Doe]: What's the weather in Tokyo?
|
|
5635
|
-
->
|
|
5636
|
-
->
|
|
5637
|
-
->
|
|
5638
|
-
->
|
|
5639
|
-
->
|
|
5518
|
+
-> band_send_event("I can't check weather directly. Looking for a Weather Agent.", message_type="thought")
|
|
5519
|
+
-> band_lookup_peers()
|
|
5520
|
+
-> band_send_event("Found Weather Agent. Adding to room.", message_type="thought")
|
|
5521
|
+
-> band_add_participant("Weather Agent")
|
|
5522
|
+
-> band_send_message("What's the weather in Tokyo?", mentions=["@john/weather-agent"])
|
|
5640
5523
|
|
|
5641
5524
|
[Weather Agent]: Tokyo is 15\xB0C and cloudy.
|
|
5642
|
-
->
|
|
5643
|
-
->
|
|
5525
|
+
-> band_send_event("Got weather response. Relaying back to John Doe.", message_type="thought")
|
|
5526
|
+
-> band_send_message("The weather in Tokyo is 15\xB0C and cloudy.", mentions=["@john"])
|
|
5644
5527
|
|
|
5645
5528
|
### No suitable agent available
|
|
5646
5529
|
[John Doe]: What's the stock price of AAPL?
|
|
5647
|
-
->
|
|
5648
|
-
->
|
|
5649
|
-
->
|
|
5650
|
-
->
|
|
5530
|
+
-> band_send_event("I can't check stock prices. Looking for a Stock Agent.", message_type="thought")
|
|
5531
|
+
-> band_lookup_peers()
|
|
5532
|
+
-> band_send_event("No stock agent available. Must inform user.", message_type="thought")
|
|
5533
|
+
-> band_send_message("I don't have access to stock prices, and there's no specialized agent available to help with that.", mentions=["@john"])
|
|
5651
5534
|
|
|
5652
5535
|
### Follow-up question in same conversation
|
|
5653
5536
|
[John Doe]: What about London?
|
|
5654
|
-
->
|
|
5655
|
-
->
|
|
5537
|
+
-> band_send_event("Follow-up weather question. Asking Weather Agent.", message_type="thought")
|
|
5538
|
+
-> band_send_message("What's the weather in London?", mentions=["@john/weather-agent"])
|
|
5656
5539
|
|
|
5657
5540
|
[Weather Agent]: London is 8\xB0C and rainy.
|
|
5658
|
-
->
|
|
5659
|
-
->
|
|
5541
|
+
-> band_send_event("Got London weather. Relaying to John Doe.", message_type="thought")
|
|
5542
|
+
-> band_send_message("London is 8\xB0C and rainy.", mentions=["@john"])`;
|
|
5660
5543
|
var BASE_INSTRUCTIONS = [
|
|
5661
5544
|
ENVIRONMENT_SECTION,
|
|
5662
5545
|
MULTI_AGENT_RULES_SECTION,
|
|
@@ -5668,10 +5551,10 @@ var BASE_INSTRUCTIONS = [
|
|
|
5668
5551
|
var MEMORY_INTRO = `## Memory Tools
|
|
5669
5552
|
|
|
5670
5553
|
You have access to memory tools for storing and retrieving information
|
|
5671
|
-
across conversations. Use \`
|
|
5672
|
-
information and \`
|
|
5673
|
-
Use \`
|
|
5674
|
-
\`
|
|
5554
|
+
across conversations. Use \`band_store_memory\` to persist important
|
|
5555
|
+
information and \`band_list_memories\` / \`band_get_memory\` to recall it.
|
|
5556
|
+
Use \`band_supersede_memory\` to mark outdated memories and
|
|
5557
|
+
\`band_archive_memory\` to hide memories that should be preserved.`;
|
|
5675
5558
|
function longTermPattern(label, type, segment, scope) {
|
|
5676
5559
|
return {
|
|
5677
5560
|
label,
|
|
@@ -5696,7 +5579,7 @@ var MEMORY_COMMON_PATTERNS = [
|
|
|
5696
5579
|
].join("\n");
|
|
5697
5580
|
var MEMORY_SCOPE_GUIDANCE = `Prefer \`scope="${MEMORY_STORE_SCOPE.subject}"\` whenever the memory is about a specific person or agent, so it
|
|
5698
5581
|
stays attached to that subject rather than leaking org-wide. Storing with \`scope="${MEMORY_STORE_SCOPE.subject}"\` requires a
|
|
5699
|
-
real \`subject_id\` UUID, so resolve it first via \`
|
|
5582
|
+
real \`subject_id\` UUID, so resolve it first via \`band_lookup_peers\` or the participant list.
|
|
5700
5583
|
Reserve \`scope="${MEMORY_STORE_SCOPE.organization}"\` for knowledge that is genuinely shared across the whole organization and
|
|
5701
5584
|
is not about any one subject.`;
|
|
5702
5585
|
function quoteChoices(values) {
|
|
@@ -5706,11 +5589,11 @@ function memoryTypeLines() {
|
|
|
5706
5589
|
return Object.entries(MEMORY_SYSTEM_TYPES).map(([system, types]) => ` - ${system}: ${quoteChoices(types)}`).join("\n");
|
|
5707
5590
|
}
|
|
5708
5591
|
function buildMemorySection() {
|
|
5709
|
-
const storeMemoryProps = TOOL_MODELS.
|
|
5592
|
+
const storeMemoryProps = TOOL_MODELS.band_store_memory.properties;
|
|
5710
5593
|
const systems = storeMemoryProps.system.enum;
|
|
5711
5594
|
const segments = storeMemoryProps.segment.enum;
|
|
5712
5595
|
const scopes = storeMemoryProps.scope.enum;
|
|
5713
|
-
const fieldRules = `When calling \`
|
|
5596
|
+
const fieldRules = `When calling \`band_store_memory\`, the \`system\`, \`type\`, \`segment\`, and \`scope\` fields
|
|
5714
5597
|
must use these exact values (case-sensitive):
|
|
5715
5598
|
|
|
5716
5599
|
- **system**: ${quoteChoices(systems)}
|
|
@@ -5750,61 +5633,6 @@ ${customSection}`.trim();
|
|
|
5750
5633
|
return parts.join("\n\n");
|
|
5751
5634
|
}
|
|
5752
5635
|
|
|
5753
|
-
// src/runtime/participantTracker.ts
|
|
5754
|
-
var ParticipantTracker = class {
|
|
5755
|
-
participantsList = [];
|
|
5756
|
-
lastSent = null;
|
|
5757
|
-
loaded = false;
|
|
5758
|
-
get participants() {
|
|
5759
|
-
return [...this.participantsList];
|
|
5760
|
-
}
|
|
5761
|
-
get isLoaded() {
|
|
5762
|
-
return this.loaded;
|
|
5763
|
-
}
|
|
5764
|
-
setLoaded(participants) {
|
|
5765
|
-
this.participantsList = participants.map((participant) => ({ ...participant }));
|
|
5766
|
-
this.loaded = true;
|
|
5767
|
-
}
|
|
5768
|
-
add(participant) {
|
|
5769
|
-
if (this.participantsList.some((entry) => entry.id === participant.id)) {
|
|
5770
|
-
return false;
|
|
5771
|
-
}
|
|
5772
|
-
this.participantsList.push({
|
|
5773
|
-
id: participant.id,
|
|
5774
|
-
name: participant.name,
|
|
5775
|
-
type: participant.type,
|
|
5776
|
-
handle: participant.handle
|
|
5777
|
-
});
|
|
5778
|
-
return true;
|
|
5779
|
-
}
|
|
5780
|
-
remove(participantId) {
|
|
5781
|
-
const before = this.participantsList.length;
|
|
5782
|
-
this.participantsList = this.participantsList.filter(
|
|
5783
|
-
(participant) => participant.id !== participantId
|
|
5784
|
-
);
|
|
5785
|
-
return this.participantsList.length < before;
|
|
5786
|
-
}
|
|
5787
|
-
changed() {
|
|
5788
|
-
if (!this.lastSent) {
|
|
5789
|
-
return true;
|
|
5790
|
-
}
|
|
5791
|
-
const oldIds = new Set(this.lastSent.map((participant) => participant.id));
|
|
5792
|
-
const newIds = new Set(this.participantsList.map((participant) => participant.id));
|
|
5793
|
-
if (oldIds.size !== newIds.size) {
|
|
5794
|
-
return true;
|
|
5795
|
-
}
|
|
5796
|
-
for (const id of oldIds) {
|
|
5797
|
-
if (!newIds.has(id)) {
|
|
5798
|
-
return true;
|
|
5799
|
-
}
|
|
5800
|
-
}
|
|
5801
|
-
return false;
|
|
5802
|
-
}
|
|
5803
|
-
markSent() {
|
|
5804
|
-
this.lastSent = this.participantsList.map((participant) => ({ ...participant }));
|
|
5805
|
-
}
|
|
5806
|
-
};
|
|
5807
|
-
|
|
5808
5636
|
// src/runtime/shutdown.ts
|
|
5809
5637
|
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 3e4;
|
|
5810
5638
|
var GracefulShutdown = class {
|
|
@@ -5883,12 +5711,13 @@ async function runWithGracefulShutdown(agent, options) {
|
|
|
5883
5711
|
GracefulShutdown,
|
|
5884
5712
|
HUB_ROOM_SYSTEM_PROMPT,
|
|
5885
5713
|
HistoryProvider,
|
|
5714
|
+
MCP_SERVER_NAME,
|
|
5886
5715
|
MCP_TOOL_PREFIX,
|
|
5887
5716
|
MEMORY_SECTION,
|
|
5888
5717
|
MEMORY_TOOL_NAMES,
|
|
5889
|
-
|
|
5890
|
-
ParticipantTracker,
|
|
5718
|
+
ParticipantRoster,
|
|
5891
5719
|
PlatformRuntime,
|
|
5720
|
+
RetryTracker,
|
|
5892
5721
|
RoomPresence,
|
|
5893
5722
|
SYNTHETIC_CONTACT_EVENTS_SENDER_ID,
|
|
5894
5723
|
SYNTHETIC_CONTACT_EVENTS_SENDER_NAME,
|