opc-agent 2.0.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +603 -545
  2. package/dist/channels/voice.d.ts +59 -0
  3. package/dist/channels/voice.js +351 -1
  4. package/dist/cli.js +284 -5
  5. package/dist/core/agent.d.ts +9 -0
  6. package/dist/core/agent.js +49 -0
  7. package/dist/core/collaboration.d.ts +89 -0
  8. package/dist/core/collaboration.js +201 -0
  9. package/dist/deploy/index.d.ts +40 -0
  10. package/dist/deploy/index.js +261 -0
  11. package/dist/index.d.ts +7 -1
  12. package/dist/index.js +47 -3
  13. package/dist/mcp/servers/calculator-mcp.d.ts +3 -0
  14. package/dist/mcp/servers/calculator-mcp.js +65 -0
  15. package/dist/mcp/servers/crypto-mcp.d.ts +3 -0
  16. package/dist/mcp/servers/crypto-mcp.js +108 -0
  17. package/dist/mcp/servers/database-mcp.d.ts +3 -0
  18. package/dist/mcp/servers/database-mcp.js +73 -0
  19. package/dist/mcp/servers/datetime-mcp.d.ts +3 -0
  20. package/dist/mcp/servers/datetime-mcp.js +71 -0
  21. package/dist/mcp/servers/filesystem.d.ts +3 -0
  22. package/dist/mcp/servers/filesystem.js +101 -0
  23. package/dist/mcp/servers/github-mcp.d.ts +3 -0
  24. package/dist/mcp/servers/github-mcp.js +60 -0
  25. package/dist/mcp/servers/index.d.ts +21 -0
  26. package/dist/mcp/servers/index.js +50 -0
  27. package/dist/mcp/servers/json-mcp.d.ts +3 -0
  28. package/dist/mcp/servers/json-mcp.js +126 -0
  29. package/dist/mcp/servers/memory-mcp.d.ts +3 -0
  30. package/dist/mcp/servers/memory-mcp.js +60 -0
  31. package/dist/mcp/servers/regex-mcp.d.ts +3 -0
  32. package/dist/mcp/servers/regex-mcp.js +56 -0
  33. package/dist/mcp/servers/web-mcp.d.ts +3 -0
  34. package/dist/mcp/servers/web-mcp.js +51 -0
  35. package/dist/memory/index.d.ts +2 -0
  36. package/dist/memory/index.js +4 -1
  37. package/dist/memory/seed-loader.d.ts +51 -0
  38. package/dist/memory/seed-loader.js +200 -0
  39. package/dist/schema/oad.d.ts +292 -12
  40. package/dist/schema/oad.js +12 -1
  41. package/dist/security/guardrails.d.ts +50 -0
  42. package/dist/security/guardrails.js +197 -0
  43. package/dist/studio/server.d.ts +31 -1
  44. package/dist/studio/server.js +154 -3
  45. package/dist/studio-ui/index.html +1278 -662
  46. package/dist/tools/integrations/calendar.d.ts +3 -0
  47. package/dist/tools/integrations/calendar.js +73 -0
  48. package/dist/tools/integrations/code-exec.d.ts +3 -0
  49. package/dist/tools/integrations/code-exec.js +42 -0
  50. package/dist/tools/integrations/csv-analyzer.d.ts +3 -0
  51. package/dist/tools/integrations/csv-analyzer.js +142 -0
  52. package/dist/tools/integrations/database.d.ts +3 -0
  53. package/dist/tools/integrations/database.js +44 -0
  54. package/dist/tools/integrations/email-send.d.ts +3 -0
  55. package/dist/tools/integrations/email-send.js +104 -0
  56. package/dist/tools/integrations/git-tool.d.ts +3 -0
  57. package/dist/tools/integrations/git-tool.js +49 -0
  58. package/dist/tools/integrations/github-tool.d.ts +3 -0
  59. package/dist/tools/integrations/github-tool.js +77 -0
  60. package/dist/tools/integrations/image-gen.d.ts +3 -0
  61. package/dist/tools/integrations/image-gen.js +58 -0
  62. package/dist/tools/integrations/index.d.ts +30 -0
  63. package/dist/tools/integrations/index.js +107 -0
  64. package/dist/tools/integrations/jira.d.ts +3 -0
  65. package/dist/tools/integrations/jira.js +85 -0
  66. package/dist/tools/integrations/notion.d.ts +3 -0
  67. package/dist/tools/integrations/notion.js +71 -0
  68. package/dist/tools/integrations/npm-tool.d.ts +3 -0
  69. package/dist/tools/integrations/npm-tool.js +49 -0
  70. package/dist/tools/integrations/pdf-reader.d.ts +3 -0
  71. package/dist/tools/integrations/pdf-reader.js +91 -0
  72. package/dist/tools/integrations/slack.d.ts +3 -0
  73. package/dist/tools/integrations/slack.js +67 -0
  74. package/dist/tools/integrations/summarizer.d.ts +3 -0
  75. package/dist/tools/integrations/summarizer.js +49 -0
  76. package/dist/tools/integrations/translator.d.ts +3 -0
  77. package/dist/tools/integrations/translator.js +48 -0
  78. package/dist/tools/integrations/trello.d.ts +3 -0
  79. package/dist/tools/integrations/trello.js +60 -0
  80. package/dist/tools/integrations/vector-search.d.ts +3 -0
  81. package/dist/tools/integrations/vector-search.js +44 -0
  82. package/dist/tools/integrations/web-scraper.d.ts +3 -0
  83. package/dist/tools/integrations/web-scraper.js +48 -0
  84. package/dist/tools/integrations/web-search.d.ts +3 -0
  85. package/dist/tools/integrations/web-search.js +60 -0
  86. package/dist/tools/integrations/webhook.d.ts +3 -0
  87. package/dist/tools/integrations/webhook.js +39 -0
  88. package/dist/ui/components.d.ts +10 -0
  89. package/dist/ui/components.js +123 -0
  90. package/package.json +1 -1
  91. package/src/channels/voice.ts +365 -0
  92. package/src/cli.ts +294 -6
  93. package/src/core/agent.ts +56 -0
  94. package/src/core/collaboration.ts +275 -0
  95. package/src/deploy/index.ts +255 -0
  96. package/src/index.ts +21 -1
  97. package/src/mcp/servers/calculator-mcp.ts +65 -0
  98. package/src/mcp/servers/crypto-mcp.ts +73 -0
  99. package/src/mcp/servers/database-mcp.ts +72 -0
  100. package/src/mcp/servers/datetime-mcp.ts +69 -0
  101. package/src/mcp/servers/filesystem.ts +66 -0
  102. package/src/mcp/servers/github-mcp.ts +58 -0
  103. package/src/mcp/servers/index.ts +63 -0
  104. package/src/mcp/servers/json-mcp.ts +102 -0
  105. package/src/mcp/servers/memory-mcp.ts +56 -0
  106. package/src/mcp/servers/regex-mcp.ts +53 -0
  107. package/src/mcp/servers/web-mcp.ts +49 -0
  108. package/src/memory/index.ts +3 -0
  109. package/src/memory/seed-loader.ts +212 -0
  110. package/src/schema/oad.ts +13 -0
  111. package/src/security/guardrails.ts +248 -0
  112. package/src/studio/server.ts +166 -4
  113. package/src/studio-ui/index.html +1278 -662
  114. package/src/tools/integrations/calendar.ts +73 -0
  115. package/src/tools/integrations/code-exec.ts +39 -0
  116. package/src/tools/integrations/csv-analyzer.ts +92 -0
  117. package/src/tools/integrations/database.ts +44 -0
  118. package/src/tools/integrations/email-send.ts +76 -0
  119. package/src/tools/integrations/git-tool.ts +42 -0
  120. package/src/tools/integrations/github-tool.ts +76 -0
  121. package/src/tools/integrations/image-gen.ts +56 -0
  122. package/src/tools/integrations/index.ts +92 -0
  123. package/src/tools/integrations/jira.ts +83 -0
  124. package/src/tools/integrations/notion.ts +71 -0
  125. package/src/tools/integrations/npm-tool.ts +48 -0
  126. package/src/tools/integrations/pdf-reader.ts +58 -0
  127. package/src/tools/integrations/slack.ts +65 -0
  128. package/src/tools/integrations/summarizer.ts +49 -0
  129. package/src/tools/integrations/translator.ts +48 -0
  130. package/src/tools/integrations/trello.ts +60 -0
  131. package/src/tools/integrations/vector-search.ts +42 -0
  132. package/src/tools/integrations/web-scraper.ts +47 -0
  133. package/src/tools/integrations/web-search.ts +58 -0
  134. package/src/tools/integrations/webhook.ts +38 -0
  135. package/src/ui/components.ts +127 -0
  136. package/tests/brain-seed-extended.test.ts +490 -0
  137. package/tests/brain-seed.test.ts +239 -0
  138. package/tests/collaboration.test.ts +319 -0
  139. package/tests/deploy-and-dag.test.ts +196 -0
  140. package/tests/guardrails.test.ts +177 -0
  141. package/tests/integrations.test.ts +249 -0
  142. package/tests/mcp-servers.test.ts +260 -0
  143. package/tests/voice-enhanced.test.ts +169 -0
  144. package/dist/dtv/data.d.ts +0 -18
  145. package/dist/dtv/data.js +0 -25
  146. package/dist/dtv/trust.d.ts +0 -19
  147. package/dist/dtv/trust.js +0 -40
  148. package/dist/dtv/value.d.ts +0 -23
  149. package/dist/dtv/value.js +0 -38
  150. package/dist/marketplace/index.d.ts +0 -34
  151. package/dist/marketplace/index.js +0 -202
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Multi-agent collaboration patterns
3
+ * @module core/collaboration
4
+ */
5
+
6
+ import type { BaseAgent } from './agent';
7
+ import type { Message } from './types';
8
+
9
+ // ─── Result Types ───────────────────────────────────────────
10
+
11
+ export interface DebateArgument {
12
+ agent: string;
13
+ round: number;
14
+ argument: string;
15
+ }
16
+
17
+ export interface DebateResult {
18
+ topic: string;
19
+ rounds: DebateArgument[];
20
+ summary: string;
21
+ judge?: string;
22
+ }
23
+
24
+ export interface VoteEntry {
25
+ agent: string;
26
+ choice: string;
27
+ confidence: number;
28
+ }
29
+
30
+ export interface VoteResult {
31
+ question: string;
32
+ votes: VoteEntry[];
33
+ winner: string;
34
+ tally: Record<string, number>;
35
+ }
36
+
37
+ export interface PipelineStageResult {
38
+ agent: string;
39
+ input: string;
40
+ output: string;
41
+ durationMs: number;
42
+ }
43
+
44
+ export interface PipelineResult {
45
+ stages: PipelineStageResult[];
46
+ finalOutput: string;
47
+ totalDurationMs: number;
48
+ }
49
+
50
+ export interface WorkerResult {
51
+ agent: string;
52
+ subtask: string;
53
+ result: string;
54
+ }
55
+
56
+ export interface HierarchyResult {
57
+ task: string;
58
+ subtasks: WorkerResult[];
59
+ synthesis: string;
60
+ }
61
+
62
+ // ─── Helper ─────────────────────────────────────────────────
63
+
64
+ function makeMsg(role: 'user' | 'assistant' | 'system', content: string): Message {
65
+ return { id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, role, content, timestamp: Date.now() };
66
+ }
67
+
68
+ async function agentChat(agent: BaseAgent, prompt: string): Promise<string> {
69
+ const response = await agent.handleMessage(makeMsg('user', prompt));
70
+ return response.content;
71
+ }
72
+
73
+ // ─── DebatePattern ──────────────────────────────────────────
74
+
75
+ export class DebatePattern {
76
+ constructor(private agents: BaseAgent[], private rounds: number = 3) {}
77
+
78
+ async debate(topic: string, judgeAgent?: BaseAgent): Promise<DebateResult> {
79
+ const allArgs: DebateArgument[] = [];
80
+ let context = '';
81
+
82
+ for (let round = 1; round <= this.rounds; round++) {
83
+ for (const agent of this.agents) {
84
+ const prompt = round === 1
85
+ ? `Debate topic: "${topic}". Present your argument.`
86
+ : `Debate topic: "${topic}". Previous arguments:\n${context}\nPresent your counter-argument for round ${round}.`;
87
+ const argument = await agentChat(agent, prompt);
88
+ allArgs.push({ agent: agent.name, round, argument });
89
+ context += `\n[${agent.name} round ${round}]: ${argument}`;
90
+ }
91
+ }
92
+
93
+ const judge = judgeAgent ?? this.agents[0];
94
+ const summaryPrompt = `You are the judge. Summarize and decide the winner of this debate on "${topic}":\n${context}`;
95
+ const summary = await agentChat(judge, summaryPrompt);
96
+
97
+ return { topic, rounds: allArgs, summary, judge: judge.name };
98
+ }
99
+ }
100
+
101
+ // ─── VotingPattern ──────────────────────────────────────────
102
+
103
+ export class VotingPattern {
104
+ constructor(private agents: BaseAgent[]) {}
105
+
106
+ async vote(question: string, options: string[]): Promise<VoteResult> {
107
+ const votes: VoteEntry[] = [];
108
+ const optionList = options.map((o, i) => `${i + 1}. ${o}`).join('\n');
109
+
110
+ for (const agent of this.agents) {
111
+ const prompt = `Question: "${question}"\nOptions:\n${optionList}\nRespond with ONLY the exact text of your chosen option.`;
112
+ const raw = await agentChat(agent, prompt);
113
+ const choice = options.find(o => raw.includes(o)) ?? raw.trim();
114
+ votes.push({ agent: agent.name, choice, confidence: 1 });
115
+ }
116
+
117
+ return this.tallyVotes(question, votes);
118
+ }
119
+
120
+ async weightedVote(question: string, options: string[]): Promise<VoteResult> {
121
+ const votes: VoteEntry[] = [];
122
+ const optionList = options.map((o, i) => `${i + 1}. ${o}`).join('\n');
123
+
124
+ for (const agent of this.agents) {
125
+ const prompt = `Question: "${question}"\nOptions:\n${optionList}\nRespond in format: CHOICE|CONFIDENCE(0-1)`;
126
+ const raw = await agentChat(agent, prompt);
127
+ const parts = raw.split('|');
128
+ const choiceRaw = parts[0]?.trim() ?? '';
129
+ const choice = options.find(o => choiceRaw.includes(o)) ?? choiceRaw;
130
+ const confidence = Math.min(1, Math.max(0, parseFloat(parts[1] ?? '0.5') || 0.5));
131
+ votes.push({ agent: agent.name, choice, confidence });
132
+ }
133
+
134
+ return this.tallyVotes(question, votes);
135
+ }
136
+
137
+ private tallyVotes(question: string, votes: VoteEntry[]): VoteResult {
138
+ const tally: Record<string, number> = {};
139
+ for (const v of votes) {
140
+ tally[v.choice] = (tally[v.choice] ?? 0) + v.confidence;
141
+ }
142
+ const winner = Object.entries(tally).sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';
143
+ return { question, votes, winner, tally };
144
+ }
145
+ }
146
+
147
+ // ─── PipelinePattern ────────────────────────────────────────
148
+
149
+ export class PipelinePattern {
150
+ constructor(private stages: { agent: BaseAgent; transform?: (input: string) => string }[]) {}
151
+
152
+ async process(input: string): Promise<PipelineResult> {
153
+ const stageResults: PipelineStageResult[] = [];
154
+ let current = input;
155
+ const t0 = Date.now();
156
+
157
+ for (const stage of this.stages) {
158
+ const stageInput = stage.transform ? stage.transform(current) : current;
159
+ const start = Date.now();
160
+ const output = await agentChat(stage.agent, stageInput);
161
+ stageResults.push({ agent: stage.agent.name, input: stageInput, output, durationMs: Date.now() - start });
162
+ current = output;
163
+ }
164
+
165
+ return { stages: stageResults, finalOutput: current, totalDurationMs: Date.now() - t0 };
166
+ }
167
+ }
168
+
169
+ // ─── HierarchyPattern ───────────────────────────────────────
170
+
171
+ export class HierarchyPattern {
172
+ constructor(private leader: BaseAgent, private workers: BaseAgent[]) {}
173
+
174
+ async execute(task: string): Promise<HierarchyResult> {
175
+ // Leader decomposes
176
+ const decomposePrompt = `Decompose this task into ${this.workers.length} subtasks (one per line, no numbering): "${task}"`;
177
+ const decomposition = await agentChat(this.leader, decomposePrompt);
178
+ const subtasks = decomposition.split('\n').map(s => s.trim()).filter(Boolean);
179
+
180
+ // Workers execute in parallel
181
+ const workerResults: WorkerResult[] = await Promise.all(
182
+ this.workers.map(async (worker, i) => {
183
+ const subtask = subtasks[i] ?? subtasks[subtasks.length - 1] ?? task;
184
+ const result = await agentChat(worker, `Complete this subtask: "${subtask}"`);
185
+ return { agent: worker.name, subtask, result };
186
+ })
187
+ );
188
+
189
+ // Leader synthesizes
190
+ const synthPrompt = `Original task: "${task}"\nSubtask results:\n${workerResults.map(r => `[${r.agent}] ${r.subtask}: ${r.result}`).join('\n')}\nSynthesize a final answer.`;
191
+ const synthesis = await agentChat(this.leader, synthPrompt);
192
+
193
+ return { task, subtasks: workerResults, synthesis };
194
+ }
195
+ }
196
+
197
+ // ─── SharedContext ───────────────────────────────────────────
198
+
199
+ export class SharedContext {
200
+ private store: Map<string, any> = new Map();
201
+ private listeners: Map<string, ((value: any) => void)[]> = new Map();
202
+
203
+ set(key: string, value: any): void {
204
+ this.store.set(key, value);
205
+ const cbs = this.listeners.get(key);
206
+ if (cbs) cbs.forEach(cb => cb(value));
207
+ }
208
+
209
+ get<T>(key: string): T | undefined {
210
+ return this.store.get(key) as T | undefined;
211
+ }
212
+
213
+ getAll(): Record<string, any> {
214
+ const result: Record<string, any> = {};
215
+ for (const [k, v] of this.store) result[k] = v;
216
+ return result;
217
+ }
218
+
219
+ onChange(key: string, callback: (value: any) => void): void {
220
+ const existing = this.listeners.get(key) ?? [];
221
+ existing.push(callback);
222
+ this.listeners.set(key, existing);
223
+ }
224
+ }
225
+
226
+ // ─── ConversationProtocol ───────────────────────────────────
227
+
228
+ export class ConversationProtocol {
229
+ async roundRobin(agents: BaseAgent[], topic: string, rounds: number): Promise<Message[]> {
230
+ const messages: Message[] = [];
231
+ let context = `Topic: "${topic}"`;
232
+
233
+ for (let round = 0; round < rounds; round++) {
234
+ for (const agent of agents) {
235
+ const prompt = `${context}\n\nIt's your turn to contribute to this discussion. Be concise.`;
236
+ const content = await agentChat(agent, prompt);
237
+ const msg = makeMsg('assistant', content);
238
+ (msg as any).agent = agent.name;
239
+ messages.push(msg);
240
+ context += `\n[${agent.name}]: ${content}`;
241
+ }
242
+ }
243
+
244
+ return messages;
245
+ }
246
+
247
+ async moderated(agents: BaseAgent[], moderator: BaseAgent, topic: string): Promise<Message[]> {
248
+ const messages: Message[] = [];
249
+ let context = `Topic: "${topic}"`;
250
+
251
+ // Moderator opens
252
+ const opening = await agentChat(moderator, `You are moderating a discussion on "${topic}". Introduce the topic and ask the first question.`);
253
+ const openMsg = makeMsg('assistant', opening);
254
+ (openMsg as any).agent = moderator.name;
255
+ messages.push(openMsg);
256
+ context += `\n[Moderator ${moderator.name}]: ${opening}`;
257
+
258
+ // Each agent responds
259
+ for (const agent of agents) {
260
+ const content = await agentChat(agent, `${context}\n\nRespond to the moderator's question.`);
261
+ const msg = makeMsg('assistant', content);
262
+ (msg as any).agent = agent.name;
263
+ messages.push(msg);
264
+ context += `\n[${agent.name}]: ${content}`;
265
+ }
266
+
267
+ // Moderator summarizes
268
+ const summary = await agentChat(moderator, `${context}\n\nSummarize the discussion and provide closing remarks.`);
269
+ const closeMsg = makeMsg('assistant', summary);
270
+ (closeMsg as any).agent = moderator.name;
271
+ messages.push(closeMsg);
272
+
273
+ return messages;
274
+ }
275
+ }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * AgentDeployer - Deploy agents to Docker, Railway, Fly.io
3
+ */
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ import { execSync } from 'child_process';
7
+
8
+ export interface DeployOptions {
9
+ port?: number;
10
+ env?: Record<string, string>;
11
+ platform?: 'docker' | 'railway' | 'fly' | 'render';
12
+ replicas?: number;
13
+ }
14
+
15
+ export interface DeployResult {
16
+ platform: string;
17
+ success: boolean;
18
+ url?: string;
19
+ message: string;
20
+ files?: string[];
21
+ }
22
+
23
+ export class AgentDeployer {
24
+ /**
25
+ * Generate Dockerfile for the agent
26
+ */
27
+ async generateDockerfile(agentDir: string, options?: DeployOptions): Promise<string> {
28
+ const port = options?.port || 3000;
29
+ const pkgPath = path.join(agentDir, 'package.json');
30
+ let startCmd = 'node src/index.js';
31
+
32
+ if (fs.existsSync(pkgPath)) {
33
+ try {
34
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
35
+ if (pkg.scripts?.start) {
36
+ startCmd = pkg.scripts.start;
37
+ }
38
+ if (pkg.main) {
39
+ startCmd = `node ${pkg.main}`;
40
+ }
41
+ } catch {}
42
+ }
43
+
44
+ return `FROM node:22-slim
45
+ WORKDIR /app
46
+
47
+ # Install dependencies
48
+ COPY package*.json ./
49
+ RUN npm ci --production
50
+
51
+ # Copy source
52
+ COPY . .
53
+
54
+ # Build if needed
55
+ RUN if [ -f "tsconfig.json" ]; then npx tsc || true; fi
56
+
57
+ EXPOSE ${port}
58
+
59
+ ENV NODE_ENV=production
60
+ ENV PORT=${port}
61
+
62
+ CMD ["${startCmd.split(' ')[0]}", ${startCmd.split(' ').slice(1).map(s => `"${s}"`).join(', ')}]
63
+ `;
64
+ }
65
+
66
+ /**
67
+ * Generate docker-compose.yml
68
+ */
69
+ async generateCompose(agentDir: string, options?: DeployOptions): Promise<string> {
70
+ const port = options?.port || 3000;
71
+ const replicas = options?.replicas || 1;
72
+ const agentName = path.basename(agentDir).toLowerCase().replace(/[^a-z0-9-]/g, '-') || 'opc-agent';
73
+
74
+ const envLines = options?.env
75
+ ? Object.entries(options.env).map(([k, v]) => ` - ${k}=${v}`).join('\n')
76
+ : '';
77
+
78
+ return `version: "3.8"
79
+
80
+ services:
81
+ ${agentName}:
82
+ build: .
83
+ ports:
84
+ - "${port}:${port}"
85
+ environment:
86
+ - NODE_ENV=production
87
+ - PORT=${port}
88
+ ${envLines ? envLines + '\n' : ''} restart: unless-stopped
89
+ ${replicas > 1 ? ` deploy:\n replicas: ${replicas}` : ''}
90
+ volumes:
91
+ - agent-data:/app/data
92
+
93
+ volumes:
94
+ agent-data:
95
+ `;
96
+ }
97
+
98
+ /**
99
+ * Deploy to Railway (via CLI)
100
+ */
101
+ async deployRailway(agentDir: string): Promise<DeployResult> {
102
+ try {
103
+ execSync('railway version', { stdio: 'pipe' });
104
+ } catch {
105
+ return { platform: 'railway', success: false, message: 'Railway CLI not installed. Run: npm i -g @railway/cli' };
106
+ }
107
+
108
+ try {
109
+ // Ensure Dockerfile exists
110
+ const dockerfilePath = path.join(agentDir, 'Dockerfile');
111
+ if (!fs.existsSync(dockerfilePath)) {
112
+ const content = await this.generateDockerfile(agentDir);
113
+ fs.writeFileSync(dockerfilePath, content);
114
+ }
115
+
116
+ const output = execSync('railway up --detach', { cwd: agentDir, encoding: 'utf-8' });
117
+ const urlMatch = output.match(/(https:\/\/[^\s]+)/);
118
+ return {
119
+ platform: 'railway',
120
+ success: true,
121
+ url: urlMatch?.[1],
122
+ message: 'Deployed to Railway successfully'
123
+ };
124
+ } catch (e: any) {
125
+ return { platform: 'railway', success: false, message: e.message };
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Deploy to Fly.io
131
+ */
132
+ async deployFly(agentDir: string): Promise<DeployResult> {
133
+ try {
134
+ execSync('fly version', { stdio: 'pipe' });
135
+ } catch {
136
+ return { platform: 'fly', success: false, message: 'Fly CLI not installed. Run: curl -L https://fly.io/install.sh | sh' };
137
+ }
138
+
139
+ try {
140
+ const agentName = path.basename(agentDir).toLowerCase().replace(/[^a-z0-9-]/g, '-');
141
+
142
+ // Generate fly.toml if not exists
143
+ const flyTomlPath = path.join(agentDir, 'fly.toml');
144
+ if (!fs.existsSync(flyTomlPath)) {
145
+ fs.writeFileSync(flyTomlPath, `app = "${agentName}"
146
+ primary_region = "sjc"
147
+
148
+ [build]
149
+
150
+ [http_service]
151
+ internal_port = 3000
152
+ force_https = true
153
+ auto_stop_machines = true
154
+ auto_start_machines = true
155
+
156
+ [checks]
157
+ [checks.alive]
158
+ type = "tcp"
159
+ port = 3000
160
+ `);
161
+ }
162
+
163
+ // Ensure Dockerfile exists
164
+ const dockerfilePath = path.join(agentDir, 'Dockerfile');
165
+ if (!fs.existsSync(dockerfilePath)) {
166
+ const content = await this.generateDockerfile(agentDir);
167
+ fs.writeFileSync(dockerfilePath, content);
168
+ }
169
+
170
+ const output = execSync('fly deploy', { cwd: agentDir, encoding: 'utf-8' });
171
+ return {
172
+ platform: 'fly',
173
+ success: true,
174
+ url: `https://${agentName}.fly.dev`,
175
+ message: 'Deployed to Fly.io successfully'
176
+ };
177
+ } catch (e: any) {
178
+ return { platform: 'fly', success: false, message: e.message };
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Deploy locally via Docker
184
+ */
185
+ async deployLocal(agentDir: string, options?: DeployOptions): Promise<DeployResult> {
186
+ try {
187
+ execSync('docker version', { stdio: 'pipe' });
188
+ } catch {
189
+ return { platform: 'docker', success: false, message: 'Docker not installed or not running' };
190
+ }
191
+
192
+ const files: string[] = [];
193
+
194
+ // Generate Dockerfile
195
+ const dockerfilePath = path.join(agentDir, 'Dockerfile');
196
+ if (!fs.existsSync(dockerfilePath)) {
197
+ fs.writeFileSync(dockerfilePath, await this.generateDockerfile(agentDir, options));
198
+ files.push('Dockerfile');
199
+ }
200
+
201
+ // Generate docker-compose.yml
202
+ const composePath = path.join(agentDir, 'docker-compose.yml');
203
+ if (!fs.existsSync(composePath)) {
204
+ fs.writeFileSync(composePath, await this.generateCompose(agentDir, options));
205
+ files.push('docker-compose.yml');
206
+ }
207
+
208
+ try {
209
+ execSync('docker compose up -d --build', { cwd: agentDir, stdio: 'inherit' });
210
+ const port = options?.port || 3000;
211
+ return {
212
+ platform: 'docker',
213
+ success: true,
214
+ url: `http://localhost:${port}`,
215
+ message: 'Running locally via Docker',
216
+ files
217
+ };
218
+ } catch (e: any) {
219
+ return { platform: 'docker', success: false, message: e.message, files };
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Generate deployment files without deploying
225
+ */
226
+ async generateFiles(agentDir: string, options?: DeployOptions): Promise<DeployResult> {
227
+ const files: string[] = [];
228
+ const port = options?.port || 3000;
229
+
230
+ const dockerfile = await this.generateDockerfile(agentDir, options);
231
+ fs.writeFileSync(path.join(agentDir, 'Dockerfile'), dockerfile);
232
+ files.push('Dockerfile');
233
+
234
+ const compose = await this.generateCompose(agentDir, options);
235
+ fs.writeFileSync(path.join(agentDir, 'docker-compose.yml'), compose);
236
+ files.push('docker-compose.yml');
237
+
238
+ // Generate .dockerignore
239
+ const dockerignore = `node_modules
240
+ .git
241
+ .env
242
+ *.log
243
+ dist
244
+ `;
245
+ fs.writeFileSync(path.join(agentDir, '.dockerignore'), dockerignore);
246
+ files.push('.dockerignore');
247
+
248
+ return {
249
+ platform: 'docker',
250
+ success: true,
251
+ message: `Generated ${files.length} deployment files`,
252
+ files,
253
+ };
254
+ }
255
+ }
package/src/index.ts CHANGED
@@ -40,7 +40,8 @@ export type { A2ARequest, A2AResponse, AgentCapability, AgentRegistration, Agent
40
40
  export { HITLManager } from './core/hitl';
41
41
  export type { ApprovalRequest, ApprovalResponse, HITLConfig } from './core/hitl';
42
42
  export { VoiceChannel } from './channels/voice';
43
- export type { VoiceChannelConfig, STTProvider, TTSProvider } from './channels/voice';
43
+ export type { VoiceChannelConfig, STTProvider, TTSProvider, VoiceConfig } from './channels/voice';
44
+ export { WhisperSTTProvider, DeepgramSTTProvider, EdgeTTSProvider, OpenAITTSProvider, ElevenLabsTTSProvider, createVoiceProviders } from './channels/voice';
44
45
  export { WebhookChannel } from './channels/webhook';
45
46
  export type { WebhookConfig, WebhookPayload } from './channels/webhook';
46
47
  export { VersionManager } from './core/versioning';
@@ -106,6 +107,10 @@ export { loggerPlugin } from './plugins/logger';
106
107
  export { rateLimiterPlugin, createRateLimiterPlugin as createEnhancedRateLimiterPlugin } from './plugins/rate-limiter';
107
108
  export { contentFilterPlugin, createContentFilterPlugin } from './plugins/content-filter';
108
109
 
110
+ // v2.1.0 — Guardrails
111
+ export { GuardrailManager, createGuardrailsFromConfig } from './security/guardrails';
112
+ export type { GuardrailConfig, GuardrailRule, GuardrailResult, GuardrailViolation } from './security/guardrails';
113
+
109
114
  // v1.1.0 modules
110
115
  export { FeishuChannel } from './channels/feishu';
111
116
  export type { FeishuChannelConfig } from './channels/feishu';
@@ -168,6 +173,10 @@ export type { EvalCase, EvalResult, EvalSuite, EvalReport } from './eval';
168
173
  // v1.9.0 — AG-UI Protocol (Agent-User Interaction)
169
174
  export { AGUIServer, AGUIEventEmitter, AGUIClient } from './protocols/agui';
170
175
  export { AGUI_EVENT_TYPES, isValidEventType } from './protocols/agui';
176
+ // v2.0.0 - Multi-agent collaboration patterns
177
+ export { DebatePattern, VotingPattern, PipelinePattern, HierarchyPattern, SharedContext, ConversationProtocol } from './core/collaboration';
178
+ export type { DebateResult, DebateArgument, VoteResult, VoteEntry, PipelineResult, PipelineStageResult, HierarchyResult, WorkerResult } from './core/collaboration';
179
+
171
180
  export type {
172
181
  AGUIEvent, AGUIEventType, AGUIMessage, AGUIRunRequest, AGUIToolCall,
173
182
  AGUIToolDefinition, TextMessageStartEvent, TextMessageContentEvent,
@@ -176,3 +185,14 @@ export type {
176
185
  RunStartedEvent, RunFinishedEvent, RunErrorEvent,
177
186
  StepStartedEvent, StepFinishedEvent, CustomEvent,
178
187
  } from './protocols/agui';
188
+
189
+ // v2.0.0 - Pre-built tool integrations (20 tools)
190
+ export {
191
+ SlackTool, EmailSendTool, WebhookTool,
192
+ NotionTool, GitHubTool, JiraTool, CalendarTool, TrelloTool,
193
+ WebSearchTool, WebScraperTool, DatabaseTool, VectorSearchTool,
194
+ CodeExecutionTool, GitTool, NpmTool,
195
+ ImageGenerationTool, PDFReaderTool, CSVAnalyzerTool,
196
+ SummarizerTool, TranslatorTool,
197
+ getAllIntegrationTools, getIntegrationTool,
198
+ } from './tools/integrations';
@@ -0,0 +1,65 @@
1
+ import type { MCPServerConfig } from '../../protocols/mcp/types';
2
+
3
+ const UNITS: Record<string, Record<string, number>> = {
4
+ length: { m: 1, km: 1000, cm: 0.01, mm: 0.001, in: 0.0254, ft: 0.3048, yd: 0.9144, mi: 1609.344 },
5
+ weight: { kg: 1, g: 0.001, mg: 0.000001, lb: 0.453592, oz: 0.0283495, ton: 1000 },
6
+ temperature: {}, // special
7
+ };
8
+
9
+ function convertTemp(value: number, from: string, to: string): number {
10
+ let celsius = from === 'C' ? value : from === 'F' ? (value - 32) * 5/9 : value - 273.15;
11
+ return to === 'C' ? celsius : to === 'F' ? celsius * 9/5 + 32 : celsius + 273.15;
12
+ }
13
+
14
+ export function createCalculatorServer(): MCPServerConfig {
15
+ return {
16
+ name: 'calculator',
17
+ version: '1.0.0',
18
+ tools: [
19
+ {
20
+ name: 'calc_evaluate',
21
+ description: 'Evaluate a mathematical expression (safe eval with Math functions)',
22
+ inputSchema: { type: 'object', properties: { expression: { type: 'string', description: 'Math expression, e.g. "sqrt(16) + pow(2,3)"' } }, required: ['expression'] },
23
+ handler: async (args: { expression: string }) => {
24
+ const safe = args.expression.replace(/[^0-9+\-*/().,%\s]/g, (m) => {
25
+ const allowed = ['Math','PI','E','sqrt','pow','abs','sin','cos','tan','log','log2','log10','ceil','floor','round','min','max','random'];
26
+ return allowed.some(a => m.includes(a)) ? m : '';
27
+ });
28
+ const fn = new Function('Math', `"use strict"; return (${args.expression})`);
29
+ const result = fn(Math);
30
+ return { expression: args.expression, result };
31
+ },
32
+ },
33
+ {
34
+ name: 'calc_convert',
35
+ description: 'Convert between units (length, weight, temperature)',
36
+ inputSchema: { type: 'object', properties: { value: { type: 'number' }, from: { type: 'string' }, to: { type: 'string' }, category: { type: 'string', enum: ['length', 'weight', 'temperature'] } }, required: ['value', 'from', 'to'] },
37
+ handler: async (args: { value: number; from: string; to: string; category?: string }) => {
38
+ if (['C', 'F', 'K'].includes(args.from) && ['C', 'F', 'K'].includes(args.to)) {
39
+ return { value: args.value, from: args.from, to: args.to, result: convertTemp(args.value, args.from, args.to) };
40
+ }
41
+ for (const [, units] of Object.entries(UNITS)) {
42
+ if (units[args.from] && units[args.to]) {
43
+ const base = args.value * units[args.from];
44
+ return { value: args.value, from: args.from, to: args.to, result: base / units[args.to] };
45
+ }
46
+ }
47
+ throw new Error(`Cannot convert ${args.from} to ${args.to}`);
48
+ },
49
+ },
50
+ {
51
+ name: 'calc_percentage',
52
+ description: 'Calculate percentages: what is X% of Y, X is what % of Y, % change',
53
+ inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['of', 'is_what_percent', 'change'] }, x: { type: 'number' }, y: { type: 'number' } }, required: ['operation', 'x', 'y'] },
54
+ handler: async (args: { operation: string; x: number; y: number }) => {
55
+ switch (args.operation) {
56
+ case 'of': return { result: (args.x / 100) * args.y, description: `${args.x}% of ${args.y}` };
57
+ case 'is_what_percent': return { result: (args.x / args.y) * 100, description: `${args.x} is ${((args.x / args.y) * 100).toFixed(2)}% of ${args.y}` };
58
+ case 'change': return { result: ((args.y - args.x) / args.x) * 100, description: `Change from ${args.x} to ${args.y}` };
59
+ default: throw new Error('Unknown operation');
60
+ }
61
+ },
62
+ },
63
+ ],
64
+ };
65
+ }