@toolpack-sdk/agents 2.0.0-alpha.1
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 +827 -0
- package/dist/base-agent-CjrUlo6Y.d.cts +189 -0
- package/dist/base-agent-Cx2kWzLF.d.ts +189 -0
- package/dist/capabilities/index.cjs +17 -0
- package/dist/capabilities/index.d.cts +74 -0
- package/dist/capabilities/index.d.ts +74 -0
- package/dist/capabilities/index.js +17 -0
- package/dist/channels/index.cjs +3 -0
- package/dist/channels/index.d.cts +616 -0
- package/dist/channels/index.d.ts +616 -0
- package/dist/channels/index.js +3 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +334 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +20 -0
- package/dist/intent-classifier-agent-BLXXcbNJ.d.cts +45 -0
- package/dist/intent-classifier-agent-BLpDwKVf.d.ts +45 -0
- package/dist/interceptors/index.cjs +1 -0
- package/dist/interceptors/index.d.cts +539 -0
- package/dist/interceptors/index.d.ts +539 -0
- package/dist/interceptors/index.js +1 -0
- package/dist/registry/index.cjs +1 -0
- package/dist/registry/index.d.cts +159 -0
- package/dist/registry/index.d.ts +159 -0
- package/dist/registry/index.js +1 -0
- package/dist/testing/index.cjs +3 -0
- package/dist/testing/index.d.cts +389 -0
- package/dist/testing/index.d.ts +389 -0
- package/dist/testing/index.js +3 -0
- package/dist/types-BWoRx1ZE.d.cts +395 -0
- package/dist/types-BWoRx1ZE.d.ts +395 -0
- package/package.json +121 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { A as AgentInput, a as AgentResult, b as IAgentRegistry, d as AgentOutput, e as AgentInstance, C as ChannelInterface, P as PendingAsk, B as BaseAgentOptions } from './types-BWoRx1ZE.js';
|
|
2
|
+
export { c as AgentRunOptions, I as Interceptor, f as InterceptorChainConfig, g as InterceptorContext, h as InterceptorResult, N as NextFunction, S as SKIP_SENTINEL, W as WorkflowStep, i as isSkipSentinel, s as skip } from './types-BWoRx1ZE.js';
|
|
3
|
+
import { B as BaseAgent } from './base-agent-Cx2kWzLF.js';
|
|
4
|
+
export { A as AgentEvents } from './base-agent-Cx2kWzLF.js';
|
|
5
|
+
import { ModeConfig, ConversationStore, AssemblerOptions, AssembledPrompt } from 'toolpack-sdk';
|
|
6
|
+
export { AssembledPrompt, AssemblerOptions, ConversationScope, ConversationStore, GetOptions, InMemoryConversationStore, InMemoryConversationStoreConfig, Participant, PromptMessage, ConversationSearchOptions as SearchOptions, StoredMessage } from 'toolpack-sdk';
|
|
7
|
+
export { BaseChannel, DiscordChannel, DiscordChannelConfig, EmailChannel, EmailChannelConfig, SMSChannel, SMSChannelConfig, ScheduledChannel, ScheduledChannelConfig, SlackChannel, SlackChannelConfig, TelegramChannel, TelegramChannelConfig, WebhookChannel, WebhookChannelConfig } from './channels/index.js';
|
|
8
|
+
export { I as IntentClassification, a as IntentClassifierAgent, b as IntentClassifierInput } from './intent-classifier-agent-BLpDwKVf.js';
|
|
9
|
+
import { SummarizerAgent } from './capabilities/index.js';
|
|
10
|
+
export { HistoryTurn, SummarizerInput, SummarizerOutput } from './capabilities/index.js';
|
|
11
|
+
export { AddressCheckConfig, AddressCheckResult, CaptureHistoryConfig, ComposedChain, DepthExceededError, DepthGuardConfig, EventDedupConfig, IntentClassifierInterceptorConfig, InvocationDepthExceededError, NoiseFilterConfig, ParticipantResolverConfig, RateLimitConfig, SelfFilterConfig, TracerConfig, composeChain, createAddressCheckInterceptor, createCaptureInterceptor, createDepthGuardInterceptor, createEventDedupInterceptor, createIntentClassifierInterceptor, createNoiseFilterInterceptor, createParticipantResolverInterceptor, createRateLimitInterceptor, createSelfFilterInterceptor, createTracerInterceptor, executeChain } from './interceptors/index.js';
|
|
12
|
+
import 'events';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Transport interface for agent-to-agent communication.
|
|
16
|
+
* Enables pluggable transport mechanisms (local, JSON-RPC, etc.)
|
|
17
|
+
*/
|
|
18
|
+
interface AgentTransport {
|
|
19
|
+
/**
|
|
20
|
+
* Invoke a remote agent by name.
|
|
21
|
+
* @param agentName The name of the target agent
|
|
22
|
+
* @param input The input to send to the agent
|
|
23
|
+
* @returns The agent's result
|
|
24
|
+
*/
|
|
25
|
+
invoke(agentName: string, input: AgentInput): Promise<AgentResult>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for configuring the AgentRegistry transport.
|
|
29
|
+
*/
|
|
30
|
+
interface AgentRegistryTransportOptions {
|
|
31
|
+
/** Transport implementation for cross-process communication */
|
|
32
|
+
transport?: AgentTransport;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Optional coordinator for multi-agent deployments.
|
|
37
|
+
*
|
|
38
|
+
* Accepts a list of agent instances (each carrying its own channels and
|
|
39
|
+
* interceptors). On `start()` it wires the registry reference into every agent
|
|
40
|
+
* so cross-agent features (sendTo, delegation, ask) work, then delegates
|
|
41
|
+
* channel lifecycle to each agent's own `start()` method.
|
|
42
|
+
*
|
|
43
|
+
* For a single-agent deployment you do not need this class at all — just call
|
|
44
|
+
* `agent.start()` directly.
|
|
45
|
+
*/
|
|
46
|
+
declare class AgentRegistry implements IAgentRegistry {
|
|
47
|
+
private agentList;
|
|
48
|
+
private instances;
|
|
49
|
+
private channels;
|
|
50
|
+
/** Transport for agent-to-agent communication */
|
|
51
|
+
_transport: AgentTransport;
|
|
52
|
+
/** In-memory store for pending human-in-the-loop questions. Stored as Map<conversationId, PendingAsk[]> */
|
|
53
|
+
private pendingAsks;
|
|
54
|
+
/**
|
|
55
|
+
* @param agents Agent instances to coordinate. Each agent's `channels` and
|
|
56
|
+
* `interceptors` are configured on the agent itself.
|
|
57
|
+
* @param options Optional transport override.
|
|
58
|
+
*/
|
|
59
|
+
constructor(agents: BaseAgent[], options?: AgentRegistryTransportOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Start all agents.
|
|
62
|
+
*
|
|
63
|
+
* For each agent:
|
|
64
|
+
* 1. Ensures the agent's Toolpack instance is ready.
|
|
65
|
+
* 2. Sets `agent._registry = this` so cross-agent features are available
|
|
66
|
+
* when the agent's channels start processing messages.
|
|
67
|
+
* 3. Registers named channels in the registry's routing table for `sendTo()`.
|
|
68
|
+
* 4. Calls `agent.start()` which binds message handlers and begins listening.
|
|
69
|
+
*/
|
|
70
|
+
start(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Send output to a named channel.
|
|
73
|
+
*/
|
|
74
|
+
sendTo(channelName: string, output: AgentOutput): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Get a registered agent instance by name.
|
|
77
|
+
*/
|
|
78
|
+
getAgent(name: string): AgentInstance | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Get all registered agent instances.
|
|
81
|
+
*/
|
|
82
|
+
getAllAgents(): AgentInstance[];
|
|
83
|
+
/**
|
|
84
|
+
* Get a registered channel by name.
|
|
85
|
+
*/
|
|
86
|
+
getChannel(name: string): ChannelInterface | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Invoke an agent by name through the transport layer.
|
|
89
|
+
* Used by BaseAgent.delegate() and BaseAgent.delegateAndWait().
|
|
90
|
+
*/
|
|
91
|
+
invoke(agentName: string, input: AgentInput): Promise<AgentResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Stop all agents and clean up resources.
|
|
94
|
+
*/
|
|
95
|
+
stop(): Promise<void>;
|
|
96
|
+
getPendingAsk(conversationId: string): PendingAsk | undefined;
|
|
97
|
+
hasPendingAsks(conversationId: string): boolean;
|
|
98
|
+
cleanupExpiredAsks(): number;
|
|
99
|
+
addPendingAsk(ask: Omit<PendingAsk, 'id' | 'askedAt' | 'retries' | 'status'>): PendingAsk;
|
|
100
|
+
incrementRetries(id: string): number | undefined;
|
|
101
|
+
resolvePendingAsk(id: string, answer: string): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Custom error class for agent-related errors.
|
|
106
|
+
*/
|
|
107
|
+
declare class AgentError extends Error {
|
|
108
|
+
constructor(message: string);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
declare class ResearchAgent extends BaseAgent {
|
|
112
|
+
name: string;
|
|
113
|
+
description: string;
|
|
114
|
+
mode: ModeConfig;
|
|
115
|
+
constructor(options: BaseAgentOptions);
|
|
116
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare class CodingAgent extends BaseAgent {
|
|
120
|
+
name: string;
|
|
121
|
+
description: string;
|
|
122
|
+
mode: ModeConfig;
|
|
123
|
+
constructor(options: BaseAgentOptions);
|
|
124
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
declare class DataAgent extends BaseAgent {
|
|
128
|
+
name: string;
|
|
129
|
+
description: string;
|
|
130
|
+
mode: ModeConfig;
|
|
131
|
+
constructor(options: BaseAgentOptions);
|
|
132
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
declare class BrowserAgent extends BaseAgent {
|
|
136
|
+
name: string;
|
|
137
|
+
description: string;
|
|
138
|
+
mode: ModeConfig;
|
|
139
|
+
constructor(options: BaseAgentOptions);
|
|
140
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Local transport for same-process agent delegation.
|
|
145
|
+
* Resolves agents via the AgentRegistry and calls invokeAgent() directly.
|
|
146
|
+
*
|
|
147
|
+
* Also captures delegated exchanges into the target agent's `conversationHistory`
|
|
148
|
+
* so that the peer-agent's store reflects the full dialogue, including turns
|
|
149
|
+
* initiated by other agents rather than human users.
|
|
150
|
+
*/
|
|
151
|
+
declare class LocalTransport implements AgentTransport {
|
|
152
|
+
private registry;
|
|
153
|
+
constructor(registry: IAgentRegistry);
|
|
154
|
+
invoke(agentName: string, input: AgentInput): Promise<AgentResult>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* JSON-RPC transport for cross-process agent communication.
|
|
159
|
+
* Calls remote agents via JSON-RPC 2.0 over HTTP.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const transport = new JsonRpcTransport({
|
|
164
|
+
* agents: {
|
|
165
|
+
* 'data-agent': 'http://localhost:3000',
|
|
166
|
+
* 'research-agent': 'http://remote-server:3000',
|
|
167
|
+
* }
|
|
168
|
+
* });
|
|
169
|
+
*
|
|
170
|
+
* const registry = new AgentRegistry(registrations, { transport });
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare class JsonRpcTransport implements AgentTransport {
|
|
174
|
+
private agentUrls;
|
|
175
|
+
constructor(options: {
|
|
176
|
+
/** Map of agent names to their JSON-RPC server URLs */
|
|
177
|
+
agents: Record<string, string>;
|
|
178
|
+
});
|
|
179
|
+
invoke(agentName: string, input: AgentInput): Promise<AgentResult>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* JSON-RPC 2.0 server for hosting multiple agents.
|
|
184
|
+
* Exposes agents via standard JSON-RPC protocol over HTTP.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* const server = new AgentJsonRpcServer({ port: 3000 });
|
|
189
|
+
* server.registerAgent('data-agent', new DataAgent(toolpack));
|
|
190
|
+
* server.registerAgent('email-agent', new EmailAgent(toolpack));
|
|
191
|
+
* server.listen();
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
declare class AgentJsonRpcServer {
|
|
195
|
+
private agents;
|
|
196
|
+
private server?;
|
|
197
|
+
private port;
|
|
198
|
+
constructor(options: {
|
|
199
|
+
port: number;
|
|
200
|
+
});
|
|
201
|
+
/**
|
|
202
|
+
* Register an agent with the server.
|
|
203
|
+
* @param name The agent name (used in JSON-RPC method calls)
|
|
204
|
+
* @param agent The agent instance
|
|
205
|
+
*/
|
|
206
|
+
registerAgent(name: string, agent: BaseAgent): void;
|
|
207
|
+
/**
|
|
208
|
+
* Start the JSON-RPC server.
|
|
209
|
+
*/
|
|
210
|
+
listen(): void;
|
|
211
|
+
/**
|
|
212
|
+
* Stop the server.
|
|
213
|
+
*/
|
|
214
|
+
stop(): Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Handle a JSON-RPC request.
|
|
217
|
+
*/
|
|
218
|
+
private handleRequest;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Assemble a prompt slice from conversation history for a specific agent.
|
|
223
|
+
*
|
|
224
|
+
* This is the function that actually controls token cost. It:
|
|
225
|
+
* 1. Loads a scoped, time-windowed slice of history from the store.
|
|
226
|
+
* 2. Optionally filters to turns where the agent was involved (addressed-only mode).
|
|
227
|
+
* 3. Triggers rolling summarisation via `SummarizerAgent` when the turn count
|
|
228
|
+
* exceeds `options.rollingSummaryThreshold`.
|
|
229
|
+
* 4. Projects each `StoredMessage` into the LLM's role-based format from the
|
|
230
|
+
* current agent's point of view.
|
|
231
|
+
* 5. Enforces a hard token budget, filling priority slots top-down.
|
|
232
|
+
*
|
|
233
|
+
* @param store The conversation store to read from.
|
|
234
|
+
* @param conversationId The conversation to load.
|
|
235
|
+
* @param agentId The current agent's stable id (its registered name).
|
|
236
|
+
* @param agentName The current agent's display name.
|
|
237
|
+
* @param options Tuning knobs — scope, budget, addressed-only mode, etc.
|
|
238
|
+
* @param summarizer Optional `SummarizerAgent` instance for rolling summaries.
|
|
239
|
+
* When omitted, old turns are simply dropped when the
|
|
240
|
+
* threshold is exceeded.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```ts
|
|
244
|
+
* const prompt = await assemblePrompt(store, conversationId, agent.name, agent.name, {
|
|
245
|
+
* scope: 'channel',
|
|
246
|
+
* tokenBudget: 3000,
|
|
247
|
+
* addressedOnlyMode: true,
|
|
248
|
+
* rollingSummaryThreshold: 40,
|
|
249
|
+
* }, summarizerAgent);
|
|
250
|
+
*
|
|
251
|
+
* const response = await llm.chat([
|
|
252
|
+
* { role: 'system', content: agent.systemPrompt },
|
|
253
|
+
* ...prompt.messages,
|
|
254
|
+
* { role: 'user', content: triggeringMessage },
|
|
255
|
+
* ]);
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
declare function assemblePrompt(store: ConversationStore, conversationId: string, agentId: string, agentName: string, options?: AssemblerOptions, summarizer?: SummarizerAgent): Promise<AssembledPrompt>;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Configuration for the conversation search tool.
|
|
262
|
+
*/
|
|
263
|
+
interface ConversationSearchToolConfig {
|
|
264
|
+
/**
|
|
265
|
+
* Maximum number of results the tool can return.
|
|
266
|
+
* Prevents the model from expanding context unboundedly.
|
|
267
|
+
* Default: 10.
|
|
268
|
+
*/
|
|
269
|
+
maxResults?: number;
|
|
270
|
+
/**
|
|
271
|
+
* Rough token cap for the total search results returned.
|
|
272
|
+
* Results are dropped (whole messages, newest-first) once the running
|
|
273
|
+
* token count would exceed this cap. The first matching message is
|
|
274
|
+
* always included even if it alone exceeds the cap.
|
|
275
|
+
* Default: 2000.
|
|
276
|
+
*/
|
|
277
|
+
tokenCap?: number;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* A tool definition compatible with the Toolpack / Anthropic tool-use format.
|
|
281
|
+
*/
|
|
282
|
+
interface ConversationSearchTool {
|
|
283
|
+
name: string;
|
|
284
|
+
description: string;
|
|
285
|
+
input_schema: {
|
|
286
|
+
type: 'object';
|
|
287
|
+
properties: Record<string, {
|
|
288
|
+
type: string;
|
|
289
|
+
description: string;
|
|
290
|
+
}>;
|
|
291
|
+
required: string[];
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* Execute the tool with the given input.
|
|
295
|
+
* Returns a plain-text result ready to pass back as a tool result message.
|
|
296
|
+
*/
|
|
297
|
+
execute: (input: {
|
|
298
|
+
query: string;
|
|
299
|
+
}) => Promise<string>;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Creates a conversation search tool that the LLM can call during reasoning.
|
|
303
|
+
*
|
|
304
|
+
* The tool is **scope-locked** — it only searches the provided `conversationId`
|
|
305
|
+
* and never crosses conversation boundaries.
|
|
306
|
+
*
|
|
307
|
+
* Results are **token-capped** — the store truncates content to fit within
|
|
308
|
+
* `tokenCap` so the model cannot expand its context window by searching
|
|
309
|
+
* repeatedly.
|
|
310
|
+
*
|
|
311
|
+
* @param store The conversation store to search against.
|
|
312
|
+
* @param conversationId The current conversation id (scope lock).
|
|
313
|
+
* @param config Optional tuning (maxResults, tokenCap).
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```ts
|
|
317
|
+
* const tool = createConversationSearchTool(store, input.conversationId, {
|
|
318
|
+
* maxResults: 5,
|
|
319
|
+
* tokenCap: 1500,
|
|
320
|
+
* });
|
|
321
|
+
*
|
|
322
|
+
* // Pass to the LLM as a tool definition:
|
|
323
|
+
* const response = await llm.chat(messages, { tools: [tool] });
|
|
324
|
+
*
|
|
325
|
+
* // When the model calls the tool:
|
|
326
|
+
* if (response.toolCall?.name === tool.name) {
|
|
327
|
+
* const result = await tool.execute(response.toolCall.input);
|
|
328
|
+
* // Feed result back as a tool result message...
|
|
329
|
+
* }
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
declare function createConversationSearchTool(store: ConversationStore, conversationId: string, config?: ConversationSearchToolConfig): ConversationSearchTool;
|
|
333
|
+
|
|
334
|
+
export { AgentError, AgentInput, AgentInstance, AgentJsonRpcServer, AgentOutput, AgentRegistry, type AgentRegistryTransportOptions, AgentResult, type AgentTransport, BaseAgent, BaseAgentOptions, BrowserAgent, ChannelInterface, CodingAgent, type ConversationSearchTool, type ConversationSearchToolConfig, DataAgent, IAgentRegistry, JsonRpcTransport, LocalTransport, PendingAsk, ResearchAgent, SummarizerAgent, assemblePrompt, createConversationSearchTool };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import{EventEmitter as Me}from"events";import{Toolpack as Ne,InMemoryConversationStore as Oe}from"toolpack-sdk";var S=Symbol("interceptor-skip-sentinel");function b(i){return i===S}function $(){return S}var M=class extends Error{constructor(e,t){super(`Invocation depth ${e} exceeds maximum ${t}`),this.name="InvocationDepthExceededError"}};function D(i,e,t,n,r={}){let s=r.maxInvocationDepth??5;return{async execute(o){let d=(p=>({agent:e,channel:t,registry:n,invocationDepth:p,delegateAndWait:async(h,l)=>{let g=p+1;if(g>s)throw new M(g,s);if(!n)throw new Error(`Cannot delegate to "${h}": agent is running in standalone mode without a registry`);let I=n.getAgent(h);if(!I)throw new Error(`Agent "${h}" not found for delegation`);let f={message:l.message??"",intent:l.intent,data:l.data,context:l.context,conversationId:l.conversationId??o.conversationId??`delegation-${Date.now()}`};return await I.invokeAgent(f)},skip:$}))(0),c=async p=>{let h=p??o;return await e.invokeAgent(h)};for(let p=i.length-1;p>=0;p--){let h=i[p],l=c;c=async g=>await h(g??o,d,l)}return await c()}}}async function j(i,e){let t=await i.execute(e);return t===S?null:t}import{randomUUID as ve}from"crypto";function be(i){let e=i.context??{},t=e.channelType;return t==="im"||t==="private"||t==="dm"?"dm":e.threadId!==void 0?"thread":"channel"}var N=Symbol.for("toolpack:capture-history");function O(i){let e=i.captureAgentReplies??!0,t=i.getScope??be,n=i.getMessageId??(o=>o.context?.messageId??o.context?.eventId??ve()),r=i.getMentions??(o=>o.context?.mentions??[]),s=async(o,a,d)=>{let c=o.conversationId;if(!c)return a.logger?.warn("[capture-history] Message has no conversationId \u2014 skipping capture"),await d();let p=o.participant;if(p){let l={id:n(o),conversationId:c,participant:p,content:o.message??"",timestamp:new Date().toISOString(),scope:t(o),metadata:{channelType:o.context?.channelType,threadId:o.context?.threadId,messageId:o.context?.messageId,mentions:r(o),channelName:o.context?.channelName,channelId:o.context?.channelId}};try{await i.store.append(l),i.onCaptured?.(l),a.logger?.debug("[capture-history] Captured inbound message",{messageId:l.id,participantId:p.id,conversationId:c})}catch(g){a.logger?.warn("[capture-history] Failed to store inbound message",{error:g instanceof Error?g.message:String(g)})}}let h=await d();if(e&&!b(h)&&h.output!=null){let l={kind:"agent",id:a.agent.name,displayName:a.agent.name},g={id:ve(),conversationId:c,participant:l,content:h.output,timestamp:new Date().toISOString(),scope:t(o),metadata:{channelType:o.context?.channelType,threadId:o.context?.threadId,channelName:o.context?.channelName,channelId:o.context?.channelId}};try{await i.store.append(g),i.onCaptured?.(g),a.logger?.debug("[capture-history] Captured agent reply",{messageId:g.id,agentId:a.agent.name,conversationId:c})}catch(I){a.logger?.warn("[capture-history] Failed to store agent reply",{error:I instanceof Error?I.message:String(I)})}}return h};return s[N]=!0,s}import{randomUUID as Re}from"crypto";function we(i){return Math.ceil(i.length/4)}function Te(i){return{id:i.id,participant:i.participant,content:i.content,timestamp:i.timestamp}}function Pe(i,e){let{participant:t,content:n}=i;return t.kind==="system"?{role:"system",content:n}:t.kind==="agent"?t.id===e?{role:"assistant",content:n}:{role:"user",content:`${t.displayName??t.id} (agent): ${n}`}:{role:"user",content:`${t.displayName??t.id}: ${n}`}}function Ee(i,e,t){return!!(i.participant.id===e||i.metadata?.mentions?.some(n=>t.has(n)))}async function F(i,e,t,n,r={},s){let{scope:o,addressedOnlyMode:a=!0,tokenBudget:d=3e3,rollingSummaryThreshold:c=40,timeWindowMinutes:p,maxTurnsToLoad:h=100,agentAliases:l}=r,g=new Set([t,...l??[]]),I=p!==void 0?new Date(Date.now()-p*60*1e3).toISOString():void 0,f=await i.get(e,{scope:o,sinceTimestamp:I,limit:h}),_=f.length;if(a){let C=new Set;for(let k=0;k<f.length;k++){let E=f[k];if(Ee(E,t,g)&&C.add(E.id),k<f.length-1){let x=f[k+1];x.participant.kind==="agent"&&x.participant.id===t&&C.add(E.id)}}let A=f[f.length-1];A&&C.add(A.id),f=f.filter(k=>C.has(k.id))}let H=!1;if(f.length>c&&s){let C=Math.floor(f.length/2),A=f.slice(0,C),k=f.slice(C),E=A.filter(x=>!x.metadata?.isSummary);try{let x=await s.invokeAgent({message:"summarize",data:{turns:E.map(Te),agentName:n,agentId:t,maxTokens:Math.floor(d*.25),extractDecisions:!0}}),ye=JSON.parse(x.output),Ie={id:`summary-${Re()}`,conversationId:e,participant:{kind:"system",id:"summarizer"},content:`[Summary of ${ye.turnsSummarized} earlier turns]: ${ye.summary}`,timestamp:A[0].timestamp,scope:o??"channel",metadata:{isSummary:!0}};f=[Ie,...k],H=!0;try{await i.append(Ie),await i.deleteMessages(e,A.map(Se=>Se.id))}catch{}}catch{f=f.slice(-c)}}else f.length>c&&(f=f.slice(-c));let P=f.map(C=>Pe(C,t));if(P.length===0)return{messages:[],estimatedTokens:0,turnsLoaded:_,hasSummary:H};let he=P[P.length-1],fe=[he],W=we(he.content);for(let C=P.length-2;C>=0;C--){let A=P[C],k=we(A.content);if(W+k>d)break;fe.unshift(A),W+=k}return{messages:fe,estimatedTokens:W,turnsLoaded:_,hasSummary:H}}var y=class extends Error{constructor(e){super(e),this.name="AgentError"}};var w=class extends Me{provider;model;workflow;conversationHistory;assemblerOptions;channels=[];interceptors=[];_registry;_triggeringChannel;_conversationId;_isTriggerChannel;toolpack;_initConfig;_ownedToolpack=!1;_conversationLocks=new Map;constructor(e){super(),this.conversationHistory=new Oe,"toolpack"in e?this.toolpack=e.toolpack:this._initConfig=e}async _ensureToolpack(){if(!this.toolpack){if(!this._initConfig)throw new Error(`[${this.name??"agent"}] Cannot start: no apiKey or toolpack provided`);this.toolpack=await Ne.init({provider:this._initConfig.provider??"anthropic",apiKey:this._initConfig.apiKey,model:this._initConfig.model}),this._ownedToolpack=!0}}async start(){await this._ensureToolpack(),this.mode&&(typeof this.mode=="string"?this.toolpack.setMode(this.mode):(this.toolpack.registerMode(this.mode),this.toolpack.setMode(this.mode.name)));for(let e of this.channels)this._bindChannel(e),e.listen()}async stop(){for(let e of this.channels)"stop"in e&&typeof e.stop=="function"&&await e.stop();this._ownedToolpack&&await this.toolpack.disconnect?.()}async run(e,t,n){let r=n?.conversationId??this._conversationId;await this.onBeforeRun({message:e,conversationId:r}),this.emit("agent:start",{message:e});try{typeof this.mode=="string"?this.toolpack.setMode(this.mode):(this.toolpack.registerMode(this.mode),this.toolpack.setMode(this.mode.name));let s=[];if(r)try{let c=await F(this.conversationHistory,r,this.name,this.name,this._resolveAssemblerOptions()),p=c.messages[c.messages.length-1],h=e.trim(),g=h!==""&&p?.role==="user"&&typeof p.content=="string"&&(p.content===h||p.content.endsWith(`: ${h}`))?c.messages.slice(0,-1):c.messages;s.push(...g)}catch{}e.trim()&&s.push({role:"user",content:e});let o=[];if(r){let c=this.conversationHistory;o.push({name:"conversation_search",displayName:"Conversation Search",description:"Search past conversation history for specific information, questions, or topics mentioned earlier in this conversation.",category:"search",parameters:{type:"object",properties:{query:{type:"string",description:"Keywords or phrases to search for in conversation history."},limit:{type:"number",description:"Maximum number of results to return (default: 5)."}},required:["query"]},execute:async p=>{let h=await c.search(r,String(p.query??""),{limit:typeof p.limit=="number"?p.limit:5});return{results:h.map(l=>({role:l.participant.kind==="agent"?"assistant":"user",content:l.content,timestamp:l.timestamp})),count:h.length}}})}let a=await this.toolpack.generate({messages:s,model:this.model||"",requestTools:o.length>0?o:void 0},this.provider),d={output:a.content||"",steps:this.extractSteps(a),metadata:a.usage?{usage:a.usage}:void 0};return await this.onComplete(d),this.emit("agent:complete",d),d}catch(s){throw await this.onError(s),this.emit("agent:error",s),s}}getAgentAliases(){let e=[];for(let t of this.channels){let n=t.botUserId;n&&e.push(n)}return e}async sendTo(e,t){if(!this._registry)throw new Error("Agent not registered - _registry not set");await this._registry.sendTo(e,{output:t})}async ask(e,t){if(!this._registry)throw new y("Agent not registered - cannot use ask()");if(!this._conversationId)throw new y("No conversationId available - ask() requires a conversation channel");if(this._isTriggerChannel)throw new y("this.ask() called from a trigger channel (ScheduledChannel). Trigger channels have no human recipient \u2014 use a conversation channel (Slack, Telegram, Webhook) instead.");if(!this._triggeringChannel||this._triggeringChannel.trim()==="")throw new y("Cannot use ask() - no triggering channel available. The channel must have a name registered with AgentRegistry.");let n=this._registry.addPendingAsk({conversationId:this._conversationId,agentName:this.name,question:e,context:t?.context??{},maxRetries:t?.maxRetries??2,expiresAt:t?.expiresIn?new Date(Date.now()+t.expiresIn):void 0,channelName:this._triggeringChannel});return await this.sendTo(this._triggeringChannel,e),{output:e,metadata:{waitingForHuman:!0,askId:n.id}}}getPendingAsk(e){if(!this._registry)return null;let t=e??this._conversationId;return t?this._registry.getPendingAsk(t)??null:null}async resolvePendingAsk(e,t){if(!this._registry)throw new y("Agent not registered - cannot resolve ask");await this._registry.resolvePendingAsk(e,t)}async evaluateAnswer(e,t,n){return n?.simpleValidation?n.simpleValidation(t):(await this.run(`Evaluate if this answer sufficiently addresses the question.
|
|
2
|
+
|
|
3
|
+
Question: "${e}"
|
|
4
|
+
Answer: "${t}"
|
|
5
|
+
|
|
6
|
+
Is this answer sufficient? Reply with ONLY "yes" or "no".`,{workflow:{mode:"single-shot"}})).output.toLowerCase().trim().startsWith("yes")}async handlePendingAsk(e,t,n,r){return await this.evaluateAnswer(e.question,t,{simpleValidation:o=>o.trim().length>3})?(await this.resolvePendingAsk(e.id,t),n(t)):e.retries>=e.maxRetries?(await this.resolvePendingAsk(e.id,"__insufficient__"),this._triggeringChannel&&await this.sendTo(this._triggeringChannel,"I was unable to get enough information to proceed. Skipping this step."),r?r():{output:"Step skipped due to insufficient input.",metadata:{skipped:!0,askId:e.id}}):(this._registry?.incrementRetries(e.id),this.ask(`I need a bit more clarity on: "${e.question}". Could you provide more details?`,{context:e.context,maxRetries:e.maxRetries}))}async delegate(e,t){if(!this._registry)throw new y("Agent not registered - cannot use delegate()");let n={message:t.message,intent:t.intent,data:t.data,context:{...t.context||{},delegatedBy:this.name},conversationId:t.conversationId||this._conversationId||`delegation-${Date.now()}`};this._registry.invoke(e,n).catch(r=>{console.error(`[${this.name}] Delegation to ${e} failed:`,r.message)})}async delegateAndWait(e,t){if(!this._registry)throw new y("Agent not registered - cannot use delegateAndWait()");let n={message:t.message,intent:t.intent,data:t.data,context:{...t.context||{},delegatedBy:this.name},conversationId:t.conversationId||this._conversationId||`delegation-${Date.now()}`};return await this._registry.invoke(e,n)}async onBeforeRun(e){}async onStepComplete(e){}async onComplete(e){}async onError(e){}_resolveAssemblerOptions(){let e=this.channels.map(r=>r.botUserId).filter(r=>typeof r=="string"&&r.length>0),t=this.assemblerOptions?.agentAliases??[];if(e.length===0&&t.length===0)return this.assemblerOptions;let n=Array.from(new Set([...t,...e]));return{...this.assemblerOptions,agentAliases:n}}_getEffectiveInterceptors(){return this.interceptors.some(t=>t[N]===!0)?this.interceptors:[O({store:this.conversationHistory}),...this.interceptors]}_bindChannel(e){e.onMessage(async t=>{if(!t.conversationId){console.warn(`[${this.name}] Message received without conversationId \u2014 skipping`);return}let n=await this._acquireConversationLock(t.conversationId),r=()=>{};try{this._triggeringChannel=e.name,this._isTriggerChannel=e.isTriggerChannel,this._conversationId=t.conversationId,r=this._attachWorkflowStepUpdates(e,t);let s=D(this._getEffectiveInterceptors(),this,e,this._registry??null),o=await j(s,t);if(o===null)return;let a={output:o.output,metadata:o.metadata};await e.send({output:a.output,metadata:{...a.metadata,conversationId:t.conversationId,...t.context}})}catch(s){let o=s instanceof Error?s.message:"Unknown error occurred";console.error(`[${this.name}] Error in agent invocation: ${o}`);try{await e.send({output:`Error: ${o}`,metadata:{conversationId:t.conversationId,error:!0,...t.context}})}catch(a){console.error(`[${this.name}] Failed to send error to channel: ${a}`)}}finally{r(),n()}})}_attachWorkflowStepUpdates(e,t){if(e.isTriggerChannel)return()=>{};let n=new Set,r=new Set,s=a=>{a?.id&&n.add(String(a.id))},o=(a,d)=>{if(!d?.id||!n.has(String(d.id))||!a?.result?.output||typeof a.result.output!="string"||d?.steps?.length&&Number(d.steps.length)<=1)return;let c=`${String(d.id)}:${String(a.id??a.number??"unknown")}`;if(r.has(c))return;r.add(c);let p=a.result.output.trim();if(!p)return;let h=p.length>3500?`${p.slice(0,3500)}
|
|
7
|
+
... [truncated]`:p,l=`Step ${a.number}: ${a.description||"Completed"}`;e.send({output:`${l}
|
|
8
|
+
|
|
9
|
+
${h}`,metadata:{conversationId:t.conversationId,...t.context}}).catch(g=>{let I=g instanceof Error?g.message:String(g);console.warn(`[${this.name}] Failed to send workflow step update: ${I}`)})};return this.toolpack.on("workflow:plan_created",s),this.toolpack.on("workflow:step_complete",o),()=>{this.toolpack.off("workflow:plan_created",s),this.toolpack.off("workflow:step_complete",o)}}async _acquireConversationLock(e){for(;this._conversationLocks.has(e);)try{await this._conversationLocks.get(e)}catch{}let t,n=new Promise(r=>{t=r});return this._conversationLocks.set(e,n),()=>{this._conversationLocks.delete(e),t()}}extractSteps(e){let t=e;if(t.plan&&typeof t.plan=="object"){let n=t.plan;if(Array.isArray(n.steps))return n.steps.map(r=>({number:r.number||0,description:r.description||"",status:r.status||"completed",result:r.result}))}if(Array.isArray(t.steps))return t.steps}};import{randomUUID as _e}from"crypto";import{randomUUID as Ce}from"crypto";var R=class{constructor(e){this.registry=e}registry;async invoke(e,t){let n=this.registry.getAgent(e);if(!n)throw new y(`Agent "${e}" not found in registry. Available agents: ${this.registry.getAllAgents().map(d=>d.name).join(", ")}`);let r=n.conversationHistory,s=t.conversationId,o=t.context?.delegatedBy;if(r&&s&&o){let d={id:t.context?.messageId??Ce(),conversationId:s,participant:{kind:"agent",id:o,displayName:o},content:t.message??"",timestamp:new Date().toISOString(),scope:"channel",metadata:{}};try{await r.append(d)}catch{}}let a=await n.invokeAgent(t);if(r&&s){let d={id:Ce(),conversationId:s,participant:{kind:"agent",id:e,displayName:e},content:a.output,timestamp:new Date().toISOString(),scope:"channel",metadata:{}};try{await r.append(d)}catch{}}return a}};var J=class{agentList;instances=new Map;channels=new Map;_transport;pendingAsks=new Map;constructor(e,t){this.agentList=e,this._transport=t?.transport||new R(this)}async start(){for(let e of this.agentList){await e._ensureToolpack(),e._registry=this,this.instances.set(e.name,e);for(let t of e.channels??[])t.name&&this.channels.set(t.name,t)}for(let e of this.agentList)await e.start()}async sendTo(e,t){let n=this.channels.get(e);if(!n)throw new Error(`No channel registered with name "${e}"`);await n.send(t)}getAgent(e){return this.instances.get(e)}getAllAgents(){return Array.from(this.instances.values())}getChannel(e){return this.channels.get(e)}async invoke(e,t){return this._transport.invoke(e,t)}async stop(){for(let e of this.agentList)await e.stop();this.instances.clear(),this.channels.clear(),this.pendingAsks.clear()}getPendingAsk(e){let t=this.pendingAsks.get(e);if(!t||t.length===0)return;let n=new Date;for(;t.length>0;){let r=t[0];if(r.expiresAt&&r.expiresAt<n)t.shift();else break}if(t.length===0){this.pendingAsks.delete(e);return}return t[0]}hasPendingAsks(e){let t=this.pendingAsks.get(e);if(!t||t.length===0)return!1;let n=new Date,r=t.filter(s=>!s.expiresAt||s.expiresAt>=n);return r.length===0?(this.pendingAsks.delete(e),!1):(r.length!==t.length&&this.pendingAsks.set(e,r),r.some(s=>s.status==="pending"))}cleanupExpiredAsks(){let e=0,t=new Date;for(let[n,r]of this.pendingAsks.entries()){let s=r.filter(o=>!o.expiresAt||o.expiresAt>=t);e+=r.length-s.length,s.length===0?this.pendingAsks.delete(n):s.length!==r.length&&this.pendingAsks.set(n,s)}return e}addPendingAsk(e){let t={...e,id:_e(),askedAt:new Date,retries:0,status:"pending"},n=this.pendingAsks.get(e.conversationId);return n?n.push(t):this.pendingAsks.set(e.conversationId,[t]),t}incrementRetries(e){for(let t of this.pendingAsks.values()){let n=t.find(r=>r.id===e);if(n)return n.retries+=1,n.retries}}async resolvePendingAsk(e,t){for(let[n,r]of this.pendingAsks.entries()){let s=r.findIndex(o=>o.id===e);if(s!==-1){r[s].status="answered",r[s].answer=t;let o=r[s].channelName;if(r.splice(s,1),r.length>0){let a=r[0];if(o&&o.trim()!=="")try{await this.sendTo(o,{output:a.question})}catch(d){console.error(`[AgentRegistry] Failed to auto-send next ask: ${d instanceof Error?d.message:"Unknown error"}`)}else console.warn(`[AgentRegistry] Cannot auto-send next ask: channelName is empty for conversation ${n}`)}r.length===0&&this.pendingAsks.delete(n);return}}throw new Error(`Pending ask with id "${e}" not found`)}};import{AGENT_MODE as $e}from"toolpack-sdk";var De={...$e,name:"research-agent-mode",systemPrompt:["You are a research agent specialized in web research and information gathering.","Use web.search to find relevant information, web.fetch to retrieve content, and web.scrape when needed.","Always cite your sources with URLs.","Provide comprehensive, well-structured summaries.","Flag any conflicting information or uncertainty in your findings."].join(" ")},q=class extends w{name="research-agent";description="Web research agent for summarization, fact-finding, competitive analysis, and trend monitoring";mode=De;constructor(e){super(e)}async invokeAgent(e){let t=await this.run(e.message||"",void 0,{conversationId:e.conversationId});return await this.onComplete(t),t}};import{CODING_MODE as je}from"toolpack-sdk";var Fe={...je,name:"coding-agent-mode",systemPrompt:["You are a coding agent specialized in software development tasks.","Use coding.* tools for code analysis, fs.* for file operations, and git.* for version control.","Write clean, idiomatic code following best practices.","Always verify your changes and check for potential issues.","Provide clear explanations of your code changes."].join(" ")},K=class extends w{name="coding-agent";description="Coding agent for code generation, refactoring, debugging, test writing, and code review";mode=Fe;constructor(e){super(e)}async invokeAgent(e){let t=await this.run(e.message||"",void 0,{conversationId:e.conversationId});return await this.onComplete(t),t}};import{AGENT_MODE as ze}from"toolpack-sdk";var Be={...ze,name:"data-agent-mode",systemPrompt:["You are a data agent specialized in database operations and data analysis.","Use db.* tools for database queries, fs.* for file operations, and http.* for API requests.","Generate clear, well-formatted reports and summaries.","Always validate data integrity and handle errors gracefully.","Provide insights and patterns when analyzing data."].join(" ")},G=class extends w{name="data-agent";description="Data agent for database queries, CSV generation, data analysis, reporting, and aggregation";mode=Be;constructor(e){super(e)}async invokeAgent(e){let t=await this.run(e.message||"",void 0,{conversationId:e.conversationId});return await this.onComplete(t),t}};import{CHAT_MODE as Le}from"toolpack-sdk";var Ue={...Le,name:"browser-agent-mode",systemPrompt:["You are a browser agent specialized in web interaction and content extraction.","Use web.fetch to retrieve pages, web.screenshot for visual content, and web.extract_links for navigation.","Follow links intelligently to gather comprehensive information.","Extract structured data from web pages when possible.","Be mindful of rate limits and respectful of website resources."].join(" ")},Y=class extends w{name="browser-agent";description="Browser agent for web browsing, form interaction, page extraction, and link following";mode=Ue;constructor(e){super(e)}async invokeAgent(e){let t=await this.run(e.message||"",void 0,{conversationId:e.conversationId});return await this.onComplete(t),t}};var v=class{name;_handler;onMessage(e){this._handler=e}async handleMessage(e){this._handler&&await this._handler(e)}};import{createHmac as He,timingSafeEqual as We}from"crypto";var V=class extends v{isTriggerChannel=!1;config;server;participantCache=new Map;botUserId;allowedChannels;constructor(e){super(),this.config={port:3e3,...e},this.name=e.name;let t=e.channel;this.allowedChannels=t==null?null:Array.isArray(t)?t:[t]}listen(){typeof process<"u"&&import("http").then(e=>{this.server=e.createServer((t,n)=>{this.handleRequest(t,n)}),this.server.listen(this.config.port,()=>{console.log(`[SlackChannel] Listening on port ${this.config.port}`),this.runStartupCheck().catch(()=>{})})}).catch(e=>{console.error("[SlackChannel] Failed to start HTTP server:",e)})}async runStartupCheck(){try{let t=await(await fetch("https://slack.com/api/auth.test",{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,"Content-Type":"application/json"}})).json();t.ok?(this.botUserId=t.user_id,console.log(`[SlackChannel] Connected as @${t.user} (${t.user_id}) in workspace "${t.team}" \u2014 ${t.url}`)):console.warn(`[SlackChannel] auth.test failed: ${t.error}. Check your bot token.`)}catch(e){console.warn("[SlackChannel] Startup self-check failed (network error):",e)}}verifySignature(e,t){let n=e["x-slack-request-timestamp"],r=e["x-slack-signature"];if(!n||!r||Array.isArray(n)||Array.isArray(r))return!1;let s=parseInt(n,10),o=Math.floor(Date.now()/1e3);if(isNaN(s)||Math.abs(o-s)>300)return!1;let a=`v0:${n}:${t}`,c=`v0=${He("sha256",this.config.signingSecret).update(a).digest("hex")}`;if(c.length!==r.length)return!1;try{return We(Buffer.from(c),Buffer.from(r))}catch{return!1}}async send(e){let t=e.metadata?.threadTs??e.metadata?.thread_ts??e.metadata?.threadId,r=e.metadata?.channelId??(this.allowedChannels&&this.allowedChannels.length>0?this.allowedChannels[0]:void 0);if(!r)throw new Error("[SlackChannel] Cannot send: no channel configured and metadata.channelId is missing. Provide a target via SlackChannelConfig.channel or output.metadata.channelId.");let s={channel:r,text:e.output};t&&(s.thread_ts=t);let o=await fetch("https://slack.com/api/chat.postMessage",{method:"POST",headers:{Authorization:`Bearer ${this.config.token}`,"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw new Error(`Failed to send Slack message: ${o.statusText}`);let a=await o.json();if(!a.ok)throw new Error(`Slack API error: ${a.error}`)}normalize(e){let t=e,n=t.text||"",r=t.ts,s=t.thread_ts,o=s!==void 0&&s!==r,a=t.user,d=a?{kind:"user",id:a}:void 0,c=/<@([A-Z0-9]+)>/g,p=[],h;for(;(h=c.exec(n))!==null;)p.push(h[1]);let l=t.channel;return{message:n,conversationId:o?s:l||r||"",data:t,participant:d,context:{user:a,channel:l,team:t.team,channelType:t.channel_type,threadId:o?s:void 0,mentions:p.length>0?p:void 0,channelId:l,channelName:typeof this.config.channel=="string"?this.config.channel:l}}}async resolveParticipant(e){let t=e.participant?.id??e.context?.user;if(!t)return;let n=this.participantCache.get(t);if(n)return n;try{let r=await fetch(`https://slack.com/api/users.info?user=${encodeURIComponent(t)}`,{method:"GET",headers:{Authorization:`Bearer ${this.config.token}`}});if(!r.ok)return{kind:"user",id:t};let s=await r.json();if(!s.ok||!s.user){let d={kind:"user",id:t};return this.participantCache.set(t,d),d}let o=s.user.profile?.display_name||s.user.profile?.real_name||s.user.real_name||s.user.name||t,a={kind:"user",id:t,displayName:o,metadata:{slackUser:s.user}};return this.participantCache.set(t,a),a}catch{return{kind:"user",id:t}}}invalidateParticipant(e){this.participantCache.delete(e)}shouldProcessEvent(e){let t=e.type;if(t!=="message"&&t!=="app_mention")return!1;if(this.allowedChannels!==null){let o=e.channel_type;if(!(o==="im"||o==="mpim")){let d=e.channel;if(!d||!this.allowedChannels.includes(d))return!1}}let n=e.user;if(this.botUserId&&n===this.botUserId)return!1;let r=e.bot_id;if(!r)return!0;let s=this.config.blockedBotIds??[];if(s.includes(r)||n!==void 0&&s.includes(n))return!1;if(this.config.allowedBotIds!==void 0){let o=this.config.allowedBotIds;return o.includes(r)||n!==void 0&&o.includes(n)}return!0}handleRequest(e,t){if(e.method!=="POST"){t.writeHead(405),t.end("Method not allowed");return}let n="";e.on("data",r=>{n+=r.toString()}),e.on("end",()=>{if(!this.verifySignature(e.headers,n)){t.writeHead(401),t.end("Invalid signature");return}try{let r=JSON.parse(n);if(r.type==="url_verification"){t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify({challenge:r.challenge}));return}if(r.type==="event_callback"&&r.event){let s=r.event;if(this.shouldProcessEvent(s)){let o=this.normalize(s);this.handleMessage(o)}else s.type==="user_change"&&s.user&&this.invalidateParticipant(s.user.id);t.writeHead(200),t.end("OK");return}t.writeHead(200),t.end("OK")}catch(r){console.error("[SlackChannel] Error handling request:",r),t.writeHead(400),t.end("Bad request")}})}async stop(){if(this.server)return new Promise(e=>{this.server.close(e)})}};var Z=class extends v{isTriggerChannel=!1;config;server;pendingResponses=new Map;constructor(e){super(),this.name=e.name,this.config={port:e.port??3e3,path:e.path??"/webhook"}}listen(){typeof process<"u"&&import("http").then(e=>{this.server=e.createServer((t,n)=>{this.handleRequest(t,n)}),this.server.listen(this.config.port,()=>{console.log(`[WebhookChannel] Listening on port ${this.config.port}${this.config.path}`)})}).catch(e=>{console.error("[WebhookChannel] Failed to start HTTP server:",e)})}async send(e){let t=e.metadata?.conversationId;if(t&&this.pendingResponses.has(t)){let n=this.pendingResponses.get(t);this.pendingResponses.delete(t),n.resolve({output:e.output,metadata:e.metadata})}}normalize(e){let t=e,n=t.headers||{},r=n["x-session-id"]||n["X-Session-Id"]||t.sessionId||t.conversationId||this.generateSessionId();return{message:t.message||t.text||"",intent:t.intent,conversationId:r,data:t,context:{headers:t.headers,method:t.method,sessionId:r}}}handleRequest(e,t){if(e.url!==this.config.path){t.writeHead(404),t.end("Not found");return}if(e.method!=="POST"){t.writeHead(405),t.end("Method not allowed");return}let n="";e.on("data",r=>{n+=r.toString()}),e.on("end",()=>{try{let r=JSON.parse(n),s=this.normalize(r),o=s.conversationId||this.generateSessionId(),a=new Promise((d,c)=>{this.pendingResponses.set(o,{resolve:d,reject:c}),setTimeout(()=>{this.pendingResponses.has(o)&&(this.pendingResponses.delete(o),c(new Error("Agent response timeout")))},3e4)});this.handleMessage({...s,conversationId:o,context:{...s.context,sessionId:o}}),a.then(d=>{t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(d))}).catch(d=>{t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:d.message}))})}catch(r){console.error("[WebhookChannel] Error handling request:",r),t.writeHead(400,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Bad request"}))}})}generateSessionId(){return`webhook-${Date.now()}-${Math.random().toString(36).substring(2,9)}`}async stop(){if(this.server)return new Promise(e=>{this.server.close(e)})}};import{CronExpressionParser as ke}from"cron-parser";var Q=class extends v{isTriggerChannel=!0;config;timer;constructor(e){super(),this.config=e,this.name=e.name;try{ke.parse(e.cron)}catch(t){throw new Error(`Invalid cron expression '${e.cron}': ${t.message}`)}}listen(){this.scheduleNextRun()}async send(e){let t=this.config.notify.indexOf(":");if(t===-1)throw new Error(`Invalid notify format: ${this.config.notify}. Expected format: 'webhook:https://...'`);let n=this.config.notify.substring(0,t),r=this.config.notify.substring(t+1);if(!n||!r)throw new Error(`Invalid notify format: ${this.config.notify}. Expected format: 'webhook:https://...'`);switch(n.toLowerCase()){case"webhook":await this.sendToWebhook(r,e);break;case"slack":throw new Error("ScheduledChannel no longer supports the 'slack:' notify protocol. Attach a named SlackChannel to the agent and route from inside run() via this.sendTo('<channelName>', output). See ScheduledChannelConfig.notify docs.");default:throw new Error(`Unknown notify protocol: ${n}`)}}normalize(e){let t=new Date,n=`${t.getFullYear()}-${t.getMonth()+1}-${t.getDate()}`;return{intent:this.config.intent,message:`Scheduled task triggered at ${t.toISOString()}`,conversationId:`scheduled:${this.name||"default"}:${n}`,data:{scheduled:!0,cron:this.config.cron,timestamp:t.toISOString()}}}async sendToWebhook(e,t){let n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({output:t.output,metadata:t.metadata,timestamp:new Date().toISOString()})});if(!n.ok)throw new Error(`Webhook notification failed: ${n.statusText}`)}getNextRunTime(){return ke.parse(this.config.cron,{currentDate:new Date}).next().toDate()}scheduleNextRun(){let e=this.getNextRunTime(),t=e.getTime()-Date.now();if(t<=0){this.scheduleNextRun();return}console.log(`[ScheduledChannel] Next run scheduled for ${e.toISOString()}`),this.timer=setTimeout(()=>{this.trigger(),this.scheduleNextRun()},t)}async trigger(){let e=this.normalize(null);try{await this.handleMessage(e)}catch(t){console.error("[ScheduledChannel] Error triggering scheduled task:",t)}}async stop(){this.timer&&(clearTimeout(this.timer),this.timer=void 0)}};var X=class extends v{isTriggerChannel=!1;config;offset=0;pollingInterval;server;botUserId;botUsername;constructor(e){super(),this.name=e.name,this.config=e}listen(){this.runStartupCheck().catch(()=>{}),this.config.webhookUrl?this.startWebhook():this.startPolling()}async runStartupCheck(){try{let t=await(await fetch(`https://api.telegram.org/bot${this.config.token}/getMe`)).json();if(t.ok&&t.result){let n=t.result;this.botUserId=n.id!=null?String(n.id):void 0,this.botUsername=n.username,console.log(`[TelegramChannel] Connected as @${n.username} (id: ${n.id}, name: ${n.first_name})`)}else console.warn(`[TelegramChannel] getMe failed: ${t.description??"unknown error"}. Check your bot token.`)}catch(e){console.warn("[TelegramChannel] Startup self-check failed (network error):",e)}}async send(e){let t=e.metadata?.chatId;if(!t)throw new Error("Telegram send requires chatId in metadata");let n=await fetch(`https://api.telegram.org/bot${this.config.token}/sendMessage`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({chat_id:t,text:e.output,parse_mode:"Markdown"})});if(!n.ok)throw new Error(`Failed to send Telegram message: ${n.statusText}`);let r=await n.json();if(!r.ok)throw new Error(`Telegram API error: ${r.description}`)}normalize(e){let t=e,n=t.message||t.edited_message||{},r=n.text||"",s=n.chat||{},o=n.from||{},a=o.id!=null?String(o.id):void 0,d=o.first_name||o.username||a,c=a?{kind:"user",id:a,displayName:d??a}:void 0,p=n.entities??[],h=[];for(let I of p)if(I.type==="text_mention"&&I.user){let f=I.user;f.id!=null&&h.push(String(f.id))}let l=s.type,g=s.id!=null?String(s.id):"";return{message:r,conversationId:g,data:t,participant:c,context:{chatId:s.id,userId:o.id,username:o.username,firstName:o.first_name,lastName:o.last_name,messageId:n.message_id,channelType:l,channelId:g,channelName:s.title,mentions:h.length>0?h:void 0}}}startPolling(){console.log("[TelegramChannel] Starting polling mode"),this.pollingInterval=setInterval(async()=>{try{await this.pollUpdates()}catch(e){console.error("[TelegramChannel] Polling error:",e)}},5e3)}async pollUpdates(){let e=`https://api.telegram.org/bot${this.config.token}/getUpdates?offset=${this.offset}&limit=100`,t=await fetch(e);if(!t.ok)throw new Error(`Telegram getUpdates failed: ${t.statusText}`);let n=await t.json();if(!n.ok)throw new Error("Telegram getUpdates returned not ok");for(let r of n.result){let s=r.update_id;s>=this.offset&&(this.offset=s+1);try{let o=this.normalize(r);await this.handleMessage(o)}catch(o){console.error("[TelegramChannel] Error processing update:",o)}}}startWebhook(){typeof process>"u"||(console.log("[TelegramChannel] Starting webhook mode"),import("http").then(e=>{this.server=e.createServer((r,s)=>{this.handleWebhookRequest(r,s)});let t=new URL(this.config.webhookUrl||"http://localhost:3000"),n=parseInt(t.port,10)||3e3;this.server.listen(n,()=>{console.log(`[TelegramChannel] Webhook server listening on port ${n}`)}),this.setWebhook()}).catch(e=>{console.error("[TelegramChannel] Failed to start webhook server:",e)}))}async setWebhook(){if(!this.config.webhookUrl)return;let e=await fetch(`https://api.telegram.org/bot${this.config.token}/setWebhook`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:this.config.webhookUrl})});if(!e.ok){console.error("[TelegramChannel] Failed to set webhook");return}let t=await e.json();t.ok?console.log("[TelegramChannel] Webhook set successfully"):console.error("[TelegramChannel] Failed to set webhook:",t.description)}handleWebhookRequest(e,t){if(e.method!=="POST"){t.writeHead(405),t.end("Method not allowed");return}let n="";e.on("data",r=>{n+=r.toString()}),e.on("end",()=>{try{let r=JSON.parse(n);this.handleMessage(this.normalize(r)).catch(s=>{console.error("[TelegramChannel] Error processing webhook:",s)}),t.writeHead(200),t.end("OK")}catch(r){console.error("[TelegramChannel] Error parsing webhook:",r),t.writeHead(400),t.end("Bad request")}})}async stop(){if(this.pollingInterval&&(clearInterval(this.pollingInterval),this.pollingInterval=void 0),this.server)return new Promise(e=>{this.server.close(e)});if(this.config.webhookUrl)try{await fetch(`https://api.telegram.org/bot${this.config.token}/deleteWebhook`,{method:"POST"})}catch(e){console.error("[TelegramChannel] Failed to delete webhook:",e)}}};var ee=class extends v{isTriggerChannel=!1;config;client;constructor(e){super(),this.config=e,this.name=e.name}listen(){typeof process<"u"&&import("discord.js").then(e=>{let{Client:t,GatewayIntentBits:n}=e;this.client=new t({intents:[n.Guilds,n.GuildMessages,n.MessageContent,n.DirectMessages]}),this.client.on("ready",()=>{console.log(`[DiscordChannel] Bot logged in as ${this.client.user?.tag}`)}),this.client.on("messageCreate",r=>{this.handleDiscordMessage(r)}),this.client.login(this.config.token).catch(r=>{console.error("[DiscordChannel] Failed to login to Discord:",r)})}).catch(e=>{console.error("[DiscordChannel] Failed to initialize Discord client:",e),console.error("[DiscordChannel] Make sure to install discord.js: npm install discord.js")})}async send(e){if(!this.client)throw new Error("Discord client not initialized. Did you call listen()?");try{let t=e.metadata?.channelId||this.config.channelId,n=await this.client.channels.fetch(t);if(!n||!("send"in n))throw new Error(`Channel ${t} not found or is not a text channel`);let r={content:e.output},s=e.metadata?.threadId;if(s){let o=await this.client.channels.fetch(s);if(o&&"send"in o){await o.send(r);return}}await n.send(r)}catch(t){throw console.error("[DiscordChannel] Failed to send Discord message:",t),new Error(`Failed to send Discord message: ${t instanceof Error?t.message:String(t)}`)}}normalize(e){let t=e,n=t.channelId,r=(n??"")+(t.thread?.id?`:${t.thread.id}`:""),s=t.channel?.type,o=s===1||s===3,a=t.author?.id,d=t.author?.globalName||t.author?.username;return{message:t.content,conversationId:r,data:t,participant:a?{kind:"user",id:a,displayName:d}:void 0,context:{userId:a,username:t.author?.username,channelType:o?"dm":"channel",channelId:n,channelName:t.channel?.name,guildId:t.guildId,threadId:t.thread?.id,messageId:t.id}}}handleDiscordMessage(e){if(e.author?.bot||e.channelId!==this.config.channelId||e.guildId!==this.config.guildId)return;let t=this.normalize(e);this.handleMessage(t)}async stop(){this.client&&(await this.client.destroy(),this.client=void 0)}};var te=class extends v{isTriggerChannel=!0;config;transporter;constructor(e){super(),this.config=e,this.name=e.name}listen(){typeof process<"u"&&import("nodemailer").then(e=>{this.transporter=e.default.createTransport({host:this.config.smtp.host,port:this.config.smtp.port,secure:this.config.smtp.secure??this.config.smtp.port===465,auth:{user:this.config.smtp.auth.user,pass:this.config.smtp.auth.pass}}),console.log(`[EmailChannel] Email transporter initialized for ${this.config.from}`)}).catch(e=>{console.error("[EmailChannel] Failed to initialize nodemailer:",e),console.error("[EmailChannel] Make sure to install nodemailer: npm install nodemailer")})}async send(e){if(!this.transporter)throw new Error("Email transporter not initialized. Did you call listen()?");let t=Array.isArray(this.config.to)?this.config.to:[this.config.to],n=this.config.subject||"Message from Agent",r={from:this.config.from,to:t.join(", "),subject:n,text:e.output,html:this.formatAsHtml(e.output)};try{let s=await this.transporter.sendMail(r);console.log(`[EmailChannel] Email sent: ${s.messageId}`)}catch(s){throw console.error("[EmailChannel] Failed to send email:",s),new Error(`Failed to send email: ${s instanceof Error?s.message:String(s)}`)}}normalize(e){throw new Error("EmailChannel is outbound-only. Use WebhookChannel with email webhook events for inbound email.")}formatAsHtml(e){return e.split(`
|
|
10
|
+
|
|
11
|
+
`).map(t=>`<p>${t.replace(/\n/g,"<br>")}</p>`).join("")}async stop(){this.transporter&&(this.transporter.close(),this.transporter=void 0)}};var ne=class extends v{config;twilioClient;server;constructor(e){super(),this.config={port:3e3,...e},this.name=e.name}get isTriggerChannel(){return!this.config.webhookPath}listen(){typeof process<"u"&&import("twilio").then(e=>{this.twilioClient=e.default(this.config.accountSid,this.config.authToken),console.log("[SMSChannel] Twilio client initialized"),this.config.webhookPath&&this.startWebhookServer()}).catch(e=>{console.error("[SMSChannel] Failed to initialize Twilio client:",e),console.error("[SMSChannel] Make sure to install twilio: npm install twilio")})}async send(e){if(!this.twilioClient)throw new Error("Twilio client not initialized. Did you call listen()?");let t=e.metadata?.from||this.config.to;if(!t)throw new Error('No recipient phone number specified. Set "to" in config or provide in output.metadata.from');try{let n=await this.twilioClient.messages.create({body:e.output,from:this.config.from,to:t});console.log(`[SMSChannel] SMS sent: ${n.sid}`)}catch(n){throw console.error("[SMSChannel] Failed to send SMS:",n),new Error(`Failed to send SMS: ${n instanceof Error?n.message:String(n)}`)}}normalize(e){let t=e,n=t.From,r=t.Body,s=t.MessageSid;return{message:r,conversationId:n,data:t,context:{from:n,to:t.To,messageSid:s}}}startWebhookServer(){import("http").then(e=>{this.server=e.createServer((t,n)=>{this.handleWebhookRequest(t,n)}),this.server.listen(this.config.port,()=>{console.log(`[SMSChannel] Webhook server listening on port ${this.config.port} at ${this.config.webhookPath}`)})}).catch(e=>{console.error("[SMSChannel] Failed to start webhook server:",e)})}handleWebhookRequest(e,t){if(e.method!=="POST"||e.url!==this.config.webhookPath){t.writeHead(404),t.end("Not found");return}let n="";e.on("data",r=>{n+=r.toString()}),e.on("end",()=>{try{let r=new URLSearchParams(n),s={};r.forEach((a,d)=>{s[d]=a});let o=this.normalize(s);this.handleMessage(o),t.writeHead(200,{"Content-Type":"text/xml"}),t.end('<?xml version="1.0" encoding="UTF-8"?><Response></Response>')}catch(r){console.error("[SMSChannel] Error handling webhook:",r),t.writeHead(400),t.end("Bad request")}})}async stop(){if(this.server)return new Promise(e=>{this.server.close(e)})}};var z=class{agentUrls;constructor(e){this.agentUrls=new Map(Object.entries(e.agents))}async invoke(e,t){let n=this.agentUrls.get(e);if(!n)throw new y(`Agent "${e}" not found in transport configuration. Available agents: ${Array.from(this.agentUrls.keys()).join(", ")}`);let r={jsonrpc:"2.0",method:`agent.invoke:${e}`,params:t,id:Date.now()};try{let s=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!s.ok)throw new y(`HTTP ${s.status}: ${s.statusText}`);let o=await s.json();if(o.error)throw new y(`JSON-RPC error (${o.error.code}): ${o.error.message}`+(o.error.data?` - ${JSON.stringify(o.error.data)}`:""));if(!o.result)throw new y("No result in JSON-RPC response");return o.result}catch(s){throw s instanceof y?s:new y(`Failed to invoke agent "${e}" at ${n}: ${s instanceof Error?s.message:String(s)}`)}}};import Je from"http";var B=class{agents=new Map;server;port;constructor(e){this.port=e.port}registerAgent(e,t){this.agents.set(e,t)}listen(){this.server=Je.createServer(async(e,t)=>{if(e.method!=="POST"){t.writeHead(405,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Method not allowed"}));return}let n="";e.on("data",r=>{n+=r.toString()}),e.on("end",async()=>{try{let r=JSON.parse(n),s=await this.handleRequest(r);t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}catch(r){let s={jsonrpc:"2.0",error:{code:-32700,message:"Parse error",data:r instanceof Error?r.message:String(r)},id:null};t.writeHead(200,{"Content-Type":"application/json"}),t.end(JSON.stringify(s))}})}),this.server.listen(this.port,()=>{console.log(`[AgentJsonRpcServer] Listening on port ${this.port}`),console.log(`[AgentJsonRpcServer] Registered agents: ${Array.from(this.agents.keys()).join(", ")}`)})}async stop(){return new Promise((e,t)=>{if(!this.server){e();return}this.server.close(n=>{n?t(n):(console.log("[AgentJsonRpcServer] Server stopped"),e())})})}async handleRequest(e){if(e.jsonrpc!=="2.0")return{jsonrpc:"2.0",error:{code:-32600,message:"Invalid Request",data:'jsonrpc must be "2.0"'},id:e.id||null};let[t,n]=e.method.split(":");if(t!=="agent.invoke")return{jsonrpc:"2.0",error:{code:-32601,message:"Method not found",data:`Unknown method: ${e.method}`},id:e.id||null};if(!n)return{jsonrpc:"2.0",error:{code:-32602,message:"Invalid params",data:'Agent name required in method (e.g., "agent.invoke:data-agent")'},id:e.id||null};let r=this.agents.get(n);if(!r)return{jsonrpc:"2.0",error:{code:-32602,message:"Invalid params",data:`Agent "${n}" not found. Available: ${Array.from(this.agents.keys()).join(", ")}`},id:e.id||null};if(!e.params)return{jsonrpc:"2.0",error:{code:-32602,message:"Invalid params",data:"params (AgentInput) required"},id:e.id||null};try{return{jsonrpc:"2.0",result:await r.invokeAgent(e.params),id:e.id||null}}catch(s){return{jsonrpc:"2.0",error:{code:-32603,message:"Internal error",data:s instanceof Error?s.message:String(s)},id:e.id||null}}}};import{CHAT_MODE as qe}from"toolpack-sdk";var Ke={...qe,name:"intent-classifier-mode",systemPrompt:["You classify whether a message is asking an agent to respond.","","Categories:","direct = Message uses @mention, name in greeting, possessive, or commands the agent to act","indirect = Agent is mentioned but unclear if response wanted (talking ABOUT, not TO them)","passive = No addressing detected; agent should only listen, not reply","ignore = Definitely not for this agent (noise, code blocks, other bots)","","Response must start with one of: direct, indirect, passive, ignore"].join(`
|
|
12
|
+
`)},L=class extends w{name="intent-classifier";description="Classifies whether a message is directly addressing an agent for response";mode=Ke;constructor(e){super(e)}async invokeAgent(e){let t=e.data;if(t?.isDirectMessage)return{output:"direct",metadata:{classification:"direct",shortCircuit:"dm"}};if(!t?.message)return{output:"ignore",metadata:{error:"No message provided for classification"}};let n=[];if(n.push(`Context: Public channel #${t.channelName}`),n.push(`Target agent: "${t.agentName}" (ID: ${t.agentId})`),n.push(`Message sender: ${t.senderName}`),t.recentContext&&t.recentContext.length>0){n.push(`
|
|
13
|
+
Recent conversation:`);for(let a of t.recentContext)n.push(` ${a.sender}: ${a.content.substring(0,100)}`)}n.push(`
|
|
14
|
+
Message to classify: "${t.message}"`),t.includeExamples&&(n.push(`
|
|
15
|
+
Examples of classifications:`),n.push(` "@${t.agentName} help me" \u2192 direct`),n.push(` "Can someone ask ${t.agentName} about this?" \u2192 indirect`),n.push(` "I was talking to ${t.agentName} earlier" \u2192 passive`),n.push(' "Check the logs" \u2192 ignore')),n.push(`
|
|
16
|
+
Classification (start with direct, indirect, passive, or ignore):`);let r=n.join(`
|
|
17
|
+
`),s=await this.run(r),o=this.normalizeClassification(s.output);return{output:o,metadata:{rawOutput:s.output,classification:o,confidence:"high"}}}normalizeClassification(e){let t=e.toLowerCase().trim().split(/\s+/)[0],n=e.toLowerCase();return["direct","indirect","passive","ignore"].includes(t)?t:n.includes("indirect")||n.includes("mention")?"indirect":n.includes("passive")||n.includes("listen")?"passive":n.includes("ignore")||n.includes("skip")?"ignore":n.includes("direct")||n.includes("addressed")?"direct":"ignore"}};import{CHAT_MODE as Ge}from"toolpack-sdk";var Ye={...Ge,name:"summarizer-mode",systemPrompt:["You are a conversation summarizer for multi-participant chat histories.","Your job is to compress older conversation turns into a dense summary that preserves:","","1. Key facts and information shared","2. Decisions made or action items assigned","3. Context relevant to the target agent's perspective","4. Important questions asked or problems raised","","Summarize from the perspective of the target agent.","If the agent was not addressed in a turn, note it as observed context.","Use bullet points for clarity. Be concise but complete.","","Output format: Return ONLY a JSON object with these fields:","- summary: string (the summary text)","- turnsSummarized: number (count of turns processed)","- hasDecisions: boolean (whether any decisions/action items were found)","- estimatedTokens: number (rough estimate: characters / 4)","","Do not include markdown code blocks, just the raw JSON."].join(`
|
|
18
|
+
`)},U=class extends w{name="summarizer";description="Compresses conversation history into compact summaries for prompt assembly";mode=Ye;constructor(e){super(e)}async invokeAgent(e){let t=e.data;if(!t?.turns||t.turns.length===0)return{output:JSON.stringify({summary:"(No history to summarize)",turnsSummarized:0,hasDecisions:!1,estimatedTokens:5}),metadata:{emptyInput:!0}};let n=t.maxTokens??800,r=t.extractDecisions??!0,s=[`Target agent: "${t.agentName}" (ID: ${t.agentId})`,`Maximum summary length: ~${n} tokens`,`Extract decisions/action items: ${r?"yes":"no"}`,"",`Conversation turns to summarize (${t.turns.length} turns):`,""];for(let c of t.turns){let p=new Date(c.timestamp).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"}),h=c.participant.displayName??c.participant.id,l=c.participant.kind==="agent"?`[BOT] ${h}`:h,g=`[${p}] ${l}: ${c.content.substring(0,200)}`;c.content.length>200&&(g+="..."),c.metadata?.isToolCall&&c.metadata.toolName&&(g+=` [tool: ${c.metadata.toolName}]`),s.push(g)}s.push("","Generate a JSON summary object:");let o=s.join(`
|
|
19
|
+
`),a=await this.run(o),d=this.parseSummarizerOutput(a.output,t.turns.length);return{output:JSON.stringify(d),metadata:{turnsProcessed:t.turns.length,rawOutputLength:a.output.length}}}parseSummarizerOutput(e,t){let n=e.trim(),r=n.match(/```(?:json)?\s*([\s\S]*?)\s*```/);r&&(n=r[1].trim());try{let s=JSON.parse(n);return{summary:typeof s.summary=="string"&&s.summary.length>0?s.summary:this.generateFallbackSummary(t),turnsSummarized:typeof s.turnsSummarized=="number"?s.turnsSummarized:t,hasDecisions:typeof s.hasDecisions=="boolean"?s.hasDecisions:!1,estimatedTokens:typeof s.estimatedTokens=="number"&&s.estimatedTokens>0?s.estimatedTokens:Math.ceil(e.length/4)}}catch{return{summary:this.generateFallbackSummary(t),turnsSummarized:t,hasDecisions:e.toLowerCase().includes("decision")||e.toLowerCase().includes("action"),estimatedTokens:Math.ceil(e.length/4)}}}generateFallbackSummary(e){return`(Summary of ${e} conversation turns - key details preserved in full context)`}};import{InMemoryConversationStore as Ae}from"toolpack-sdk";function xe(i,e,t={}){let n=t.maxResults??10,r=t.tokenCap??2e3,s={limit:n,tokenCap:r};return{name:"search_conversation_history",description:["Search the conversation history for messages matching a query.","Use this when you need to recall something specific that was said earlier","in this conversation but is not in your immediate context.","Results are limited to this conversation only."].join(" "),input_schema:{type:"object",properties:{query:{type:"string",description:"The search query \u2014 keywords or phrases to look for in the conversation history."}},required:["query"]},execute:async({query:o})=>{if(!o||o.trim()==="")return"Error: query must not be empty.";let a=await i.search(e,o.trim(),s);if(a.length===0)return`No messages found matching "${o}".`;let d=a.map(c=>{let p=c.participant.displayName??c.participant.id,h=c.participant.kind==="agent"?`${p} (agent)`:p;return`[${new Date(c.timestamp).toLocaleString("en-US",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}] ${h}: ${c.content}`});return[`Found ${a.length} result(s) for "${o}":`,"",...d].join(`
|
|
20
|
+
`)}}}var re=class{constructor(e){this.maxSize=e}maxSize;cache=new Map;has(e){return this.cache.has(e)}set(e,t){if(this.cache.has(e)&&this.cache.delete(e),this.cache.size>=this.maxSize){let n=this.cache.keys().next().value;n!==void 0&&this.cache.delete(n)}this.cache.set(e,t)}clear(){this.cache.clear()}size(){return this.cache.size}};function se(i={}){let e=i.maxCacheSize??1e3,t=i.getEventId??(r=>r.context?.eventId),n=new re(e);return async(r,s,o)=>{let a=t(r);if(a){if(n.has(a))return i.onDuplicate?.(a,r),s.logger?.debug(`Event dedup: dropping duplicate event ${a}`,{eventId:a}),s.skip();n.set(a,!0)}return await o()}}function oe(i){let e=i.getSubtype??(n=>n.context?.subtype),t=new Set(i.denySubtypes);return async(n,r,s)=>{let o=e(n);return o&&t.has(o)?(i.onFiltered?.(o,n),r.logger?.debug(`Noise filter: dropping message with subtype "${o}"`,{subtype:o}),r.skip()):await s()}}function ie(i){return async(e,t,n)=>{let r=i.getSenderId(e),s=i.agentId??t.agent.name;return r&&r===s?(i.onSelfMessage?.(r,e),t.logger?.debug(`Self filter: dropping self-message from ${r}`,{senderId:r,agentId:s}),t.skip()):await n()}}var ae=class{constructor(e){this.maxSize=e}maxSize;cache=new Map;get(e){let t=this.cache.get(e);return t!==void 0&&(this.cache.delete(e),this.cache.set(e,t)),t}set(e,t){if(this.cache.has(e))this.cache.delete(e);else if(this.cache.size>=this.maxSize){let n=this.cache.keys().next().value;n!==void 0&&this.cache.delete(n)}this.cache.set(e,t)}clear(){this.cache.clear()}size(){return this.cache.size}},ce=class{constructor(e,t,n){this.capacity=e;this.refillRate=t;this.refillInterval=n;this.tokens=e,this.lastRefill=Date.now()}capacity;refillRate;refillInterval;tokens;lastRefill;consume(e=1){return this.refill(),this.tokens>=e?(this.tokens-=e,!0):!1}refill(){let e=Date.now(),t=e-this.lastRefill,n=Math.floor(t/this.refillInterval*this.refillRate);n>0&&(this.tokens=Math.min(this.capacity,this.tokens+n),this.lastRefill=e)}getTokens(){return this.refill(),this.tokens}};function de(i){let e=i.tokensPerInterval??10,t=i.interval??6e4,n=i.maxBuckets??1e3,r=i.onExceeded??"skip",s=new ae(n);return async(o,a,d)=>{let c=i.getKey(o),p=s.get(c);if(p||(p=new ce(e,e,t),s.set(c,p)),!p.consume()){if(i.onRateLimited?.(c,o),a.logger?.warn(`Rate limit exceeded for key: ${c}`,{key:c}),r==="reject")throw new Error("Rate limit exceeded. Please try again later.");return a.skip()}return await d()}}function pe(i={}){return async(e,t,n)=>{let r;if(i.resolveParticipant)r=await i.resolveParticipant(e);else if(typeof t.channel.resolveParticipant=="function")try{r=await t.channel.resolveParticipant(e)}catch(o){t.logger?.warn("Channel resolveParticipant threw; falling back",{error:o instanceof Error?o.message:"Unknown error"})}let s=r??e.participant;if(s){let o={...e,participant:s,context:{...e.context,_participant:s}};return i.onResolved?.(o,s),t.logger?.debug("Resolved participant",{participantId:s.id,participantKind:s.kind}),await n(o)}return await n()}}function Ve(i,e){let t=e.toLowerCase();if(!i.toLowerCase().includes(t))return!1;let r=[],s=/```[\s\S]*?```/g,o;for(;(o=s.exec(i))!==null;)r.push([o.index,o.index+o[0].length]);let a=/`[^`\n]*`/g;for(;(o=a.exec(i))!==null;){let l=o.index,g=l+o[0].length;r.some(([f,_])=>l>=f&&g<=_)||r.push([l,g])}if(r.length===0)return!1;r.sort((l,g)=>l[0]-g[0]);let d="",c=0;for(let[l,g]of r)l>c&&(d+=i.slice(c,l)),c=Math.max(c,g);return c<i.length&&(d+=i.slice(c)),d.toLowerCase().includes(t)?!1:r.some(([l,g])=>i.slice(l,g).toLowerCase().includes(t))}function le(i){return async(e,t,n)=>{let r=i.getMessageText(e)??"";if(i.isDirectMessage?.(e)){let g={...e,context:{...e.context,_addressCheck:"direct",_isDM:!0}};return i.onClassified?.("direct",e),await n(g)}let s="ambiguous",o=r.toLowerCase(),a=i.agentName.toLowerCase(),d=g=>g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=d(a),p=i.agentId?`|^@${d(i.agentId)}\\b`:"";if(new RegExp(`^(hey\\s+)?@?${c}\\b${p}`,"i").test(o))s="direct";else if(new RegExp(`\\b(my|our|the)\\s+${c}\\b`,"i").test(o))s="ambiguous";else if(Ve(r,i.agentName))s="ignore";else if(/^https?:\/\//.test(r))s="ignore";else if(i.getMentions){let g=i.getMentions(e),I=g.some(f=>f.toLowerCase()===a||f===i.agentId);I&&g.length>1?s="indirect":I&&(s="ambiguous")}else o.includes(a)?s="ambiguous":s="passive";let l={...e,context:{...e.context,_addressCheck:s}};return i.onClassified?.(s,e),t.logger?.debug(`Address check classified as: ${s}`,{result:s}),await n(l)}}function ge(i){let e=i.classifierAgentName??"intent-classifier";return async(t,n,r)=>{let s=t.context?._addressCheck;if(s==="direct")return await r();if(s==="ignore"||s==="passive")return i.onClassified?.(s,t),n.skip();let o=i.getMessageText(t)??"";if(!o.trim())return await r();let a={message:o,agentName:i.agentName,agentId:i.agentId,senderName:i.getSenderName(t),channelName:i.getChannelName(t),isDirectMessage:i.isDirectMessage?.(t)??!1,recentContext:i.getRecentContext?.(t)};try{let c=(await n.delegateAndWait(e,{message:"classify",data:a,conversationId:t.conversationId})).output.trim();i.onClassified?.(c,t),n.logger?.debug(`Intent classified as: ${c}`,{classification:c});let p={...t,context:{...t.context,_intentClassification:c}};return c==="direct"?await r(p):n.skip()}catch(d){return n.logger?.error("Intent classification failed, allowing message",{error:d instanceof Error?d.message:"Unknown error"}),await r()}}}var T=class extends Error{constructor(t,n){super(`Maximum invocation depth exceeded: ${t} > ${n}`);this.currentDepth=t;this.maxDepth=n;this.name="DepthExceededError"}currentDepth;maxDepth};function ue(i={}){let e=i.maxDepth??5;return async(t,n,r)=>{if(n.invocationDepth>e)throw i.onDepthExceeded?.(n.invocationDepth,e,t),n.logger?.error(`Depth guard: invocation depth ${n.invocationDepth} exceeds maximum ${e}`,{currentDepth:n.invocationDepth,maxDepth:e}),new T(n.invocationDepth,e);return await r()}}function me(i={}){let e=i.level??"debug",t=i.includeInputData??!1,n=i.includeResultOutput??!1;return async(r,s,o)=>{if(i.shouldTrace&&!i.shouldTrace(r))return await o();let a=e==="info"?s.logger?.info:s.logger?.debug;a?.("Interceptor entry",{agent:s.agent.name,channel:s.channel.name,depth:s.invocationDepth,conversationId:r.conversationId,intent:r.intent,input:t?r:void 0});let d=performance.now();try{let c=await o(),p=performance.now()-d;return b(c)?a?.("Interceptor exit: skipped",{agent:s.agent.name,channel:s.channel.name,depth:s.invocationDepth,conversationId:r.conversationId,durationMs:p.toFixed(2)}):a?.("Interceptor exit: success",{agent:s.agent.name,channel:s.channel.name,depth:s.invocationDepth,conversationId:r.conversationId,durationMs:p.toFixed(2),outputLength:c.output.length,result:n?c:void 0}),c}catch(c){let p=performance.now()-d;throw s.logger?.error("Interceptor exit: error",{agent:s.agent.name,channel:s.channel.name,depth:s.invocationDepth,conversationId:r.conversationId,durationMs:p.toFixed(2),error:c instanceof Error?c.message:"Unknown error",errorType:c?.constructor?.name}),c}}}export{y as AgentError,B as AgentJsonRpcServer,J as AgentRegistry,w as BaseAgent,v as BaseChannel,Y as BrowserAgent,K as CodingAgent,G as DataAgent,T as DepthExceededError,ee as DiscordChannel,te as EmailChannel,Ae as InMemoryConversationStore,L as IntentClassifierAgent,M as InvocationDepthExceededError,z as JsonRpcTransport,R as LocalTransport,q as ResearchAgent,S as SKIP_SENTINEL,ne as SMSChannel,Q as ScheduledChannel,V as SlackChannel,U as SummarizerAgent,X as TelegramChannel,Z as WebhookChannel,F as assemblePrompt,D as composeChain,le as createAddressCheckInterceptor,O as createCaptureInterceptor,xe as createConversationSearchTool,ue as createDepthGuardInterceptor,se as createEventDedupInterceptor,ge as createIntentClassifierInterceptor,oe as createNoiseFilterInterceptor,pe as createParticipantResolverInterceptor,de as createRateLimitInterceptor,ie as createSelfFilterInterceptor,me as createTracerInterceptor,j as executeChain,b as isSkipSentinel,$ as skip};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { B as BaseAgentOptions, A as AgentInput, a as AgentResult } from './types-BWoRx1ZE.cjs';
|
|
2
|
+
import { B as BaseAgent } from './base-agent-CjrUlo6Y.cjs';
|
|
3
|
+
import { ModeConfig } from 'toolpack-sdk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Input payload for intent classification.
|
|
7
|
+
*/
|
|
8
|
+
interface IntentClassifierInput {
|
|
9
|
+
/** The message content to classify */
|
|
10
|
+
message: string;
|
|
11
|
+
/** The agent's display name (e.g., "Assistant") */
|
|
12
|
+
agentName: string;
|
|
13
|
+
/** The agent's unique identifier */
|
|
14
|
+
agentId: string;
|
|
15
|
+
/** The sender's display name */
|
|
16
|
+
senderName: string;
|
|
17
|
+
/** The conversation channel name */
|
|
18
|
+
channelName: string;
|
|
19
|
+
/** Whether this is a direct message (IM) context */
|
|
20
|
+
isDirectMessage?: boolean;
|
|
21
|
+
/** Previous message context (last 3 messages for continuity) */
|
|
22
|
+
recentContext?: Array<{
|
|
23
|
+
sender: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Whether to include classification examples in the prompt (helps tiny models) */
|
|
27
|
+
includeExamples?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Classification result indicating how the message relates to the target agent.
|
|
31
|
+
*/
|
|
32
|
+
type IntentClassification = 'direct' | 'indirect' | 'passive' | 'ignore';
|
|
33
|
+
declare class IntentClassifierAgent extends BaseAgent {
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
mode: ModeConfig;
|
|
37
|
+
constructor(options: BaseAgentOptions);
|
|
38
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Normalize the LLM output to a valid classification.
|
|
41
|
+
*/
|
|
42
|
+
private normalizeClassification;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { type IntentClassification as I, IntentClassifierAgent as a, type IntentClassifierInput as b };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { B as BaseAgentOptions, A as AgentInput, a as AgentResult } from './types-BWoRx1ZE.js';
|
|
2
|
+
import { B as BaseAgent } from './base-agent-Cx2kWzLF.js';
|
|
3
|
+
import { ModeConfig } from 'toolpack-sdk';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Input payload for intent classification.
|
|
7
|
+
*/
|
|
8
|
+
interface IntentClassifierInput {
|
|
9
|
+
/** The message content to classify */
|
|
10
|
+
message: string;
|
|
11
|
+
/** The agent's display name (e.g., "Assistant") */
|
|
12
|
+
agentName: string;
|
|
13
|
+
/** The agent's unique identifier */
|
|
14
|
+
agentId: string;
|
|
15
|
+
/** The sender's display name */
|
|
16
|
+
senderName: string;
|
|
17
|
+
/** The conversation channel name */
|
|
18
|
+
channelName: string;
|
|
19
|
+
/** Whether this is a direct message (IM) context */
|
|
20
|
+
isDirectMessage?: boolean;
|
|
21
|
+
/** Previous message context (last 3 messages for continuity) */
|
|
22
|
+
recentContext?: Array<{
|
|
23
|
+
sender: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Whether to include classification examples in the prompt (helps tiny models) */
|
|
27
|
+
includeExamples?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Classification result indicating how the message relates to the target agent.
|
|
31
|
+
*/
|
|
32
|
+
type IntentClassification = 'direct' | 'indirect' | 'passive' | 'ignore';
|
|
33
|
+
declare class IntentClassifierAgent extends BaseAgent {
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
mode: ModeConfig;
|
|
37
|
+
constructor(options: BaseAgentOptions);
|
|
38
|
+
invokeAgent(input: AgentInput): Promise<AgentResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Normalize the LLM output to a valid classification.
|
|
41
|
+
*/
|
|
42
|
+
private normalizeClassification;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { type IntentClassification as I, IntentClassifierAgent as a, type IntentClassifierInput as b };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var R=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var n in t)R(e,n,{get:t[n],enumerable:!0})},H=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of O(t))!G.call(e,s)&&s!==n&&R(e,s,{get:()=>t[s],enumerable:!(i=B(t,s))||i.enumerable});return e};var W=e=>H(R({},"__esModule",{value:!0}),e);var Q={};U(Q,{CAPTURE_INTERCEPTOR_MARKER:()=>A,DepthExceededError:()=>C,InvocationDepthExceededError:()=>x,SKIP_SENTINEL:()=>h,composeChain:()=>_,createAddressCheckInterceptor:()=>M,createCaptureInterceptor:()=>F,createDepthGuardInterceptor:()=>L,createEventDedupInterceptor:()=>b,createIntentClassifierInterceptor:()=>j,createNoiseFilterInterceptor:()=>N,createParticipantResolverInterceptor:()=>P,createRateLimitInterceptor:()=>D,createSelfFilterInterceptor:()=>k,createTracerInterceptor:()=>$,executeChain:()=>K,isSkipSentinel:()=>y,skip:()=>v});module.exports=W(Q);var h=Symbol("interceptor-skip-sentinel");function y(e){return e===h}function v(){return h}var x=class extends Error{constructor(t,n){super(`Invocation depth ${t} exceeds maximum ${n}`),this.name="InvocationDepthExceededError"}};function _(e,t,n,i,s={}){let o=s.maxInvocationDepth??5;return{async execute(r){let g=(u=>({agent:t,channel:n,registry:i,invocationDepth:u,delegateAndWait:async(l,d)=>{let p=u+1;if(p>o)throw new x(p,o);if(!i)throw new Error(`Cannot delegate to "${l}": agent is running in standalone mode without a registry`);let m=i.getAgent(l);if(!m)throw new Error(`Agent "${l}" not found for delegation`);let f={message:d.message??"",intent:d.intent,data:d.data,context:d.context,conversationId:d.conversationId??r.conversationId??`delegation-${Date.now()}`};return await m.invokeAgent(f)},skip:v}))(0),a=async u=>{let l=u??r;return await t.invokeAgent(l)};for(let u=e.length-1;u>=0;u--){let l=e[u],d=a;a=async p=>await l(p??r,g,d)}return await a()}}}async function K(e,t){let n=await e.execute(t);return n===h?null:n}var w=class{constructor(t){this.maxSize=t}maxSize;cache=new Map;has(t){return this.cache.has(t)}set(t,n){if(this.cache.has(t)&&this.cache.delete(t),this.cache.size>=this.maxSize){let i=this.cache.keys().next().value;i!==void 0&&this.cache.delete(i)}this.cache.set(t,n)}clear(){this.cache.clear()}size(){return this.cache.size}};function b(e={}){let t=e.maxCacheSize??1e3,n=e.getEventId??(s=>s.context?.eventId),i=new w(t);return async(s,o,r)=>{let c=n(s);if(c){if(i.has(c))return e.onDuplicate?.(c,s),o.logger?.debug(`Event dedup: dropping duplicate event ${c}`,{eventId:c}),o.skip();i.set(c,!0)}return await r()}}function N(e){let t=e.getSubtype??(i=>i.context?.subtype),n=new Set(e.denySubtypes);return async(i,s,o)=>{let r=t(i);return r&&n.has(r)?(e.onFiltered?.(r,i),s.logger?.debug(`Noise filter: dropping message with subtype "${r}"`,{subtype:r}),s.skip()):await o()}}function k(e){return async(t,n,i)=>{let s=e.getSenderId(t),o=e.agentId??n.agent.name;return s&&s===o?(e.onSelfMessage?.(s,t),n.logger?.debug(`Self filter: dropping self-message from ${s}`,{senderId:s,agentId:o}),n.skip()):await i()}}var S=class{constructor(t){this.maxSize=t}maxSize;cache=new Map;get(t){let n=this.cache.get(t);return n!==void 0&&(this.cache.delete(t),this.cache.set(t,n)),n}set(t,n){if(this.cache.has(t))this.cache.delete(t);else if(this.cache.size>=this.maxSize){let i=this.cache.keys().next().value;i!==void 0&&this.cache.delete(i)}this.cache.set(t,n)}clear(){this.cache.clear()}size(){return this.cache.size}},E=class{constructor(t,n,i){this.capacity=t;this.refillRate=n;this.refillInterval=i;this.tokens=t,this.lastRefill=Date.now()}capacity;refillRate;refillInterval;tokens;lastRefill;consume(t=1){return this.refill(),this.tokens>=t?(this.tokens-=t,!0):!1}refill(){let t=Date.now(),n=t-this.lastRefill,i=Math.floor(n/this.refillInterval*this.refillRate);i>0&&(this.tokens=Math.min(this.capacity,this.tokens+i),this.lastRefill=t)}getTokens(){return this.refill(),this.tokens}};function D(e){let t=e.tokensPerInterval??10,n=e.interval??6e4,i=e.maxBuckets??1e3,s=e.onExceeded??"skip",o=new S(i);return async(r,c,g)=>{let a=e.getKey(r),u=o.get(a);if(u||(u=new E(t,t,n),o.set(a,u)),!u.consume()){if(e.onRateLimited?.(a,r),c.logger?.warn(`Rate limit exceeded for key: ${a}`,{key:a}),s==="reject")throw new Error("Rate limit exceeded. Please try again later.");return c.skip()}return await g()}}function P(e={}){return async(t,n,i)=>{let s;if(e.resolveParticipant)s=await e.resolveParticipant(t);else if(typeof n.channel.resolveParticipant=="function")try{s=await n.channel.resolveParticipant(t)}catch(r){n.logger?.warn("Channel resolveParticipant threw; falling back",{error:r instanceof Error?r.message:"Unknown error"})}let o=s??t.participant;if(o){let r={...t,participant:o,context:{...t.context,_participant:o}};return e.onResolved?.(r,o),n.logger?.debug("Resolved participant",{participantId:o.id,participantKind:o.kind}),await i(r)}return await i()}}var T=require("crypto");function q(e){let t=e.context??{},n=t.channelType;return n==="im"||n==="private"||n==="dm"?"dm":t.threadId!==void 0?"thread":"channel"}var A=Symbol.for("toolpack:capture-history");function F(e){let t=e.captureAgentReplies??!0,n=e.getScope??q,i=e.getMessageId??(r=>r.context?.messageId??r.context?.eventId??(0,T.randomUUID)()),s=e.getMentions??(r=>r.context?.mentions??[]),o=async(r,c,g)=>{let a=r.conversationId;if(!a)return c.logger?.warn("[capture-history] Message has no conversationId \u2014 skipping capture"),await g();let u=r.participant;if(u){let d={id:i(r),conversationId:a,participant:u,content:r.message??"",timestamp:new Date().toISOString(),scope:n(r),metadata:{channelType:r.context?.channelType,threadId:r.context?.threadId,messageId:r.context?.messageId,mentions:s(r),channelName:r.context?.channelName,channelId:r.context?.channelId}};try{await e.store.append(d),e.onCaptured?.(d),c.logger?.debug("[capture-history] Captured inbound message",{messageId:d.id,participantId:u.id,conversationId:a})}catch(p){c.logger?.warn("[capture-history] Failed to store inbound message",{error:p instanceof Error?p.message:String(p)})}}let l=await g();if(t&&!y(l)&&l.output!=null){let d={kind:"agent",id:c.agent.name,displayName:c.agent.name},p={id:(0,T.randomUUID)(),conversationId:a,participant:d,content:l.output,timestamp:new Date().toISOString(),scope:n(r),metadata:{channelType:r.context?.channelType,threadId:r.context?.threadId,channelName:r.context?.channelName,channelId:r.context?.channelId}};try{await e.store.append(p),e.onCaptured?.(p),c.logger?.debug("[capture-history] Captured agent reply",{messageId:p.id,agentId:c.agent.name,conversationId:a})}catch(m){c.logger?.warn("[capture-history] Failed to store agent reply",{error:m instanceof Error?m.message:String(m)})}}return l};return o[A]=!0,o}function J(e,t){let n=t.toLowerCase();if(!e.toLowerCase().includes(n))return!1;let s=[],o=/```[\s\S]*?```/g,r;for(;(r=o.exec(e))!==null;)s.push([r.index,r.index+r[0].length]);let c=/`[^`\n]*`/g;for(;(r=c.exec(e))!==null;){let d=r.index,p=d+r[0].length;s.some(([f,z])=>d>=f&&p<=z)||s.push([d,p])}if(s.length===0)return!1;s.sort((d,p)=>d[0]-p[0]);let g="",a=0;for(let[d,p]of s)d>a&&(g+=e.slice(a,d)),a=Math.max(a,p);return a<e.length&&(g+=e.slice(a)),g.toLowerCase().includes(n)?!1:s.some(([d,p])=>e.slice(d,p).toLowerCase().includes(n))}function M(e){return async(t,n,i)=>{let s=e.getMessageText(t)??"";if(e.isDirectMessage?.(t)){let p={...t,context:{...t.context,_addressCheck:"direct",_isDM:!0}};return e.onClassified?.("direct",t),await i(p)}let o="ambiguous",r=s.toLowerCase(),c=e.agentName.toLowerCase(),g=p=>p.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=g(c),u=e.agentId?`|^@${g(e.agentId)}\\b`:"";if(new RegExp(`^(hey\\s+)?@?${a}\\b${u}`,"i").test(r))o="direct";else if(new RegExp(`\\b(my|our|the)\\s+${a}\\b`,"i").test(r))o="ambiguous";else if(J(s,e.agentName))o="ignore";else if(/^https?:\/\//.test(s))o="ignore";else if(e.getMentions){let p=e.getMentions(t),m=p.some(f=>f.toLowerCase()===c||f===e.agentId);m&&p.length>1?o="indirect":m&&(o="ambiguous")}else r.includes(c)?o="ambiguous":o="passive";let d={...t,context:{...t.context,_addressCheck:o}};return e.onClassified?.(o,t),n.logger?.debug(`Address check classified as: ${o}`,{result:o}),await i(d)}}function j(e){let t=e.classifierAgentName??"intent-classifier";return async(n,i,s)=>{let o=n.context?._addressCheck;if(o==="direct")return await s();if(o==="ignore"||o==="passive")return e.onClassified?.(o,n),i.skip();let r=e.getMessageText(n)??"";if(!r.trim())return await s();let c={message:r,agentName:e.agentName,agentId:e.agentId,senderName:e.getSenderName(n),channelName:e.getChannelName(n),isDirectMessage:e.isDirectMessage?.(n)??!1,recentContext:e.getRecentContext?.(n)};try{let a=(await i.delegateAndWait(t,{message:"classify",data:c,conversationId:n.conversationId})).output.trim();e.onClassified?.(a,n),i.logger?.debug(`Intent classified as: ${a}`,{classification:a});let u={...n,context:{...n.context,_intentClassification:a}};return a==="direct"?await s(u):i.skip()}catch(g){return i.logger?.error("Intent classification failed, allowing message",{error:g instanceof Error?g.message:"Unknown error"}),await s()}}}var C=class extends Error{constructor(n,i){super(`Maximum invocation depth exceeded: ${n} > ${i}`);this.currentDepth=n;this.maxDepth=i;this.name="DepthExceededError"}currentDepth;maxDepth};function L(e={}){let t=e.maxDepth??5;return async(n,i,s)=>{if(i.invocationDepth>t)throw e.onDepthExceeded?.(i.invocationDepth,t,n),i.logger?.error(`Depth guard: invocation depth ${i.invocationDepth} exceeds maximum ${t}`,{currentDepth:i.invocationDepth,maxDepth:t}),new C(i.invocationDepth,t);return await s()}}function $(e={}){let t=e.level??"debug",n=e.includeInputData??!1,i=e.includeResultOutput??!1;return async(s,o,r)=>{if(e.shouldTrace&&!e.shouldTrace(s))return await r();let c=t==="info"?o.logger?.info:o.logger?.debug;c?.("Interceptor entry",{agent:o.agent.name,channel:o.channel.name,depth:o.invocationDepth,conversationId:s.conversationId,intent:s.intent,input:n?s:void 0});let g=performance.now();try{let a=await r(),u=performance.now()-g;return y(a)?c?.("Interceptor exit: skipped",{agent:o.agent.name,channel:o.channel.name,depth:o.invocationDepth,conversationId:s.conversationId,durationMs:u.toFixed(2)}):c?.("Interceptor exit: success",{agent:o.agent.name,channel:o.channel.name,depth:o.invocationDepth,conversationId:s.conversationId,durationMs:u.toFixed(2),outputLength:a.output.length,result:i?a:void 0}),a}catch(a){let u=performance.now()-g;throw o.logger?.error("Interceptor exit: error",{agent:o.agent.name,channel:o.channel.name,depth:o.invocationDepth,conversationId:s.conversationId,durationMs:u.toFixed(2),error:a instanceof Error?a.message:"Unknown error",errorType:a?.constructor?.name}),a}}}0&&(module.exports={CAPTURE_INTERCEPTOR_MARKER,DepthExceededError,InvocationDepthExceededError,SKIP_SENTINEL,composeChain,createAddressCheckInterceptor,createCaptureInterceptor,createDepthGuardInterceptor,createEventDedupInterceptor,createIntentClassifierInterceptor,createNoiseFilterInterceptor,createParticipantResolverInterceptor,createRateLimitInterceptor,createSelfFilterInterceptor,createTracerInterceptor,executeChain,isSkipSentinel,skip});
|