@band-ai/sdk 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/CodexAdapter-A1k_LMdZ.d.ts +1278 -0
  2. package/dist/CodexAdapter-BbZD-nBd.d.cts +1278 -0
  3. package/dist/adapters.cjs +10643 -0
  4. package/dist/adapters.d.cts +217 -0
  5. package/dist/adapters.d.ts +217 -0
  6. package/dist/adapters.js +92 -0
  7. package/dist/backends-BnOLsG7w.d.cts +20 -0
  8. package/dist/backends-C4n6cKOf.d.ts +20 -0
  9. package/dist/chunk-3BKAC4OZ.js +44 -0
  10. package/dist/chunk-5CXIMAH2.js +52 -0
  11. package/dist/chunk-6AJA2OPC.js +3682 -0
  12. package/dist/chunk-A3TDK6GP.js +6674 -0
  13. package/dist/chunk-AVVDPXP4.js +39 -0
  14. package/dist/chunk-EDPKUUJL.js +177 -0
  15. package/dist/chunk-FUODYQRE.js +2562 -0
  16. package/dist/chunk-GVEQ3RAH.js +373 -0
  17. package/dist/chunk-INA6YZTZ.js +88 -0
  18. package/dist/chunk-IZPV6QS6.js +115 -0
  19. package/dist/chunk-LY55KYVI.js +0 -0
  20. package/dist/chunk-NIAQBANR.js +577 -0
  21. package/dist/chunk-OD2G5LFQ.js +78 -0
  22. package/dist/chunk-SFVKOEQH.js +103 -0
  23. package/dist/chunk-SG4WLD2H.js +1093 -0
  24. package/dist/chunk-YR3BOQNW.js +39 -0
  25. package/dist/chunk-ZZJRRBPQ.js +82 -0
  26. package/dist/claude-CcnQ5OUC.d.ts +53 -0
  27. package/dist/claude-CwTAxhwI.d.cts +53 -0
  28. package/dist/config.cjs +164 -0
  29. package/dist/config.d.cts +19 -0
  30. package/dist/config.d.ts +19 -0
  31. package/dist/config.js +9 -0
  32. package/dist/converters.cjs +1086 -0
  33. package/dist/converters.d.cts +143 -0
  34. package/dist/converters.d.ts +143 -0
  35. package/dist/converters.js +468 -0
  36. package/dist/core.cjs +185 -0
  37. package/dist/core.d.cts +22 -0
  38. package/dist/core.d.ts +22 -0
  39. package/dist/core.js +24 -0
  40. package/dist/customTools-BzF0IISO.d.cts +10 -0
  41. package/dist/customTools-BzF0IISO.d.ts +10 -0
  42. package/dist/dtos-DUpbIu8k.d.cts +163 -0
  43. package/dist/dtos-DUpbIu8k.d.ts +163 -0
  44. package/dist/history-ByessXNq.d.ts +24 -0
  45. package/dist/history-i6yN7neC.d.cts +24 -0
  46. package/dist/index.cjs +13914 -0
  47. package/dist/index.d.cts +63 -0
  48. package/dist/index.d.ts +63 -0
  49. package/dist/index.js +198 -0
  50. package/dist/linear.cjs +2207 -0
  51. package/dist/linear.d.cts +167 -0
  52. package/dist/linear.d.ts +167 -0
  53. package/dist/linear.js +2139 -0
  54. package/dist/logger-CABQOnlR.d.cts +21 -0
  55. package/dist/logger-CABQOnlR.d.ts +21 -0
  56. package/dist/mcp-claude.cjs +584 -0
  57. package/dist/mcp-claude.d.cts +4 -0
  58. package/dist/mcp-claude.d.ts +4 -0
  59. package/dist/mcp-claude.js +11 -0
  60. package/dist/mcp.cjs +1247 -0
  61. package/dist/mcp.d.cts +97 -0
  62. package/dist/mcp.d.ts +97 -0
  63. package/dist/mcp.js +27 -0
  64. package/dist/opencode-BBcDchcN.d.cts +159 -0
  65. package/dist/opencode-DthQQUsZ.d.ts +159 -0
  66. package/dist/pagination-BPiys10t.d.cts +25 -0
  67. package/dist/pagination-CcDkVFxK.d.ts +25 -0
  68. package/dist/protocols-CInhtFpA.d.cts +116 -0
  69. package/dist/protocols-DrhzOH6K.d.ts +116 -0
  70. package/dist/rest.cjs +1159 -0
  71. package/dist/rest.d.cts +144 -0
  72. package/dist/rest.d.ts +144 -0
  73. package/dist/rest.js +18 -0
  74. package/dist/runtime.cjs +5353 -0
  75. package/dist/runtime.d.cts +276 -0
  76. package/dist/runtime.d.ts +276 -0
  77. package/dist/runtime.js +274 -0
  78. package/dist/schemas-BpEBkq5V.d.cts +592 -0
  79. package/dist/schemas-vos1AaBc.d.ts +592 -0
  80. package/dist/sdk-HJUVSSWA.js +10 -0
  81. package/dist/simpleAdapter-9OE_p6QW.d.ts +29 -0
  82. package/dist/simpleAdapter-DqhvjsGr.d.cts +29 -0
  83. package/dist/testing.cjs +217 -0
  84. package/dist/testing.d.cts +126 -0
  85. package/dist/testing.d.ts +126 -0
  86. package/dist/testing.js +186 -0
  87. package/dist/types-7jVzOeOP.d.ts +446 -0
  88. package/dist/types-CSHFipIc.d.cts +331 -0
  89. package/dist/types-CovcHpYf.d.cts +446 -0
  90. package/dist/types-CxII3XkA.d.ts +331 -0
  91. package/package.json +189 -0
@@ -0,0 +1,373 @@
1
+ import {
2
+ ValidationError
3
+ } from "./chunk-YR3BOQNW.js";
4
+
5
+ // src/contracts/chatEvents.ts
6
+ var CHAT_EVENT_TYPES = ["tool_call", "tool_result", "thought", "error", "task"];
7
+ var CHAT_MESSAGE_TYPES = ["text", ...CHAT_EVENT_TYPES];
8
+ function isChatEventType(value) {
9
+ return CHAT_EVENT_TYPES.includes(value);
10
+ }
11
+ function assertChatEventType(value) {
12
+ if (!isChatEventType(value)) {
13
+ throw new ValidationError(
14
+ `Invalid event message_type '${value}'. Expected one of: ${CHAT_EVENT_TYPES.join(", ")}`
15
+ );
16
+ }
17
+ }
18
+
19
+ // src/runtime/tools/schemas.ts
20
+ var TOOL_MODELS = {
21
+ thenvoi_send_message: {
22
+ 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.",
23
+ properties: {
24
+ content: {
25
+ type: "string",
26
+ description: "The message content to send."
27
+ },
28
+ mentions: {
29
+ type: "array",
30
+ items: { type: "string" },
31
+ minItems: 1,
32
+ description: "List of participant handles to @mention. At least one required. For users: @<username> (e.g., '@john'). For agents: @<username>/<agent-name> (e.g., '@john/weather-agent'). Use the handle of someone already in the room."
33
+ }
34
+ },
35
+ required: ["content", "mentions"]
36
+ },
37
+ thenvoi_send_event: {
38
+ 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.",
39
+ properties: {
40
+ content: {
41
+ type: "string",
42
+ description: "Human-readable event content."
43
+ },
44
+ message_type: {
45
+ type: "string",
46
+ enum: [...CHAT_EVENT_TYPES],
47
+ description: "Type of event."
48
+ },
49
+ metadata: {
50
+ type: "object",
51
+ description: "Optional structured data for the event."
52
+ }
53
+ },
54
+ required: ["content", "message_type"]
55
+ },
56
+ thenvoi_add_participant: {
57
+ description: "Add a participant (agent or user) to the chat room by name. IMPORTANT: Use thenvoi_lookup_peers() first to find available agents. Pass the exact peer name from thenvoi_lookup_peers, not the handle. For normal delegation, omit role or use 'member'.",
58
+ properties: {
59
+ name: {
60
+ type: "string",
61
+ description: "Name of participant to add (must match a name from thenvoi_lookup_peers)."
62
+ },
63
+ role: {
64
+ type: "string",
65
+ enum: ["owner", "admin", "member"],
66
+ description: "Role for the participant in this room."
67
+ }
68
+ },
69
+ required: ["name"]
70
+ },
71
+ thenvoi_remove_participant: {
72
+ description: "Remove a participant from the chat room by name.",
73
+ properties: {
74
+ name: {
75
+ type: "string",
76
+ description: "Name of the participant to remove."
77
+ }
78
+ },
79
+ required: ["name"]
80
+ },
81
+ thenvoi_get_participants: {
82
+ description: "Get a list of all participants in the current chat room.",
83
+ properties: {},
84
+ required: []
85
+ },
86
+ thenvoi_lookup_peers: {
87
+ 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.",
88
+ properties: {
89
+ page: {
90
+ type: "integer",
91
+ description: "Page number."
92
+ },
93
+ page_size: {
94
+ type: "integer",
95
+ description: "Items per page (max 100).",
96
+ maximum: 100
97
+ }
98
+ },
99
+ required: []
100
+ },
101
+ thenvoi_create_chatroom: {
102
+ description: "Create a new chat room for a specific task or conversation.",
103
+ properties: {
104
+ task_id: {
105
+ type: "string",
106
+ description: "Associated task ID (optional)."
107
+ }
108
+ },
109
+ required: []
110
+ },
111
+ thenvoi_list_contacts: {
112
+ description: "List agent's contacts with pagination.",
113
+ properties: {
114
+ page: {
115
+ type: "integer",
116
+ description: "Page number.",
117
+ minimum: 1
118
+ },
119
+ page_size: {
120
+ type: "integer",
121
+ description: "Items per page.",
122
+ minimum: 1,
123
+ maximum: 100
124
+ }
125
+ },
126
+ required: []
127
+ },
128
+ thenvoi_add_contact: {
129
+ 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.",
130
+ properties: {
131
+ handle: {
132
+ type: "string",
133
+ description: "Handle of user/agent to add (e.g., '@john' or '@john/agent-name')."
134
+ },
135
+ message: {
136
+ type: "string",
137
+ description: "Optional message with the request."
138
+ }
139
+ },
140
+ required: ["handle"]
141
+ },
142
+ thenvoi_remove_contact: {
143
+ description: "Remove an existing contact by handle or ID.",
144
+ properties: {
145
+ handle: {
146
+ type: "string",
147
+ description: "Contact's handle."
148
+ },
149
+ contact_id: {
150
+ type: "string",
151
+ description: "Or contact record ID (UUID)."
152
+ }
153
+ },
154
+ required: []
155
+ },
156
+ thenvoi_list_contact_requests: {
157
+ description: "List both received and sent contact requests. Received requests are always filtered to pending status. Sent requests can be filtered by status.",
158
+ properties: {
159
+ page: {
160
+ type: "integer",
161
+ description: "Page number.",
162
+ minimum: 1
163
+ },
164
+ page_size: {
165
+ type: "integer",
166
+ description: "Items per page per direction (max 100).",
167
+ minimum: 1,
168
+ maximum: 100
169
+ },
170
+ sent_status: {
171
+ type: "string",
172
+ enum: ["pending", "approved", "rejected", "cancelled", "all"],
173
+ description: "Filter sent requests by status."
174
+ }
175
+ },
176
+ required: []
177
+ },
178
+ thenvoi_respond_contact_request: {
179
+ 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).",
180
+ properties: {
181
+ action: {
182
+ type: "string",
183
+ enum: ["approve", "reject", "cancel"],
184
+ description: "Action to take."
185
+ },
186
+ handle: {
187
+ type: "string",
188
+ description: "Other party's handle."
189
+ },
190
+ request_id: {
191
+ type: "string",
192
+ description: "Or request ID (UUID)."
193
+ }
194
+ },
195
+ required: ["action"]
196
+ },
197
+ thenvoi_list_memories: {
198
+ description: "List memories accessible to the agent. Returns memories about the specified subject (cross-agent sharing) and organization-wide shared memories.",
199
+ properties: {
200
+ subject_id: {
201
+ type: "string",
202
+ description: "Filter by subject UUID (required for subject-scoped queries)."
203
+ },
204
+ scope: {
205
+ type: "string",
206
+ enum: ["subject", "organization", "all"],
207
+ description: "Filter by scope."
208
+ },
209
+ system: {
210
+ type: "string",
211
+ enum: ["sensory", "working", "long_term"],
212
+ description: "Filter by memory system."
213
+ },
214
+ type: {
215
+ type: "string",
216
+ enum: [
217
+ "iconic",
218
+ "echoic",
219
+ "haptic",
220
+ "episodic",
221
+ "semantic",
222
+ "procedural"
223
+ ],
224
+ description: "Filter by memory type."
225
+ },
226
+ segment: {
227
+ type: "string",
228
+ enum: ["user", "agent", "tool", "guideline"],
229
+ description: "Filter by segment."
230
+ },
231
+ content_query: {
232
+ type: "string",
233
+ description: "Full-text search query."
234
+ },
235
+ page_size: {
236
+ type: "integer",
237
+ description: "Number of results per page.",
238
+ minimum: 1,
239
+ maximum: 50
240
+ },
241
+ status: {
242
+ type: "string",
243
+ enum: ["active", "superseded", "archived", "all"],
244
+ description: "Filter by status."
245
+ }
246
+ },
247
+ required: []
248
+ },
249
+ thenvoi_store_memory: {
250
+ 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.",
251
+ properties: {
252
+ content: {
253
+ type: "string",
254
+ description: "The memory content."
255
+ },
256
+ system: {
257
+ type: "string",
258
+ enum: ["sensory", "working", "long_term"],
259
+ description: "Memory system tier."
260
+ },
261
+ type: {
262
+ type: "string",
263
+ enum: [
264
+ "iconic",
265
+ "echoic",
266
+ "haptic",
267
+ "episodic",
268
+ "semantic",
269
+ "procedural"
270
+ ],
271
+ description: "Memory type (must be valid for selected system)."
272
+ },
273
+ segment: {
274
+ type: "string",
275
+ enum: ["user", "agent", "tool", "guideline"],
276
+ description: "Logical segment."
277
+ },
278
+ thought: {
279
+ type: "string",
280
+ description: "Agent's reasoning for storing this memory."
281
+ },
282
+ scope: {
283
+ type: "string",
284
+ enum: ["subject", "organization"],
285
+ description: "Visibility scope."
286
+ },
287
+ subject_id: {
288
+ type: "string",
289
+ description: "UUID of the subject this memory is about (required for subject scope)."
290
+ },
291
+ metadata: {
292
+ type: "object",
293
+ description: "Additional metadata (tags, references)."
294
+ }
295
+ },
296
+ required: ["content", "system", "type", "segment", "thought"]
297
+ },
298
+ thenvoi_get_memory: {
299
+ description: "Retrieve a specific memory by ID.",
300
+ properties: {
301
+ memory_id: {
302
+ type: "string",
303
+ description: "Memory ID (UUID)."
304
+ }
305
+ },
306
+ required: ["memory_id"]
307
+ },
308
+ thenvoi_supersede_memory: {
309
+ 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.",
310
+ properties: {
311
+ memory_id: {
312
+ type: "string",
313
+ description: "Memory ID (UUID)."
314
+ }
315
+ },
316
+ required: ["memory_id"]
317
+ },
318
+ thenvoi_archive_memory: {
319
+ 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.",
320
+ properties: {
321
+ memory_id: {
322
+ type: "string",
323
+ description: "Memory ID (UUID)."
324
+ }
325
+ },
326
+ required: ["memory_id"]
327
+ }
328
+ };
329
+ var ALL_TOOL_NAMES = new Set(Object.keys(TOOL_MODELS));
330
+ var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
331
+ "thenvoi_list_memories",
332
+ "thenvoi_store_memory",
333
+ "thenvoi_get_memory",
334
+ "thenvoi_supersede_memory",
335
+ "thenvoi_archive_memory"
336
+ ]);
337
+ var CONTACT_TOOL_NAMES = /* @__PURE__ */ new Set([
338
+ "thenvoi_list_contacts",
339
+ "thenvoi_add_contact",
340
+ "thenvoi_remove_contact",
341
+ "thenvoi_list_contact_requests",
342
+ "thenvoi_respond_contact_request"
343
+ ]);
344
+ var BASE_TOOL_NAMES = new Set(
345
+ [...ALL_TOOL_NAMES].filter((name) => !MEMORY_TOOL_NAMES.has(name))
346
+ );
347
+ var CHAT_TOOL_NAMES = new Set(
348
+ [...BASE_TOOL_NAMES].filter((name) => !CONTACT_TOOL_NAMES.has(name))
349
+ );
350
+ var MCP_TOOL_PREFIX = "mcp__thenvoi__";
351
+ function mcpToolNames(names) {
352
+ return [...names].sort((a, b) => a.localeCompare(b)).map((name) => `${MCP_TOOL_PREFIX}${name}`);
353
+ }
354
+ function getToolDescription(name) {
355
+ const model = TOOL_MODELS[name];
356
+ return model?.description ?? `Execute ${name}`;
357
+ }
358
+
359
+ export {
360
+ CHAT_EVENT_TYPES,
361
+ CHAT_MESSAGE_TYPES,
362
+ isChatEventType,
363
+ assertChatEventType,
364
+ TOOL_MODELS,
365
+ ALL_TOOL_NAMES,
366
+ MEMORY_TOOL_NAMES,
367
+ CONTACT_TOOL_NAMES,
368
+ BASE_TOOL_NAMES,
369
+ CHAT_TOOL_NAMES,
370
+ MCP_TOOL_PREFIX,
371
+ mcpToolNames,
372
+ getToolDescription
373
+ };
@@ -0,0 +1,88 @@
1
+ // src/runtime/formatters.ts
2
+ function isMetadataMap(value) {
3
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ function replaceUuidMentions(content, participants) {
6
+ if (!content || participants.length === 0) {
7
+ return content;
8
+ }
9
+ let next = content;
10
+ for (const participant of participants) {
11
+ const participantId = participant.id;
12
+ const handle = participant.handle;
13
+ if (typeof participantId === "string" && typeof handle === "string") {
14
+ next = next.replaceAll(`@[[${participantId}]]`, `@${handle}`);
15
+ }
16
+ }
17
+ return next;
18
+ }
19
+ function formatMessageForLlm(message, participants) {
20
+ const senderType = String(message.sender_type ?? "");
21
+ const senderName = String(message.sender_name ?? message.name ?? senderType);
22
+ const content = participants ? replaceUuidMentions(String(message.content ?? ""), participants) : String(message.content ?? "");
23
+ return {
24
+ role: senderType === "Agent" ? "assistant" : "user",
25
+ content,
26
+ sender_name: senderName,
27
+ sender_type: senderType,
28
+ message_type: String(message.message_type ?? "text"),
29
+ metadata: isMetadataMap(message.metadata) ? message.metadata : {}
30
+ };
31
+ }
32
+ function formatHistoryForLlm(messages, options) {
33
+ const excludeId = options?.excludeId;
34
+ const participants = options?.participants;
35
+ return messages.filter((message) => String(message.id ?? "") !== excludeId).map((message) => formatMessageForLlm(message, participants));
36
+ }
37
+ function buildParticipantsMessage(participants) {
38
+ if (participants.length === 0) {
39
+ return "## Current Participants\nNo other participants in this room.";
40
+ }
41
+ const lines = ["## Current Participants"];
42
+ for (const participant of participants) {
43
+ const participantType = String(participant.type ?? "Unknown");
44
+ const participantName = String(participant.name ?? "Unknown");
45
+ const participantHandle = String(participant.handle ?? "Unknown");
46
+ lines.push(`- @${participantHandle} \u2014 ${participantName} (${participantType})`);
47
+ }
48
+ lines.push("");
49
+ lines.push(
50
+ "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."
51
+ );
52
+ return lines.join("\n");
53
+ }
54
+
55
+ // src/runtime/types.ts
56
+ var HistoryProvider = class {
57
+ raw;
58
+ constructor(raw) {
59
+ this.raw = raw;
60
+ }
61
+ convert(converter) {
62
+ return converter.convert(this.raw);
63
+ }
64
+ get length() {
65
+ return this.raw.length;
66
+ }
67
+ };
68
+ var SYNTHETIC_SENDER_TYPE = "System";
69
+ var SYNTHETIC_CONTACT_EVENTS_SENDER_ID = "contact-events";
70
+ var SYNTHETIC_CONTACT_EVENTS_SENDER_NAME = "Contact Events";
71
+ function ensureHandlePrefix(handle) {
72
+ if (!handle) {
73
+ return null;
74
+ }
75
+ return handle.startsWith("@") ? handle : `@${handle}`;
76
+ }
77
+
78
+ export {
79
+ replaceUuidMentions,
80
+ formatMessageForLlm,
81
+ formatHistoryForLlm,
82
+ buildParticipantsMessage,
83
+ HistoryProvider,
84
+ SYNTHETIC_SENDER_TYPE,
85
+ SYNTHETIC_CONTACT_EVENTS_SENDER_ID,
86
+ SYNTHETIC_CONTACT_EVENTS_SENDER_NAME,
87
+ ensureHandlePrefix
88
+ };
@@ -0,0 +1,115 @@
1
+ import {
2
+ ValidationError
3
+ } from "./chunk-YR3BOQNW.js";
4
+
5
+ // src/config/loader.ts
6
+ import { readFileSync } from "fs";
7
+ import yaml from "js-yaml";
8
+ var DEFAULT_CONFIG_PATH = "./agent_config.yaml";
9
+ var DEFAULT_ENV_PREFIX = "THENVOI_";
10
+ var REQUIRED_FIELDS = ["agent_id", "api_key"];
11
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype", "toString", "valueOf"]);
12
+ function toSnakeCase(key) {
13
+ return key.replace(/([A-Z])/g, "_$1").toLowerCase();
14
+ }
15
+ function normalizeKeys(obj) {
16
+ const result = {};
17
+ for (const [key, value] of Object.entries(obj)) {
18
+ result[toSnakeCase(key)] = value;
19
+ }
20
+ return result;
21
+ }
22
+ function toAgentConfigResult(section, sourceLabel) {
23
+ const missing = REQUIRED_FIELDS.filter((field) => !section[field]);
24
+ if (missing.length > 0) {
25
+ throw new ValidationError(
26
+ `Missing required fields in ${sourceLabel}: ${missing.join(", ")}`
27
+ );
28
+ }
29
+ const invalid = REQUIRED_FIELDS.filter(
30
+ (field) => {
31
+ const value = section[field];
32
+ return typeof value !== "string" || value.trim() === "";
33
+ }
34
+ );
35
+ if (invalid.length > 0) {
36
+ throw new ValidationError(
37
+ `Invalid fields in ${sourceLabel}: ${invalid.join(", ")} must be non-empty strings`
38
+ );
39
+ }
40
+ const { agent_id, api_key, ws_url, rest_url, ...rest } = section;
41
+ if (ws_url !== void 0 && typeof ws_url !== "string") {
42
+ throw new ValidationError(`ws_url in ${sourceLabel} must be a string`);
43
+ }
44
+ if (rest_url !== void 0 && typeof rest_url !== "string") {
45
+ throw new ValidationError(`rest_url in ${sourceLabel} must be a string`);
46
+ }
47
+ const safeRest = {};
48
+ for (const [key, value] of Object.entries(rest)) {
49
+ if (!UNSAFE_KEYS.has(key)) {
50
+ safeRest[key] = value;
51
+ }
52
+ }
53
+ return {
54
+ agentId: agent_id.trim(),
55
+ apiKey: api_key.trim(),
56
+ ...typeof ws_url === "string" && ws_url.trim() !== "" ? { wsUrl: ws_url.trim() } : {},
57
+ ...typeof rest_url === "string" && rest_url.trim() !== "" ? { restUrl: rest_url.trim() } : {},
58
+ ...safeRest
59
+ };
60
+ }
61
+ function loadAgentConfig(agentKey, configPath) {
62
+ const filePath = configPath ?? DEFAULT_CONFIG_PATH;
63
+ let raw;
64
+ try {
65
+ raw = readFileSync(filePath, "utf-8");
66
+ } catch {
67
+ throw new ValidationError(
68
+ `Config file not found: ${filePath}. Copy agent_config.yaml.example to agent_config.yaml and configure your agents.`
69
+ );
70
+ }
71
+ const parsed = yaml.load(raw, { schema: yaml.JSON_SCHEMA });
72
+ if (!parsed || typeof parsed !== "object") {
73
+ throw new ValidationError(`Invalid config file: ${filePath}. Expected a YAML object.`);
74
+ }
75
+ const config = parsed;
76
+ let section;
77
+ if (agentKey && agentKey in config) {
78
+ const keyed = config[agentKey];
79
+ if (!keyed || typeof keyed !== "object") {
80
+ throw new ValidationError(
81
+ `Config key "${agentKey}" in ${filePath} must be an object with agent_id and api_key.`
82
+ );
83
+ }
84
+ section = normalizeKeys(keyed);
85
+ } else {
86
+ section = normalizeKeys(config);
87
+ }
88
+ const sourceLabel = agentKey && agentKey in config ? `${filePath} under key "${agentKey}"` : filePath;
89
+ return toAgentConfigResult(section, sourceLabel);
90
+ }
91
+ function loadAgentConfigFromEnv(options) {
92
+ const env = options?.env ?? process.env;
93
+ const prefix = options?.prefix === void 0 ? DEFAULT_ENV_PREFIX : options.prefix === "" || options.prefix.endsWith("_") ? options.prefix : `${options.prefix}_`;
94
+ const section = normalizeKeys({
95
+ agent_id: env[`${prefix}AGENT_ID`],
96
+ api_key: env[`${prefix}API_KEY`],
97
+ ws_url: env[`${prefix}WS_URL`],
98
+ rest_url: env[`${prefix}REST_URL`]
99
+ });
100
+ try {
101
+ return toAgentConfigResult(section, `environment variables (${prefix}AGENT_ID, ${prefix}API_KEY)`);
102
+ } catch (error) {
103
+ if (error instanceof ValidationError) {
104
+ throw new ValidationError(
105
+ `${error.message}. Set ${prefix}AGENT_ID and ${prefix}API_KEY, or use loadAgentConfig() for agent_config.yaml.`
106
+ );
107
+ }
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ export {
113
+ loadAgentConfig,
114
+ loadAgentConfigFromEnv
115
+ };
File without changes