opc-agent 0.6.0 → 0.7.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.
@@ -1,6 +1,7 @@
1
1
  import { type Response } from 'express';
2
2
  import type { Message } from '../core/types';
3
3
  import { BaseChannel } from './index';
4
+ import { type AuthConfig } from '../core/auth';
4
5
  export declare class WebChannel extends BaseChannel {
5
6
  readonly type = "web";
6
7
  private app;
@@ -11,11 +12,16 @@ export declare class WebChannel extends BaseChannel {
11
12
  private currentProvider;
12
13
  private stats;
13
14
  private eventHandlers;
15
+ private conversations;
16
+ private requestCount;
17
+ private llmLatencySum;
18
+ private llmCalls;
14
19
  private emit;
15
20
  onConfigChange(handler: (config: any) => void): void;
16
21
  trackMessage(responseMs: number, tokens?: number): void;
22
+ trackError(): void;
17
23
  trackSession(): void;
18
- constructor(port?: number);
24
+ constructor(port?: number, authConfig?: AuthConfig);
19
25
  setAgentName(name: string): void;
20
26
  onStreamMessage(handler: (msg: Message, res: Response) => Promise<void>): void;
21
27
  private setupRoutes;
@@ -7,6 +7,57 @@ exports.WebChannel = void 0;
7
7
  const express_1 = __importDefault(require("express"));
8
8
  const index_1 = require("./index");
9
9
  const knowledge_1 = require("../core/knowledge");
10
+ const auth_1 = require("../core/auth");
11
+ const AGENT_TEMPLATES = [
12
+ { id: 'customer-service', name: 'Customer Service', description: 'Handle support tickets, FAQs, and customer inquiries', icon: '🎧', category: 'Business' },
13
+ { id: 'code-reviewer', name: 'Code Reviewer', description: 'Review PRs, suggest improvements, check for bugs', icon: '🔍', category: 'Engineering' },
14
+ { id: 'content-writer', name: 'Content Writer', description: 'Write blogs, social media posts, and marketing copy', icon: '✍️', category: 'Marketing' },
15
+ { id: 'executive-assistant', name: 'Executive Assistant', description: 'Schedule management, email drafting, meeting prep', icon: '📋', category: 'Business' },
16
+ { id: 'knowledge-base', name: 'Knowledge Base', description: 'RAG-powered Q&A over your documents', icon: '📚', category: 'Knowledge' },
17
+ { id: 'project-manager', name: 'Project Manager', description: 'Track tasks, milestones, and team coordination', icon: '📊', category: 'Business' },
18
+ { id: 'sales-assistant', name: 'Sales Assistant', description: 'Lead qualification, outreach drafting, CRM updates', icon: '💼', category: 'Sales' },
19
+ { id: 'financial-advisor', name: 'Financial Advisor', description: 'Budget analysis, financial planning, cost optimization', icon: '💰', category: 'Finance' },
20
+ { id: 'hr-recruiter', name: 'HR Recruiter', description: 'Resume screening, interview scheduling, candidate comms', icon: '👥', category: 'HR' },
21
+ { id: 'legal-assistant', name: 'Legal Assistant', description: 'Contract review, compliance checks, legal research', icon: '⚖️', category: 'Legal' },
22
+ ];
23
+ const TEMPLATES_HTML = `<!DOCTYPE html>
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
27
+ <title>Agent Templates</title>
28
+ <style>
29
+ *{margin:0;padding:0;box-sizing:border-box}
30
+ body{background:#0a0a0f;color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;padding:24px}
31
+ h1{font-size:28px;margin-bottom:8px;color:#fff}
32
+ .sub{color:#888;margin-bottom:32px;font-size:14px}
33
+ nav{margin-bottom:24px}
34
+ nav a{color:#818cf8;text-decoration:none;margin-right:16px;font-size:14px}
35
+ .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
36
+ .card{background:#12121a;border:1px solid #1e1e2e;border-radius:12px;padding:24px;cursor:pointer;transition:all .2s}
37
+ .card:hover{border-color:#818cf8;transform:translateY(-2px)}
38
+ .card .icon{font-size:32px;margin-bottom:12px}
39
+ .card h3{font-size:16px;color:#fff;margin-bottom:8px}
40
+ .card p{font-size:13px;color:#888;line-height:1.5}
41
+ .card .cat{font-size:11px;color:#818cf8;text-transform:uppercase;letter-spacing:1px;margin-top:12px}
42
+ .btn{display:inline-block;background:#2563eb;color:#fff;border:none;border-radius:8px;padding:8px 16px;font-size:13px;cursor:pointer;margin-top:12px}
43
+ .btn:hover{background:#1d4ed8}
44
+ </style>
45
+ </head>
46
+ <body>
47
+ <nav><a href="/">← Chat</a><a href="/dashboard">Dashboard</a><a href="/templates">Templates</a></nav>
48
+ <h1>🧩 Agent Templates</h1>
49
+ <p class="sub">Create a new agent from a pre-built template in one click.</p>
50
+ <div class="grid" id="grid"></div>
51
+ <script>
52
+ fetch('/api/templates').then(r=>r.json()).then(d=>{
53
+ const g=document.getElementById('grid');
54
+ d.templates.forEach(t=>{
55
+ g.innerHTML+=\`<div class="card"><div class="icon">\${t.icon}</div><h3>\${t.name}</h3><p>\${t.description}</p><div class="cat">\${t.category}</div><button class="btn" onclick="alert('Creating agent from template: '+'\${t.id}'+'\\\\nRun: opc init --template \${t.id}')">Use Template</button></div>\`;
56
+ });
57
+ });
58
+ </script>
59
+ </body>
60
+ </html>`;
10
61
  const CHAT_HTML = `<!DOCTYPE html>
11
62
  <html lang="en">
12
63
  <head>
@@ -157,8 +208,12 @@ class WebChannel extends index_1.BaseChannel {
157
208
  streamHandler = null;
158
209
  agentName = 'OPC Agent';
159
210
  currentProvider = 'openai';
160
- stats = { sessions: 0, messages: 0, totalResponseMs: 0, tokenUsage: 0, knowledgeFiles: 0, startedAt: Date.now() };
211
+ stats = { sessions: 0, messages: 0, totalResponseMs: 0, tokenUsage: 0, knowledgeFiles: 0, startedAt: Date.now(), errors: 0 };
161
212
  eventHandlers = new Map();
213
+ conversations = new Map();
214
+ requestCount = 0;
215
+ llmLatencySum = 0;
216
+ llmCalls = 0;
162
217
  emit(event, data) {
163
218
  const handlers = this.eventHandlers.get(event) ?? [];
164
219
  for (const h of handlers)
@@ -173,13 +228,20 @@ class WebChannel extends index_1.BaseChannel {
173
228
  this.stats.messages++;
174
229
  this.stats.totalResponseMs += responseMs;
175
230
  this.stats.tokenUsage += tokens;
231
+ this.requestCount++;
232
+ this.llmLatencySum += responseMs;
233
+ this.llmCalls++;
176
234
  }
235
+ trackError() { this.stats.errors++; }
177
236
  trackSession() { this.stats.sessions++; }
178
- constructor(port = 3000) {
237
+ constructor(port = 3000, authConfig) {
179
238
  super();
180
239
  this.port = port;
181
240
  this.app = (0, express_1.default)();
182
- this.app.use(express_1.default.json());
241
+ this.app.use(express_1.default.json({ limit: '10mb' }));
242
+ if (authConfig && authConfig.apiKeys.length > 0) {
243
+ this.app.use((0, auth_1.createAuthMiddleware)(authConfig));
244
+ }
183
245
  this.setupRoutes();
184
246
  }
185
247
  setAgentName(name) {
@@ -201,6 +263,7 @@ class WebChannel extends index_1.BaseChannel {
201
263
  // Streaming chat endpoint
202
264
  this.app.post('/api/chat', async (req, res) => {
203
265
  const { message, sessionId } = req.body;
266
+ const sid = sessionId ?? 'default';
204
267
  if (!message) {
205
268
  res.status(400).json({ error: 'message is required' });
206
269
  return;
@@ -210,8 +273,12 @@ class WebChannel extends index_1.BaseChannel {
210
273
  role: 'user',
211
274
  content: message,
212
275
  timestamp: Date.now(),
213
- metadata: { sessionId: sessionId ?? 'default' },
276
+ metadata: { sessionId: sid },
214
277
  };
278
+ // Track conversation
279
+ if (!this.conversations.has(sid))
280
+ this.conversations.set(sid, []);
281
+ this.conversations.get(sid).push(msg);
215
282
  if (this.streamHandler) {
216
283
  try {
217
284
  await this.streamHandler(msg, res);
@@ -290,6 +357,100 @@ class WebChannel extends index_1.BaseChannel {
290
357
  res.json({ totalEntries: 0, sources: [] });
291
358
  }
292
359
  });
360
+ // --- Health Check (detailed) ---
361
+ this.app.get('/api/health', (_req, res) => {
362
+ const uptimeMs = Date.now() - this.stats.startedAt;
363
+ res.json({
364
+ status: 'ok',
365
+ timestamp: Date.now(),
366
+ uptime: uptimeMs,
367
+ uptimeHuman: `${Math.floor(uptimeMs / 3600000)}h ${Math.floor((uptimeMs % 3600000) / 60000)}m`,
368
+ version: '0.7.0',
369
+ agent: this.agentName,
370
+ stats: {
371
+ sessions: this.stats.sessions,
372
+ messages: this.stats.messages,
373
+ errors: this.stats.errors,
374
+ avgResponseMs: this.stats.messages > 0 ? Math.round(this.stats.totalResponseMs / this.stats.messages) : 0,
375
+ },
376
+ memory: {
377
+ rss: process.memoryUsage().rss,
378
+ heapUsed: process.memoryUsage().heapUsed,
379
+ },
380
+ });
381
+ });
382
+ // --- Prometheus Metrics ---
383
+ this.app.get('/api/metrics', (_req, res) => {
384
+ const uptimeMs = Date.now() - this.stats.startedAt;
385
+ const avgLatency = this.llmCalls > 0 ? this.llmLatencySum / this.llmCalls : 0;
386
+ const mem = process.memoryUsage();
387
+ res.type('text/plain').send(`# HELP opc_uptime_seconds Agent uptime in seconds\n` +
388
+ `# TYPE opc_uptime_seconds gauge\n` +
389
+ `opc_uptime_seconds ${(uptimeMs / 1000).toFixed(1)}\n` +
390
+ `# HELP opc_requests_total Total requests\n` +
391
+ `# TYPE opc_requests_total counter\n` +
392
+ `opc_requests_total ${this.requestCount}\n` +
393
+ `# HELP opc_messages_total Total messages processed\n` +
394
+ `# TYPE opc_messages_total counter\n` +
395
+ `opc_messages_total ${this.stats.messages}\n` +
396
+ `# HELP opc_errors_total Total errors\n` +
397
+ `# TYPE opc_errors_total counter\n` +
398
+ `opc_errors_total ${this.stats.errors}\n` +
399
+ `# HELP opc_llm_latency_avg_ms Average LLM response latency\n` +
400
+ `# TYPE opc_llm_latency_avg_ms gauge\n` +
401
+ `opc_llm_latency_avg_ms ${avgLatency.toFixed(1)}\n` +
402
+ `# HELP opc_sessions_total Total sessions\n` +
403
+ `# TYPE opc_sessions_total counter\n` +
404
+ `opc_sessions_total ${this.stats.sessions}\n` +
405
+ `# HELP opc_token_usage_total Total token usage\n` +
406
+ `# TYPE opc_token_usage_total counter\n` +
407
+ `opc_token_usage_total ${this.stats.tokenUsage}\n` +
408
+ `# HELP process_resident_memory_bytes Resident memory size\n` +
409
+ `# TYPE process_resident_memory_bytes gauge\n` +
410
+ `process_resident_memory_bytes ${mem.rss}\n`);
411
+ });
412
+ // --- Conversation tracking & export ---
413
+ this.app.get('/api/conversations/export', (req, res) => {
414
+ const sessionId = req.query.sessionId;
415
+ const format = req.query.format ?? 'json';
416
+ const messages = sessionId ? (this.conversations.get(sessionId) ?? []) : Array.from(this.conversations.values()).flat();
417
+ if (format === 'markdown') {
418
+ const md = messages.map(m => `**${m.role}** (${new Date(m.timestamp).toISOString()}):\n${m.content}`).join('\n\n---\n\n');
419
+ res.type('text/markdown').send(md);
420
+ }
421
+ else if (format === 'csv') {
422
+ const header = 'id,role,content,timestamp\n';
423
+ const rows = messages.map(m => `"${m.id}","${m.role}","${m.content.replace(/"/g, '""')}",${m.timestamp}`).join('\n');
424
+ res.type('text/csv').send(header + rows);
425
+ }
426
+ else {
427
+ res.json({ sessionId: sessionId ?? 'all', messages, count: messages.length });
428
+ }
429
+ });
430
+ // --- Document Upload ---
431
+ this.app.post('/api/documents/upload', async (req, res) => {
432
+ try {
433
+ const { content, filename, mimeType } = req.body;
434
+ if (!content || !filename) {
435
+ res.status(400).json({ error: 'content and filename are required' });
436
+ return;
437
+ }
438
+ const kb = new knowledge_1.KnowledgeBase('.');
439
+ const result = await kb.addText(content, filename);
440
+ this.stats.knowledgeFiles++;
441
+ res.json({ ok: true, filename, chunks: result.chunks, chars: content.length });
442
+ }
443
+ catch (err) {
444
+ res.status(500).json({ error: err instanceof Error ? err.message : 'Upload failed' });
445
+ }
446
+ });
447
+ // --- Agent Templates Gallery ---
448
+ this.app.get('/api/templates', (_req, res) => {
449
+ res.json({ templates: AGENT_TEMPLATES });
450
+ });
451
+ this.app.get('/templates', (_req, res) => {
452
+ res.type('html').send(TEMPLATES_HTML);
453
+ });
293
454
  // Legacy endpoint
294
455
  this.app.post('/chat', async (req, res) => {
295
456
  if (!this.handler) {
@@ -0,0 +1,13 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ export interface AuthConfig {
3
+ apiKeys: string[];
4
+ sessionIsolation?: boolean;
5
+ }
6
+ export interface AuthSession {
7
+ apiKey: string;
8
+ userId: string;
9
+ createdAt: number;
10
+ }
11
+ export declare function createAuthMiddleware(config: AuthConfig): (req: Request, res: Response, next: NextFunction) => void;
12
+ export declare function getActiveSessions(): AuthSession[];
13
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthMiddleware = createAuthMiddleware;
4
+ exports.getActiveSessions = getActiveSessions;
5
+ const sessions = new Map();
6
+ function createAuthMiddleware(config) {
7
+ return (req, res, next) => {
8
+ // Skip auth for non-API routes and health/metrics
9
+ if (!req.path.startsWith('/api/') || req.path === '/api/health' || req.path === '/api/metrics') {
10
+ next();
11
+ return;
12
+ }
13
+ const apiKey = req.headers['x-api-key']
14
+ ?? req.headers['authorization']?.replace(/^Bearer\s+/i, '')
15
+ ?? req.query.apiKey;
16
+ if (!apiKey || !config.apiKeys.includes(apiKey)) {
17
+ res.status(401).json({ error: 'Unauthorized. Provide a valid API key via X-API-Key header, Bearer token, or ?apiKey query.' });
18
+ return;
19
+ }
20
+ // Derive userId from API key for session isolation
21
+ const userId = `user_${hashKey(apiKey)}`;
22
+ if (!sessions.has(apiKey)) {
23
+ sessions.set(apiKey, { apiKey, userId, createdAt: Date.now() });
24
+ }
25
+ // Attach user info to request
26
+ req.userId = userId;
27
+ req.sessionPrefix = config.sessionIsolation ? `${userId}:` : '';
28
+ next();
29
+ };
30
+ }
31
+ function hashKey(key) {
32
+ let h = 0;
33
+ for (let i = 0; i < key.length; i++) {
34
+ h = ((h << 5) - h + key.charCodeAt(i)) | 0;
35
+ }
36
+ return Math.abs(h).toString(36);
37
+ }
38
+ function getActiveSessions() {
39
+ return Array.from(sessions.values());
40
+ }
41
+ //# sourceMappingURL=auth.js.map
package/dist/index.d.ts CHANGED
@@ -47,4 +47,13 @@ export { deployToHermes } from './deploy/hermes';
47
47
  export type { HermesDeployOptions, HermesDeployResult } from './deploy/hermes';
48
48
  export { publishAgent, installAgent } from './marketplace';
49
49
  export type { AgentManifest, PublishOptions, InstallOptions } from './marketplace';
50
+ export { createAuthMiddleware, getActiveSessions } from './core/auth';
51
+ export type { AuthConfig, AuthSession } from './core/auth';
52
+ export { HttpSkill } from './skills/http';
53
+ export { WebhookTriggerSkill } from './skills/webhook-trigger';
54
+ export type { WebhookTarget } from './skills/webhook-trigger';
55
+ export { SchedulerSkill } from './skills/scheduler';
56
+ export type { ScheduledTask } from './skills/scheduler';
57
+ export { DocumentSkill } from './skills/document';
58
+ export type { DocumentChunk } from './skills/document';
50
59
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.installAgent = exports.publishAgent = exports.deployToHermes = exports.KnowledgeBase = exports.addMessages = exports.detectLocale = exports.getLocale = exports.setLocale = exports.t = exports.LazyLoader = exports.RequestBatcher = exports.ConnectionPool = exports.VersionManager = exports.WebhookChannel = exports.VoiceChannel = exports.HITLManager = exports.AgentRegistry = exports.WorkflowEngine = exports.Analytics = exports.Sandbox = exports.PluginManager = exports.createMCPTool = exports.MCPToolRegistry = exports.Room = exports.SUPPORTED_PROVIDERS = exports.createProvider = exports.MRGConfigReader = exports.ValueTracker = exports.TrustManager = exports.DeepBrainMemoryStore = exports.InMemoryStore = exports.SkillRegistry = exports.BaseSkill = exports.WebSocketChannel = exports.TelegramChannel = exports.WebChannel = exports.BaseChannel = exports.OADSchema = exports.validateOAD = exports.loadOAD = exports.Logger = exports.truncateOutput = exports.AgentRuntime = exports.BaseAgent = void 0;
3
+ exports.DocumentSkill = exports.SchedulerSkill = exports.WebhookTriggerSkill = exports.HttpSkill = exports.getActiveSessions = exports.createAuthMiddleware = exports.installAgent = exports.publishAgent = exports.deployToHermes = exports.KnowledgeBase = exports.addMessages = exports.detectLocale = exports.getLocale = exports.setLocale = exports.t = exports.LazyLoader = exports.RequestBatcher = exports.ConnectionPool = exports.VersionManager = exports.WebhookChannel = exports.VoiceChannel = exports.HITLManager = exports.AgentRegistry = exports.WorkflowEngine = exports.Analytics = exports.Sandbox = exports.PluginManager = exports.createMCPTool = exports.MCPToolRegistry = exports.Room = exports.SUPPORTED_PROVIDERS = exports.createProvider = exports.MRGConfigReader = exports.ValueTracker = exports.TrustManager = exports.DeepBrainMemoryStore = exports.InMemoryStore = exports.SkillRegistry = exports.BaseSkill = exports.WebSocketChannel = exports.TelegramChannel = exports.WebChannel = exports.BaseChannel = exports.OADSchema = exports.validateOAD = exports.loadOAD = exports.Logger = exports.truncateOutput = exports.AgentRuntime = exports.BaseAgent = void 0;
4
4
  // OPC Agent — Open Agent Framework
5
5
  var agent_1 = require("./core/agent");
6
6
  Object.defineProperty(exports, "BaseAgent", { enumerable: true, get: function () { return agent_1.BaseAgent; } });
@@ -82,4 +82,16 @@ Object.defineProperty(exports, "deployToHermes", { enumerable: true, get: functi
82
82
  var marketplace_1 = require("./marketplace");
83
83
  Object.defineProperty(exports, "publishAgent", { enumerable: true, get: function () { return marketplace_1.publishAgent; } });
84
84
  Object.defineProperty(exports, "installAgent", { enumerable: true, get: function () { return marketplace_1.installAgent; } });
85
+ // v0.7.0 modules
86
+ var auth_1 = require("./core/auth");
87
+ Object.defineProperty(exports, "createAuthMiddleware", { enumerable: true, get: function () { return auth_1.createAuthMiddleware; } });
88
+ Object.defineProperty(exports, "getActiveSessions", { enumerable: true, get: function () { return auth_1.getActiveSessions; } });
89
+ var http_1 = require("./skills/http");
90
+ Object.defineProperty(exports, "HttpSkill", { enumerable: true, get: function () { return http_1.HttpSkill; } });
91
+ var webhook_trigger_1 = require("./skills/webhook-trigger");
92
+ Object.defineProperty(exports, "WebhookTriggerSkill", { enumerable: true, get: function () { return webhook_trigger_1.WebhookTriggerSkill; } });
93
+ var scheduler_1 = require("./skills/scheduler");
94
+ Object.defineProperty(exports, "SchedulerSkill", { enumerable: true, get: function () { return scheduler_1.SchedulerSkill; } });
95
+ var document_1 = require("./skills/document");
96
+ Object.defineProperty(exports, "DocumentSkill", { enumerable: true, get: function () { return document_1.DocumentSkill; } });
85
97
  //# sourceMappingURL=index.js.map
@@ -77,6 +77,19 @@ export declare const HITLSchema: z.ZodObject<{
77
77
  defaultTimeoutMs?: number | undefined;
78
78
  defaultAction?: "approve" | "deny" | undefined;
79
79
  }>;
80
+ export declare const AuthSchema: z.ZodObject<{
81
+ enabled: z.ZodDefault<z.ZodBoolean>;
82
+ apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
83
+ sessionIsolation: z.ZodDefault<z.ZodBoolean>;
84
+ }, "strip", z.ZodTypeAny, {
85
+ enabled: boolean;
86
+ apiKeys: string[];
87
+ sessionIsolation: boolean;
88
+ }, {
89
+ enabled?: boolean | undefined;
90
+ apiKeys?: string[] | undefined;
91
+ sessionIsolation?: boolean | undefined;
92
+ }>;
80
93
  export declare const ChannelSchema: z.ZodObject<{
81
94
  type: z.ZodEnum<["web", "websocket", "telegram", "cli", "voice", "webhook"]>;
82
95
  port: z.ZodOptional<z.ZodNumber>;
@@ -453,6 +466,19 @@ export declare const SpecSchema: z.ZodObject<{
453
466
  defaultTimeoutMs?: number | undefined;
454
467
  defaultAction?: "approve" | "deny" | undefined;
455
468
  }>>;
469
+ auth: z.ZodOptional<z.ZodObject<{
470
+ enabled: z.ZodDefault<z.ZodBoolean>;
471
+ apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
472
+ sessionIsolation: z.ZodDefault<z.ZodBoolean>;
473
+ }, "strip", z.ZodTypeAny, {
474
+ enabled: boolean;
475
+ apiKeys: string[];
476
+ sessionIsolation: boolean;
477
+ }, {
478
+ enabled?: boolean | undefined;
479
+ apiKeys?: string[] | undefined;
480
+ sessionIsolation?: boolean | undefined;
481
+ }>>;
456
482
  }, "strip", z.ZodTypeAny, {
457
483
  model: string;
458
484
  skills: {
@@ -469,6 +495,11 @@ export declare const SpecSchema: z.ZodObject<{
469
495
  enabled: boolean;
470
496
  chunkSize?: number | undefined;
471
497
  };
498
+ auth?: {
499
+ enabled: boolean;
500
+ apiKeys: string[];
501
+ sessionIsolation: boolean;
502
+ } | undefined;
472
503
  voice?: {
473
504
  enabled: boolean;
474
505
  sttProvider?: string | undefined;
@@ -522,6 +553,11 @@ export declare const SpecSchema: z.ZodObject<{
522
553
  defaultAction: "approve" | "deny";
523
554
  } | undefined;
524
555
  }, {
556
+ auth?: {
557
+ enabled?: boolean | undefined;
558
+ apiKeys?: string[] | undefined;
559
+ sessionIsolation?: boolean | undefined;
560
+ } | undefined;
525
561
  voice?: {
526
562
  enabled?: boolean | undefined;
527
563
  sttProvider?: string | undefined;
@@ -830,6 +866,19 @@ export declare const OADSchema: z.ZodObject<{
830
866
  defaultTimeoutMs?: number | undefined;
831
867
  defaultAction?: "approve" | "deny" | undefined;
832
868
  }>>;
869
+ auth: z.ZodOptional<z.ZodObject<{
870
+ enabled: z.ZodDefault<z.ZodBoolean>;
871
+ apiKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
872
+ sessionIsolation: z.ZodDefault<z.ZodBoolean>;
873
+ }, "strip", z.ZodTypeAny, {
874
+ enabled: boolean;
875
+ apiKeys: string[];
876
+ sessionIsolation: boolean;
877
+ }, {
878
+ enabled?: boolean | undefined;
879
+ apiKeys?: string[] | undefined;
880
+ sessionIsolation?: boolean | undefined;
881
+ }>>;
833
882
  }, "strip", z.ZodTypeAny, {
834
883
  model: string;
835
884
  skills: {
@@ -846,6 +895,11 @@ export declare const OADSchema: z.ZodObject<{
846
895
  enabled: boolean;
847
896
  chunkSize?: number | undefined;
848
897
  };
898
+ auth?: {
899
+ enabled: boolean;
900
+ apiKeys: string[];
901
+ sessionIsolation: boolean;
902
+ } | undefined;
849
903
  voice?: {
850
904
  enabled: boolean;
851
905
  sttProvider?: string | undefined;
@@ -899,6 +953,11 @@ export declare const OADSchema: z.ZodObject<{
899
953
  defaultAction: "approve" | "deny";
900
954
  } | undefined;
901
955
  }, {
956
+ auth?: {
957
+ enabled?: boolean | undefined;
958
+ apiKeys?: string[] | undefined;
959
+ sessionIsolation?: boolean | undefined;
960
+ } | undefined;
902
961
  voice?: {
903
962
  enabled?: boolean | undefined;
904
963
  sttProvider?: string | undefined;
@@ -999,6 +1058,11 @@ export declare const OADSchema: z.ZodObject<{
999
1058
  enabled: boolean;
1000
1059
  chunkSize?: number | undefined;
1001
1060
  };
1061
+ auth?: {
1062
+ enabled: boolean;
1063
+ apiKeys: string[];
1064
+ sessionIsolation: boolean;
1065
+ } | undefined;
1002
1066
  voice?: {
1003
1067
  enabled: boolean;
1004
1068
  sttProvider?: string | undefined;
@@ -1069,6 +1133,11 @@ export declare const OADSchema: z.ZodObject<{
1069
1133
  } | undefined;
1070
1134
  };
1071
1135
  spec: {
1136
+ auth?: {
1137
+ enabled?: boolean | undefined;
1138
+ apiKeys?: string[] | undefined;
1139
+ sessionIsolation?: boolean | undefined;
1140
+ } | undefined;
1072
1141
  voice?: {
1073
1142
  enabled?: boolean | undefined;
1074
1143
  sttProvider?: string | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OADSchema = exports.SpecSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
3
+ exports.OADSchema = exports.SpecSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.AuthSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  // ─── OAD Schema v1 ───────────────────────────────────────────
6
6
  exports.SkillRefSchema = zod_1.z.object({
@@ -43,6 +43,11 @@ exports.HITLSchema = zod_1.z.object({
43
43
  defaultTimeoutMs: zod_1.z.number().default(60000),
44
44
  defaultAction: zod_1.z.enum(['approve', 'deny']).default('deny'),
45
45
  });
46
+ exports.AuthSchema = zod_1.z.object({
47
+ enabled: zod_1.z.boolean().default(false),
48
+ apiKeys: zod_1.z.array(zod_1.z.string()).default([]),
49
+ sessionIsolation: zod_1.z.boolean().default(true),
50
+ });
46
51
  exports.ChannelSchema = zod_1.z.object({
47
52
  type: zod_1.z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook']),
48
53
  port: zod_1.z.number().optional(),
@@ -109,6 +114,7 @@ exports.SpecSchema = zod_1.z.object({
109
114
  voice: exports.VoiceSchema.optional(),
110
115
  webhook: exports.WebhookSchema.optional(),
111
116
  hitl: exports.HITLSchema.optional(),
117
+ auth: exports.AuthSchema.optional(),
112
118
  });
113
119
  exports.OADSchema = zod_1.z.object({
114
120
  apiVersion: zod_1.z.literal('opc/v1'),
@@ -0,0 +1,27 @@
1
+ import { BaseSkill } from './base';
2
+ import type { AgentContext, Message, SkillResult } from '../core/types';
3
+ export interface DocumentChunk {
4
+ content: string;
5
+ metadata: {
6
+ filename: string;
7
+ mimeType: string;
8
+ chunkIndex: number;
9
+ totalChunks: number;
10
+ };
11
+ }
12
+ export declare class DocumentSkill extends BaseSkill {
13
+ name: string;
14
+ description: string;
15
+ private knowledgeBase;
16
+ constructor(kbPath?: string);
17
+ execute(context: AgentContext, message: Message): Promise<SkillResult>;
18
+ extractText(content: string, mimeType: string): string;
19
+ chunk(text: string, size?: number, overlap?: number): DocumentChunk[];
20
+ private guessMime;
21
+ /** Process raw text content directly (for API uploads) */
22
+ processText(content: string, filename: string): Promise<{
23
+ chunks: number;
24
+ chars: number;
25
+ }>;
26
+ }
27
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DocumentSkill = void 0;
4
+ const base_1 = require("./base");
5
+ const knowledge_1 = require("../core/knowledge");
6
+ class DocumentSkill extends base_1.BaseSkill {
7
+ name = 'document';
8
+ description = 'Process uploaded documents (PDF, TXT, MD, DOCX). Chunks content and adds to knowledge base.';
9
+ knowledgeBase;
10
+ constructor(kbPath = '.') {
11
+ super();
12
+ this.knowledgeBase = new knowledge_1.KnowledgeBase(kbPath);
13
+ }
14
+ async execute(context, message) {
15
+ // Check if message has document attachment metadata
16
+ const meta = message.metadata;
17
+ if (!meta?.document)
18
+ return this.noMatch();
19
+ const { content, filename, mimeType } = meta.document;
20
+ try {
21
+ const text = this.extractText(content, mimeType ?? this.guessMime(filename));
22
+ const chunks = this.chunk(text, 1000, 100);
23
+ const result = await this.knowledgeBase.addText(chunks.map(c => c.content).join('\n\n---\n\n'), filename);
24
+ return this.match(`📄 Processed "${filename}": ${chunks.length} chunks, ${text.length} chars → added to knowledge base (${result.chunks} KB entries)`);
25
+ }
26
+ catch (err) {
27
+ return this.match(`Document processing error: ${err instanceof Error ? err.message : String(err)}`);
28
+ }
29
+ }
30
+ extractText(content, mimeType) {
31
+ // For plain text formats, content is already text
32
+ if (mimeType.includes('text/') || mimeType.includes('markdown')) {
33
+ return content;
34
+ }
35
+ // For other formats, assume base64-encoded or pre-extracted text
36
+ // In a real implementation, you'd use pdf-parse, mammoth, etc.
37
+ return content;
38
+ }
39
+ chunk(text, size = 1000, overlap = 100) {
40
+ const chunks = [];
41
+ let start = 0;
42
+ while (start < text.length) {
43
+ const end = Math.min(start + size, text.length);
44
+ chunks.push({
45
+ content: text.slice(start, end),
46
+ metadata: {
47
+ filename: '',
48
+ mimeType: '',
49
+ chunkIndex: chunks.length,
50
+ totalChunks: 0, // filled after
51
+ },
52
+ });
53
+ start = end - overlap;
54
+ if (start >= text.length)
55
+ break;
56
+ }
57
+ // Fill totalChunks
58
+ for (const c of chunks)
59
+ c.metadata.totalChunks = chunks.length;
60
+ return chunks;
61
+ }
62
+ guessMime(filename) {
63
+ const ext = filename.split('.').pop()?.toLowerCase();
64
+ switch (ext) {
65
+ case 'pdf': return 'application/pdf';
66
+ case 'txt': return 'text/plain';
67
+ case 'md': return 'text/markdown';
68
+ case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
69
+ default: return 'text/plain';
70
+ }
71
+ }
72
+ /** Process raw text content directly (for API uploads) */
73
+ async processText(content, filename) {
74
+ const chunks = this.chunk(content);
75
+ const result = await this.knowledgeBase.addText(content, filename);
76
+ return { chunks: chunks.length, chars: content.length };
77
+ }
78
+ }
79
+ exports.DocumentSkill = DocumentSkill;
80
+ //# sourceMappingURL=document.js.map
@@ -0,0 +1,8 @@
1
+ import { BaseSkill } from './base';
2
+ import type { AgentContext, Message, SkillResult } from '../core/types';
3
+ export declare class HttpSkill extends BaseSkill {
4
+ name: string;
5
+ description: string;
6
+ execute(context: AgentContext, message: Message): Promise<SkillResult>;
7
+ }
8
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpSkill = void 0;
4
+ const base_1 = require("./base");
5
+ class HttpSkill extends base_1.BaseSkill {
6
+ name = 'http';
7
+ description = 'Make HTTP requests to external APIs. Usage: http GET|POST|PUT|DELETE <url> [body]';
8
+ async execute(context, message) {
9
+ const text = message.content.trim();
10
+ const match = text.match(/^http\s+(GET|POST|PUT|PATCH|DELETE)\s+(\S+)(?:\s+(.+))?$/is);
11
+ if (!match)
12
+ return this.noMatch();
13
+ const [, method, url, bodyStr] = match;
14
+ try {
15
+ const opts = {
16
+ method: method.toUpperCase(),
17
+ headers: { 'Content-Type': 'application/json', 'User-Agent': 'OPC-Agent/0.7.0' },
18
+ };
19
+ if (bodyStr && ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase())) {
20
+ opts.body = bodyStr;
21
+ }
22
+ const res = await fetch(url, opts);
23
+ const contentType = res.headers.get('content-type') ?? '';
24
+ const body = contentType.includes('json') ? JSON.stringify(await res.json(), null, 2) : await res.text();
25
+ const truncated = body.length > 4000 ? body.slice(0, 4000) + '\n...[truncated]' : body;
26
+ return this.match(`HTTP ${res.status} ${res.statusText}\n\n${truncated}`);
27
+ }
28
+ catch (err) {
29
+ return this.match(`HTTP Error: ${err instanceof Error ? err.message : String(err)}`);
30
+ }
31
+ }
32
+ }
33
+ exports.HttpSkill = HttpSkill;
34
+ //# sourceMappingURL=http.js.map