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.
- package/README.md +603 -545
- package/dist/channels/voice.d.ts +59 -0
- package/dist/channels/voice.js +351 -1
- package/dist/cli.js +284 -5
- package/dist/core/agent.d.ts +9 -0
- package/dist/core/agent.js +49 -0
- package/dist/core/collaboration.d.ts +89 -0
- package/dist/core/collaboration.js +201 -0
- package/dist/deploy/index.d.ts +40 -0
- package/dist/deploy/index.js +261 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +47 -3
- package/dist/mcp/servers/calculator-mcp.d.ts +3 -0
- package/dist/mcp/servers/calculator-mcp.js +65 -0
- package/dist/mcp/servers/crypto-mcp.d.ts +3 -0
- package/dist/mcp/servers/crypto-mcp.js +108 -0
- package/dist/mcp/servers/database-mcp.d.ts +3 -0
- package/dist/mcp/servers/database-mcp.js +73 -0
- package/dist/mcp/servers/datetime-mcp.d.ts +3 -0
- package/dist/mcp/servers/datetime-mcp.js +71 -0
- package/dist/mcp/servers/filesystem.d.ts +3 -0
- package/dist/mcp/servers/filesystem.js +101 -0
- package/dist/mcp/servers/github-mcp.d.ts +3 -0
- package/dist/mcp/servers/github-mcp.js +60 -0
- package/dist/mcp/servers/index.d.ts +21 -0
- package/dist/mcp/servers/index.js +50 -0
- package/dist/mcp/servers/json-mcp.d.ts +3 -0
- package/dist/mcp/servers/json-mcp.js +126 -0
- package/dist/mcp/servers/memory-mcp.d.ts +3 -0
- package/dist/mcp/servers/memory-mcp.js +60 -0
- package/dist/mcp/servers/regex-mcp.d.ts +3 -0
- package/dist/mcp/servers/regex-mcp.js +56 -0
- package/dist/mcp/servers/web-mcp.d.ts +3 -0
- package/dist/mcp/servers/web-mcp.js +51 -0
- package/dist/memory/index.d.ts +2 -0
- package/dist/memory/index.js +4 -1
- package/dist/memory/seed-loader.d.ts +51 -0
- package/dist/memory/seed-loader.js +200 -0
- package/dist/schema/oad.d.ts +292 -12
- package/dist/schema/oad.js +12 -1
- package/dist/security/guardrails.d.ts +50 -0
- package/dist/security/guardrails.js +197 -0
- package/dist/studio/server.d.ts +31 -1
- package/dist/studio/server.js +154 -3
- package/dist/studio-ui/index.html +1278 -662
- package/dist/tools/integrations/calendar.d.ts +3 -0
- package/dist/tools/integrations/calendar.js +73 -0
- package/dist/tools/integrations/code-exec.d.ts +3 -0
- package/dist/tools/integrations/code-exec.js +42 -0
- package/dist/tools/integrations/csv-analyzer.d.ts +3 -0
- package/dist/tools/integrations/csv-analyzer.js +142 -0
- package/dist/tools/integrations/database.d.ts +3 -0
- package/dist/tools/integrations/database.js +44 -0
- package/dist/tools/integrations/email-send.d.ts +3 -0
- package/dist/tools/integrations/email-send.js +104 -0
- package/dist/tools/integrations/git-tool.d.ts +3 -0
- package/dist/tools/integrations/git-tool.js +49 -0
- package/dist/tools/integrations/github-tool.d.ts +3 -0
- package/dist/tools/integrations/github-tool.js +77 -0
- package/dist/tools/integrations/image-gen.d.ts +3 -0
- package/dist/tools/integrations/image-gen.js +58 -0
- package/dist/tools/integrations/index.d.ts +30 -0
- package/dist/tools/integrations/index.js +107 -0
- package/dist/tools/integrations/jira.d.ts +3 -0
- package/dist/tools/integrations/jira.js +85 -0
- package/dist/tools/integrations/notion.d.ts +3 -0
- package/dist/tools/integrations/notion.js +71 -0
- package/dist/tools/integrations/npm-tool.d.ts +3 -0
- package/dist/tools/integrations/npm-tool.js +49 -0
- package/dist/tools/integrations/pdf-reader.d.ts +3 -0
- package/dist/tools/integrations/pdf-reader.js +91 -0
- package/dist/tools/integrations/slack.d.ts +3 -0
- package/dist/tools/integrations/slack.js +67 -0
- package/dist/tools/integrations/summarizer.d.ts +3 -0
- package/dist/tools/integrations/summarizer.js +49 -0
- package/dist/tools/integrations/translator.d.ts +3 -0
- package/dist/tools/integrations/translator.js +48 -0
- package/dist/tools/integrations/trello.d.ts +3 -0
- package/dist/tools/integrations/trello.js +60 -0
- package/dist/tools/integrations/vector-search.d.ts +3 -0
- package/dist/tools/integrations/vector-search.js +44 -0
- package/dist/tools/integrations/web-scraper.d.ts +3 -0
- package/dist/tools/integrations/web-scraper.js +48 -0
- package/dist/tools/integrations/web-search.d.ts +3 -0
- package/dist/tools/integrations/web-search.js +60 -0
- package/dist/tools/integrations/webhook.d.ts +3 -0
- package/dist/tools/integrations/webhook.js +39 -0
- package/dist/ui/components.d.ts +10 -0
- package/dist/ui/components.js +123 -0
- package/package.json +1 -1
- package/src/channels/voice.ts +365 -0
- package/src/cli.ts +294 -6
- package/src/core/agent.ts +56 -0
- package/src/core/collaboration.ts +275 -0
- package/src/deploy/index.ts +255 -0
- package/src/index.ts +21 -1
- package/src/mcp/servers/calculator-mcp.ts +65 -0
- package/src/mcp/servers/crypto-mcp.ts +73 -0
- package/src/mcp/servers/database-mcp.ts +72 -0
- package/src/mcp/servers/datetime-mcp.ts +69 -0
- package/src/mcp/servers/filesystem.ts +66 -0
- package/src/mcp/servers/github-mcp.ts +58 -0
- package/src/mcp/servers/index.ts +63 -0
- package/src/mcp/servers/json-mcp.ts +102 -0
- package/src/mcp/servers/memory-mcp.ts +56 -0
- package/src/mcp/servers/regex-mcp.ts +53 -0
- package/src/mcp/servers/web-mcp.ts +49 -0
- package/src/memory/index.ts +3 -0
- package/src/memory/seed-loader.ts +212 -0
- package/src/schema/oad.ts +13 -0
- package/src/security/guardrails.ts +248 -0
- package/src/studio/server.ts +166 -4
- package/src/studio-ui/index.html +1278 -662
- package/src/tools/integrations/calendar.ts +73 -0
- package/src/tools/integrations/code-exec.ts +39 -0
- package/src/tools/integrations/csv-analyzer.ts +92 -0
- package/src/tools/integrations/database.ts +44 -0
- package/src/tools/integrations/email-send.ts +76 -0
- package/src/tools/integrations/git-tool.ts +42 -0
- package/src/tools/integrations/github-tool.ts +76 -0
- package/src/tools/integrations/image-gen.ts +56 -0
- package/src/tools/integrations/index.ts +92 -0
- package/src/tools/integrations/jira.ts +83 -0
- package/src/tools/integrations/notion.ts +71 -0
- package/src/tools/integrations/npm-tool.ts +48 -0
- package/src/tools/integrations/pdf-reader.ts +58 -0
- package/src/tools/integrations/slack.ts +65 -0
- package/src/tools/integrations/summarizer.ts +49 -0
- package/src/tools/integrations/translator.ts +48 -0
- package/src/tools/integrations/trello.ts +60 -0
- package/src/tools/integrations/vector-search.ts +42 -0
- package/src/tools/integrations/web-scraper.ts +47 -0
- package/src/tools/integrations/web-search.ts +58 -0
- package/src/tools/integrations/webhook.ts +38 -0
- package/src/ui/components.ts +127 -0
- package/tests/brain-seed-extended.test.ts +490 -0
- package/tests/brain-seed.test.ts +239 -0
- package/tests/collaboration.test.ts +319 -0
- package/tests/deploy-and-dag.test.ts +196 -0
- package/tests/guardrails.test.ts +177 -0
- package/tests/integrations.test.ts +249 -0
- package/tests/mcp-servers.test.ts +260 -0
- package/tests/voice-enhanced.test.ts +169 -0
- package/dist/dtv/data.d.ts +0 -18
- package/dist/dtv/data.js +0 -25
- package/dist/dtv/trust.d.ts +0 -19
- package/dist/dtv/trust.js +0 -40
- package/dist/dtv/value.d.ts +0 -23
- package/dist/dtv/value.js +0 -38
- package/dist/marketplace/index.d.ts +0 -34
- package/dist/marketplace/index.js +0 -202
package/src/studio/server.ts
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
import { createServer, IncomingMessage, ServerResponse, request as httpRequest } from 'http';
|
|
2
|
-
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
3
|
import { join, extname } from 'path';
|
|
4
4
|
import * as net from 'net';
|
|
5
5
|
import { Tracer } from '../telemetry';
|
|
6
6
|
|
|
7
|
+
export interface WorkflowNode {
|
|
8
|
+
id: string;
|
|
9
|
+
type: 'agent' | 'tool' | 'condition' | 'loop' | 'parallel' | 'input' | 'output';
|
|
10
|
+
name: string;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
config: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface WorkflowEdge {
|
|
17
|
+
id: string;
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
fromPort: string;
|
|
21
|
+
toPort: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface WorkflowDefinition {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
nodes: WorkflowNode[];
|
|
28
|
+
edges: WorkflowEdge[];
|
|
29
|
+
created: string;
|
|
30
|
+
updated: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
7
33
|
interface StudioConfig {
|
|
8
34
|
port: number;
|
|
9
35
|
agentDir: string;
|
|
@@ -100,6 +126,29 @@ class StudioServer {
|
|
|
100
126
|
try {
|
|
101
127
|
let data: any;
|
|
102
128
|
|
|
129
|
+
// Dynamic workflow routes (parameterized)
|
|
130
|
+
if (route.match(/^workflows\/[^/]+\/run$/) && req.method === 'POST') {
|
|
131
|
+
const wfId = route.split('/')[1];
|
|
132
|
+
data = await this.runWorkflow(wfId);
|
|
133
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
134
|
+
res.end(JSON.stringify(data));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (route.match(/^workflows\/[^/]+$/) && req.method === 'GET') {
|
|
138
|
+
const wfId = route.split('/')[1];
|
|
139
|
+
data = this.getWorkflowById(wfId);
|
|
140
|
+
res.writeHead(data.error ? 404 : 200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
141
|
+
res.end(JSON.stringify(data));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (route.match(/^workflows\/[^/]+$/) && req.method === 'DELETE') {
|
|
145
|
+
const wfId = route.split('/')[1];
|
|
146
|
+
data = this.deleteWorkflow(wfId);
|
|
147
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
|
|
148
|
+
res.end(JSON.stringify(data));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
103
152
|
switch (route) {
|
|
104
153
|
case 'modules':
|
|
105
154
|
data = await this.getModulesStatus();
|
|
@@ -130,7 +179,12 @@ class StudioServer {
|
|
|
130
179
|
data = await this.getTools();
|
|
131
180
|
break;
|
|
132
181
|
case 'workflows/list':
|
|
133
|
-
data =
|
|
182
|
+
data = this.listWorkflows();
|
|
183
|
+
break;
|
|
184
|
+
case 'workflows':
|
|
185
|
+
if (req.method === 'POST') data = await this.saveWorkflow(req);
|
|
186
|
+
else if (req.method === 'GET') data = this.listWorkflows();
|
|
187
|
+
else { res.writeHead(405); res.end(); return; }
|
|
134
188
|
break;
|
|
135
189
|
case 'jobs/list':
|
|
136
190
|
data = await this.getJobs();
|
|
@@ -188,6 +242,14 @@ class StudioServer {
|
|
|
188
242
|
case 'telemetry/metrics':
|
|
189
243
|
data = this.tracer ? this.tracer.getMetrics() : [];
|
|
190
244
|
break;
|
|
245
|
+
case 'playground/chat':
|
|
246
|
+
if (req.method === 'POST') {
|
|
247
|
+
return this.handlePlaygroundChat(req, res);
|
|
248
|
+
}
|
|
249
|
+
res.writeHead(405); res.end(); return;
|
|
250
|
+
case 'playground/models':
|
|
251
|
+
data = { models: ['gpt-4o', 'gpt-4o-mini', 'claude-sonnet-4', 'claude-haiku', 'gemini-2.0-flash', 'deepseek-v3'] };
|
|
252
|
+
break;
|
|
191
253
|
default:
|
|
192
254
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
193
255
|
res.end(JSON.stringify({ error: 'Not found' }));
|
|
@@ -333,9 +395,84 @@ class StudioServer {
|
|
|
333
395
|
}
|
|
334
396
|
}
|
|
335
397
|
|
|
336
|
-
private
|
|
398
|
+
private getWorkflowsDir(): string {
|
|
399
|
+
const dir = join(this.config.agentDir, '.opc', 'workflows');
|
|
400
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
401
|
+
return dir;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
private listWorkflows(): { workflows: WorkflowDefinition[] } {
|
|
405
|
+
const dir = this.getWorkflowsDir();
|
|
406
|
+
const files = require('fs').readdirSync(dir).filter((f: string) => f.endsWith('.json'));
|
|
407
|
+
const workflows = files.map((f: string) => {
|
|
408
|
+
try { return JSON.parse(readFileSync(join(dir, f), 'utf-8')); } catch { return null; }
|
|
409
|
+
}).filter(Boolean);
|
|
410
|
+
// Also include OAD-defined workflows
|
|
337
411
|
const oad = this.loadOAD();
|
|
338
|
-
|
|
412
|
+
const oadWorkflows = (oad?.spec?.workflows || []).map((w: any, i: number) => ({
|
|
413
|
+
id: `oad-${i}`,
|
|
414
|
+
name: w.name || `Workflow ${i + 1}`,
|
|
415
|
+
nodes: [],
|
|
416
|
+
edges: [],
|
|
417
|
+
steps: w.steps,
|
|
418
|
+
source: 'oad',
|
|
419
|
+
}));
|
|
420
|
+
return { workflows: [...workflows, ...oadWorkflows] };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
private getWorkflowById(id: string): WorkflowDefinition | { error: string } {
|
|
424
|
+
const filePath = join(this.getWorkflowsDir(), `${id}.json`);
|
|
425
|
+
if (!existsSync(filePath)) return { error: 'Workflow not found' };
|
|
426
|
+
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
private async saveWorkflow(req: IncomingMessage): Promise<{ success: boolean; id: string }> {
|
|
430
|
+
const body = await this.readBody(req);
|
|
431
|
+
const workflow = JSON.parse(body) as WorkflowDefinition;
|
|
432
|
+
if (!workflow.id) workflow.id = `wf-${Date.now()}`;
|
|
433
|
+
workflow.updated = new Date().toISOString();
|
|
434
|
+
if (!workflow.created) workflow.created = workflow.updated;
|
|
435
|
+
const filePath = join(this.getWorkflowsDir(), `${workflow.id}.json`);
|
|
436
|
+
writeFileSync(filePath, JSON.stringify(workflow, null, 2));
|
|
437
|
+
return { success: true, id: workflow.id };
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
private deleteWorkflow(id: string): { success: boolean } {
|
|
441
|
+
const filePath = join(this.getWorkflowsDir(), `${id}.json`);
|
|
442
|
+
if (existsSync(filePath)) require('fs').unlinkSync(filePath);
|
|
443
|
+
return { success: true };
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private async runWorkflow(id: string): Promise<any> {
|
|
447
|
+
const wf = this.getWorkflowById(id);
|
|
448
|
+
if ('error' in wf) return wf;
|
|
449
|
+
// Basic topological execution simulation
|
|
450
|
+
const results: Record<string, any> = {};
|
|
451
|
+
const sorted = this.topoSort(wf.nodes, wf.edges);
|
|
452
|
+
for (const node of sorted) {
|
|
453
|
+
results[node.id] = { type: node.type, name: node.name, status: 'completed', output: `[simulated output for ${node.name}]` };
|
|
454
|
+
}
|
|
455
|
+
return { workflowId: id, status: 'completed', results };
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private topoSort(nodes: WorkflowNode[], edges: WorkflowEdge[]): WorkflowNode[] {
|
|
459
|
+
const nodeMap = new Map(nodes.map(n => [n.id, n]));
|
|
460
|
+
const inDegree = new Map<string, number>();
|
|
461
|
+
const adj = new Map<string, string[]>();
|
|
462
|
+
for (const n of nodes) { inDegree.set(n.id, 0); adj.set(n.id, []); }
|
|
463
|
+
for (const e of edges) { adj.get(e.from)?.push(e.to); inDegree.set(e.to, (inDegree.get(e.to) || 0) + 1); }
|
|
464
|
+
const queue = nodes.filter(n => (inDegree.get(n.id) || 0) === 0);
|
|
465
|
+
const result: WorkflowNode[] = [];
|
|
466
|
+
while (queue.length > 0) {
|
|
467
|
+
const node = queue.shift()!;
|
|
468
|
+
result.push(node);
|
|
469
|
+
for (const next of (adj.get(node.id) || [])) {
|
|
470
|
+
const d = (inDegree.get(next) || 1) - 1;
|
|
471
|
+
inDegree.set(next, d);
|
|
472
|
+
if (d === 0) queue.push(nodeMap.get(next)!);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
339
476
|
}
|
|
340
477
|
|
|
341
478
|
private async getJobs() {
|
|
@@ -616,6 +753,31 @@ class StudioServer {
|
|
|
616
753
|
res.end(content);
|
|
617
754
|
}
|
|
618
755
|
|
|
756
|
+
private async handlePlaygroundChat(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
757
|
+
const body = JSON.parse(await this.readBody(req));
|
|
758
|
+
const { messages = [], model = 'gpt-4o', temperature = 0.7, systemPrompt } = body;
|
|
759
|
+
|
|
760
|
+
res.writeHead(200, {
|
|
761
|
+
'Content-Type': 'text/event-stream',
|
|
762
|
+
'Cache-Control': 'no-cache',
|
|
763
|
+
'Connection': 'keep-alive',
|
|
764
|
+
'Access-Control-Allow-Origin': '*',
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
// Simulated streaming response for playground demo
|
|
768
|
+
const allMsgs = systemPrompt ? [{ role: 'system', content: systemPrompt }, ...messages] : messages;
|
|
769
|
+
const lastMsg = allMsgs[allMsgs.length - 1]?.content || '';
|
|
770
|
+
const response = `This is a playground demo response to: "${lastMsg}"\n\nModel: ${model}, Temperature: ${temperature}\nMessages in context: ${allMsgs.length}`;
|
|
771
|
+
|
|
772
|
+
const words = response.split(' ');
|
|
773
|
+
for (let i = 0; i < words.length; i++) {
|
|
774
|
+
const chunk = (i === 0 ? '' : ' ') + words[i];
|
|
775
|
+
res.write(`data: ${JSON.stringify({ content: chunk })}\n\n`);
|
|
776
|
+
}
|
|
777
|
+
res.write('data: [DONE]\n\n');
|
|
778
|
+
res.end();
|
|
779
|
+
}
|
|
780
|
+
|
|
619
781
|
private readBody(req: IncomingMessage): Promise<string> {
|
|
620
782
|
return new Promise((resolve, reject) => {
|
|
621
783
|
let body = '';
|