convoai 1.5.3 → 1.6.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.
Files changed (63) hide show
  1. package/README.md +36 -9
  2. package/dist/src/commands/agent/chat.js +2 -4
  3. package/dist/src/commands/agent/chat.js.map +1 -1
  4. package/dist/src/commands/agent/join.js +2 -4
  5. package/dist/src/commands/agent/join.js.map +1 -1
  6. package/dist/src/commands/dev.d.ts +2 -0
  7. package/dist/src/commands/dev.js +73 -0
  8. package/dist/src/commands/dev.js.map +1 -0
  9. package/dist/src/commands/go.js +3 -8
  10. package/dist/src/commands/go.js.map +1 -1
  11. package/dist/src/commands/init.d.ts +2 -0
  12. package/dist/src/commands/init.js +326 -0
  13. package/dist/src/commands/init.js.map +1 -0
  14. package/dist/src/commands/openclaw.js +2 -4
  15. package/dist/src/commands/openclaw.js.map +1 -1
  16. package/dist/src/commands/quickstart.js +137 -56
  17. package/dist/src/commands/quickstart.js.map +1 -1
  18. package/dist/src/index.js +11 -0
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/starters/web/server/convoai-api.d.ts +42 -0
  21. package/dist/src/starters/web/server/convoai-api.js +116 -0
  22. package/dist/src/starters/web/server/convoai-api.js.map +1 -0
  23. package/dist/src/starters/web/server/index.d.ts +1 -0
  24. package/dist/src/starters/web/server/index.js +85 -0
  25. package/dist/src/starters/web/server/index.js.map +1 -0
  26. package/dist/src/starters/web/server/routes/callback.d.ts +2 -0
  27. package/dist/src/starters/web/server/routes/callback.js +10 -0
  28. package/dist/src/starters/web/server/routes/callback.js.map +1 -0
  29. package/dist/src/starters/web/server/routes/knowledge.d.ts +2 -0
  30. package/dist/src/starters/web/server/routes/knowledge.js +15 -0
  31. package/dist/src/starters/web/server/routes/knowledge.js.map +1 -0
  32. package/dist/src/starters/web/server/routes/session.d.ts +2 -0
  33. package/dist/src/starters/web/server/routes/session.js +82 -0
  34. package/dist/src/starters/web/server/routes/session.js.map +1 -0
  35. package/dist/src/starters/web/server/routes/token.d.ts +2 -0
  36. package/dist/src/starters/web/server/routes/token.js +19 -0
  37. package/dist/src/starters/web/server/routes/token.js.map +1 -0
  38. package/dist/src/web/serve.d.ts +7 -0
  39. package/dist/src/web/serve.js +42 -0
  40. package/dist/src/web/serve.js.map +1 -0
  41. package/package.json +3 -1
  42. package/src/starters/web/.env.example +28 -0
  43. package/src/starters/web/README.md +81 -0
  44. package/src/starters/web/connectors/README.md +35 -0
  45. package/src/starters/web/frontend/app.js +352 -0
  46. package/src/starters/web/frontend/index.html +54 -0
  47. package/src/starters/web/frontend/style.css +241 -0
  48. package/src/starters/web/package.json +23 -0
  49. package/src/starters/web/python-server/.env.example +23 -0
  50. package/src/starters/web/python-server/README.md +37 -0
  51. package/src/starters/web/python-server/app.py +202 -0
  52. package/src/starters/web/python-server/requirements.txt +4 -0
  53. package/src/starters/web/python-server/token_builder.py +99 -0
  54. package/src/starters/web/server/convoai-api.ts +243 -0
  55. package/src/starters/web/server/index.ts +109 -0
  56. package/src/starters/web/server/routes/callback.ts +13 -0
  57. package/src/starters/web/server/routes/knowledge.ts +19 -0
  58. package/src/starters/web/server/routes/session.ts +122 -0
  59. package/src/starters/web/server/routes/token.ts +22 -0
  60. package/src/starters/web/server/tsconfig.json +14 -0
  61. package/src/web/chat-client.html +1 -1
  62. package/src/web/client.html +1 -1
  63. package/src/web/serve.ts +45 -0
@@ -0,0 +1,85 @@
1
+ // ConvoAI Starter — Express Server
2
+ // Serves frontend static files + Agora RTC SDK + API routes.
3
+ import 'dotenv/config';
4
+ import express from 'express';
5
+ import { readFileSync } from 'node:fs';
6
+ import { join, dirname } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { createRequire } from 'node:module';
9
+ import sessionRouter from './routes/session.js';
10
+ import tokenRouter from './routes/token.js';
11
+ import callbackRouter from './routes/callback.js';
12
+ import knowledgeRouter from './routes/knowledge.js';
13
+ import { getHistory } from './convoai-api.js';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+ const require = createRequire(import.meta.url);
17
+ const app = express();
18
+ const PORT = parseInt(process.env.PORT || '3000', 10);
19
+ // ─── Middleware ─────────────────────────────────────────────────────────────
20
+ app.use(express.json());
21
+ // ─── Agora RTC SDK from npm ────────────────────────────────────────────────
22
+ let sdkCache = null;
23
+ app.get('/agora-sdk.js', (_req, res) => {
24
+ if (!sdkCache) {
25
+ const sdkPath = require.resolve('agora-rtc-sdk-ng/AgoraRTC_N-production.js');
26
+ sdkCache = readFileSync(sdkPath);
27
+ }
28
+ res.set({
29
+ 'Content-Type': 'application/javascript; charset=utf-8',
30
+ 'Content-Length': String(sdkCache.length),
31
+ 'Cache-Control': 'public, max-age=86400',
32
+ });
33
+ res.send(sdkCache);
34
+ });
35
+ // ─── API Routes ────────────────────────────────────────────────────────────
36
+ app.use(sessionRouter);
37
+ app.use(tokenRouter);
38
+ app.use(callbackRouter);
39
+ app.use(knowledgeRouter);
40
+ app.get('/health', (_req, res) => {
41
+ res.json({ status: 'ok' });
42
+ });
43
+ // ─── History Proxy ─────────────────────────────────────────────────────────
44
+ app.get('/history', async (req, res) => {
45
+ const agentId = req.query.agentId;
46
+ if (!agentId) {
47
+ res.status(400).json({ error: 'Missing agentId query parameter' });
48
+ return;
49
+ }
50
+ try {
51
+ const appId = process.env.AGORA_APP_ID;
52
+ const customerId = process.env.AGORA_CUSTOMER_ID;
53
+ const customerSecret = process.env.AGORA_CUSTOMER_SECRET;
54
+ const region = process.env.AGORA_REGION || 'global';
55
+ const history = await getHistory(appId, agentId, customerId, customerSecret, region);
56
+ res.json({ history });
57
+ }
58
+ catch {
59
+ res.json({ history: [] });
60
+ }
61
+ });
62
+ // ─── Frontend Static Files ─────────────────────────────────────────────────
63
+ const frontendDir = join(__dirname, '..', 'frontend');
64
+ app.use(express.static(frontendDir));
65
+ // ─── Start Server ──────────────────────────────────────────────────────────
66
+ app.listen(PORT, () => {
67
+ console.log('');
68
+ console.log(` ConvoAI Starter Server running at:`);
69
+ console.log(` -> http://localhost:${PORT}`);
70
+ console.log('');
71
+ console.log(` API routes:`);
72
+ console.log(` POST /session/start Start voice conversation`);
73
+ console.log(` POST /session/stop Stop conversation`);
74
+ console.log(` GET /token Generate RTC token`);
75
+ console.log(` GET /health Health check`);
76
+ console.log('');
77
+ const required = ['AGORA_APP_ID', 'AGORA_APP_CERTIFICATE', 'AGORA_CUSTOMER_ID', 'AGORA_CUSTOMER_SECRET'];
78
+ const missing = required.filter(k => !process.env[k]);
79
+ if (missing.length > 0) {
80
+ console.log(` ⚠ Missing credentials in .env: ${missing.join(', ')}`);
81
+ console.log(` Run "convoai quickstart" to configure, or edit .env manually.`);
82
+ console.log('');
83
+ }
84
+ });
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/starters/web/server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ declare const router: any;
2
+ export default router;
@@ -0,0 +1,10 @@
1
+ // Webhook endpoint for ConvoAI Engine callbacks.
2
+ // Customize: add your webhook handling logic here.
3
+ import { Router } from 'express';
4
+ const router = Router();
5
+ router.post('/callback', (req, res) => {
6
+ console.log('[callback] Received webhook:', JSON.stringify(req.body, null, 2));
7
+ res.json({ received: true });
8
+ });
9
+ export default router;
10
+ //# sourceMappingURL=callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback.js","sourceRoot":"","sources":["../../../../../../src/starters/web/server/routes/callback.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,mDAAmD;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACpC,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const router: any;
2
+ export default router;
@@ -0,0 +1,15 @@
1
+ // Knowledge base query endpoint.
2
+ // Customize: connect your knowledge base, RAG pipeline, or vector DB here.
3
+ import { Router } from 'express';
4
+ const router = Router();
5
+ router.post('/knowledge', (req, res) => {
6
+ const { query } = req.body || {};
7
+ console.log('[knowledge] Query:', query);
8
+ // Customize: replace with your knowledge base integration
9
+ res.json({
10
+ results: [],
11
+ message: 'Knowledge base not configured. Edit server/routes/knowledge.ts to connect yours.',
12
+ });
13
+ });
14
+ export default router;
15
+ //# sourceMappingURL=knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge.js","sourceRoot":"","sources":["../../../../../../src/starters/web/server/routes/knowledge.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,2EAA2E;AAE3E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IACrC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;IAEzC,0DAA0D;IAC1D,GAAG,CAAC,IAAI,CAAC;QACP,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,kFAAkF;KAC5F,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const router: any;
2
+ export default router;
@@ -0,0 +1,82 @@
1
+ import { Router } from 'express';
2
+ import { startAgent, stopAgent } from '../convoai-api.js';
3
+ const router = Router();
4
+ // In-memory session store (single session for simplicity)
5
+ // Customize: replace with database or Redis for production
6
+ let currentSession = null;
7
+ router.post('/session/start', async (req, res) => {
8
+ try {
9
+ if (currentSession) {
10
+ res.status(409).json({ error: 'Session already active. Stop it first.' });
11
+ return;
12
+ }
13
+ const appId = process.env.AGORA_APP_ID;
14
+ const appCertificate = process.env.AGORA_APP_CERTIFICATE;
15
+ const customerId = process.env.AGORA_CUSTOMER_ID;
16
+ const customerSecret = process.env.AGORA_CUSTOMER_SECRET;
17
+ const region = process.env.AGORA_REGION || 'global';
18
+ const channel = `session-${Date.now().toString(36)}`;
19
+ const clientUid = Math.floor(Math.random() * 90000) + 10000;
20
+ const config = {
21
+ appId,
22
+ appCertificate,
23
+ customerId,
24
+ customerSecret,
25
+ region,
26
+ channel,
27
+ clientUid,
28
+ llm: {
29
+ vendor: process.env.LLM_VENDOR,
30
+ model: process.env.LLM_MODEL,
31
+ apiKey: process.env.LLM_API_KEY,
32
+ url: process.env.LLM_URL,
33
+ style: process.env.LLM_STYLE,
34
+ },
35
+ tts: {
36
+ vendor: process.env.TTS_VENDOR,
37
+ apiKey: process.env.TTS_API_KEY,
38
+ },
39
+ asr: {
40
+ vendor: process.env.ASR_VENDOR,
41
+ language: process.env.ASR_LANGUAGE,
42
+ },
43
+ };
44
+ const result = await startAgent(config);
45
+ currentSession = { agentId: result.agentId, channel: result.channel };
46
+ res.json({
47
+ appId: result.appId,
48
+ channel: result.channel,
49
+ token: result.token,
50
+ uid: result.uid,
51
+ agentId: result.agentId,
52
+ });
53
+ }
54
+ catch (err) {
55
+ const message = err instanceof Error ? err.message : 'Unknown error';
56
+ console.error('[session/start]', message);
57
+ res.status(500).json({ error: message });
58
+ }
59
+ });
60
+ router.post('/session/stop', async (req, res) => {
61
+ try {
62
+ if (!currentSession) {
63
+ res.status(404).json({ error: 'No active session' });
64
+ return;
65
+ }
66
+ const appId = process.env.AGORA_APP_ID;
67
+ const customerId = process.env.AGORA_CUSTOMER_ID;
68
+ const customerSecret = process.env.AGORA_CUSTOMER_SECRET;
69
+ const region = process.env.AGORA_REGION || 'global';
70
+ await stopAgent(appId, currentSession.agentId, customerId, customerSecret, region);
71
+ currentSession = null;
72
+ res.json({ status: 'stopped' });
73
+ }
74
+ catch (err) {
75
+ const message = err instanceof Error ? err.message : 'Unknown error';
76
+ console.error('[session/stop]', message);
77
+ currentSession = null;
78
+ res.status(500).json({ error: message });
79
+ }
80
+ });
81
+ export default router;
82
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../../../../../src/starters/web/server/routes/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAyB,MAAM,mBAAmB,CAAC;AAEjF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,0DAA0D;AAC1D,2DAA2D;AAC3D,IAAI,cAAc,GAAgD,IAAI,CAAC;AAEvE,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAC/C,IAAI,CAAC;QACH,IAAI,cAAc,EAAE,CAAC;YACnB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC1E,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;QACxC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAsB,CAAC;QAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAkB,CAAC;QAClD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAsB,CAAC;QAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC;QAEpD,MAAM,OAAO,GAAG,WAAW,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;QAE5D,MAAM,MAAM,GAAqB;YAC/B,KAAK;YACL,cAAc;YACd,UAAU;YACV,cAAc;YACd,MAAM;YACN,OAAO;YACP,SAAS;YACT,GAAG,EAAE;gBACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;gBAC/B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS;aAC7B;YACD,GAAG,EAAE;gBACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;aAChC;YACD,GAAG,EAAE;gBACH,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;gBAC9B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;aACnC;SACF,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;QACxC,cAAc,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAEtE,GAAG,CAAC,IAAI,CAAC;YACP,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QAC1C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAC9C,IAAI,CAAC;QACH,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;QACxC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAkB,CAAC;QAClD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAsB,CAAC;QAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC;QAEpD,MAAM,SAAS,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;QACnF,cAAc,GAAG,IAAI,CAAC;QAEtB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACzC,cAAc,GAAG,IAAI,CAAC;QACtB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const router: any;
2
+ export default router;
@@ -0,0 +1,19 @@
1
+ import { Router } from 'express';
2
+ import { generateToken } from '../convoai-api.js';
3
+ const router = Router();
4
+ router.get('/token', (req, res) => {
5
+ try {
6
+ const appId = process.env.AGORA_APP_ID;
7
+ const appCertificate = process.env.AGORA_APP_CERTIFICATE;
8
+ const channel = req.query.channel || `ch-${Date.now().toString(36)}`;
9
+ const uid = parseInt(req.query.uid, 10) || 0;
10
+ const token = generateToken(appId, appCertificate, channel, uid);
11
+ res.json({ token, channel, uid });
12
+ }
13
+ catch (err) {
14
+ const message = err instanceof Error ? err.message : 'Unknown error';
15
+ res.status(500).json({ error: message });
16
+ }
17
+ });
18
+ export default router;
19
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../../../../src/starters/web/server/routes/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAChC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAa,CAAC;QACxC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAsB,CAAC;QAC1D,MAAM,OAAO,GAAI,GAAG,CAAC,KAAK,CAAC,OAAkB,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACjF,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAa,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAEvD,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAEjE,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ /**
3
+ * Returns an HTTP request handler that serves:
4
+ * - `/agora-sdk.js` → Agora RTC SDK from node_modules
5
+ * - Everything else → the provided HTML string
6
+ */
7
+ export declare function createWebHandler(html: string): (req: IncomingMessage, res: ServerResponse) => void;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Shared HTTP handler that serves HTML pages + the Agora RTC SDK from npm.
3
+ * Using the npm package (agora-rtc-sdk-ng) instead of CDN ensures each
4
+ * `npm install convoai` counts as an npm download for the SDK.
5
+ */
6
+ import { readFileSync } from 'node:fs';
7
+ import { createRequire } from 'node:module';
8
+ const require = createRequire(import.meta.url);
9
+ let _sdkCache = null;
10
+ function getSdkContent() {
11
+ if (!_sdkCache) {
12
+ // Resolve the package main entry (exports "." → AgoraRTC_N-production.js)
13
+ // Using the subpath directly would throw ERR_PACKAGE_PATH_NOT_EXPORTED
14
+ const sdkPath = require.resolve('agora-rtc-sdk-ng');
15
+ _sdkCache = readFileSync(sdkPath);
16
+ }
17
+ return _sdkCache;
18
+ }
19
+ /**
20
+ * Returns an HTTP request handler that serves:
21
+ * - `/agora-sdk.js` → Agora RTC SDK from node_modules
22
+ * - Everything else → the provided HTML string
23
+ */
24
+ export function createWebHandler(html) {
25
+ return (req, res) => {
26
+ const pathname = (req.url || '/').split('?')[0];
27
+ if (pathname === '/agora-sdk.js') {
28
+ const sdk = getSdkContent();
29
+ res.writeHead(200, {
30
+ 'Content-Type': 'application/javascript; charset=utf-8',
31
+ 'Content-Length': sdk.length,
32
+ 'Cache-Control': 'public, max-age=86400',
33
+ });
34
+ res.end(sdk);
35
+ }
36
+ else {
37
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
38
+ res.end(html);
39
+ }
40
+ };
41
+ }
42
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/web/serve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC,SAAS,aAAa;IACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACpD,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAClB,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,uCAAuC;gBACvD,gBAAgB,EAAE,GAAG,CAAC,MAAM;gBAC5B,eAAe,EAAE,uBAAuB;aACzC,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACnE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convoai",
3
- "version": "1.5.3",
3
+ "version": "1.6.1",
4
4
  "description": "CLI for Agora ConvoAI Engine — start, manage, and monitor conversational AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,11 +37,13 @@
37
37
  "dist",
38
38
  "bin",
39
39
  "src/web",
40
+ "src/starters",
40
41
  "README.md",
41
42
  "LICENSE"
42
43
  ],
43
44
  "license": "MIT",
44
45
  "dependencies": {
46
+ "agora-rtc-sdk-ng": "^4.24.3",
45
47
  "agora-token": "^2.0.5",
46
48
  "axios": "^1.7.0",
47
49
  "chalk": "^5.3.0",
@@ -0,0 +1,28 @@
1
+ # Agora Credentials (from https://console.agora.io)
2
+ AGORA_APP_ID=
3
+ AGORA_APP_CERTIFICATE=
4
+ AGORA_CUSTOMER_ID=
5
+ AGORA_CUSTOMER_SECRET=
6
+
7
+ # Region: "global" or "cn"
8
+ AGORA_REGION=global
9
+
10
+ # LLM Configuration
11
+ LLM_VENDOR=openai
12
+ LLM_MODEL=gpt-4o-mini
13
+ LLM_API_KEY=
14
+ LLM_URL=
15
+ LLM_STYLE=openai
16
+
17
+ # TTS Configuration
18
+ TTS_VENDOR=microsoft
19
+ # TTS_PARAMS is a JSON string with all provider-specific params
20
+ # Examples:
21
+ # Microsoft: {"key":"...","region":"eastus","voice_name":"en-US-AndrewMultilingualNeural"}
22
+ # MiniMax: {"key":"...","group_id":"...","model":"speech-02-turbo","voice_setting":{"voice_id":"..."},"url":"wss://api.minimaxi.com/ws/v1/t2a_v2"}
23
+ # ElevenLabs: {"key":"...","base_url":"wss://api.elevenlabs.io/v1","model_id":"eleven_flash_v2_5","voice_id":"pNInz6obpgDQGcFmaJgB"}
24
+ TTS_PARAMS=
25
+
26
+ # ASR Configuration
27
+ ASR_VENDOR=ares
28
+ ASR_LANGUAGE=en-US
@@ -0,0 +1,81 @@
1
+ # ConvoAI Web Starter
2
+
3
+ A three-layer starter project for building voice AI applications with Agora ConvoAI Engine.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm install
9
+ convoai dev # or: npm run dev
10
+ ```
11
+
12
+ Open http://localhost:3000 and click **Start Conversation**.
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ frontend/ <- Your UI (HTML / JS / CSS — no build step)
18
+ server/ <- Your backend (Express + TypeScript)
19
+ python-server/ <- Alternative Python backend (FastAPI)
20
+ connectors/ <- Future: telephony, text, IoT extensions
21
+ ```
22
+
23
+ ## How to Customize
24
+
25
+ ### Change the UI
26
+ Edit files in `frontend/`:
27
+ - `index.html` — page structure
28
+ - `style.css` — colors, layout, theme
29
+ - `app.js` — interaction logic, Agora RTC handling
30
+
31
+ ### Add business logic
32
+ Edit files in `server/routes/`:
33
+ - `session.ts` — session start/stop (add auth, rate limiting, logging)
34
+ - `callback.ts` — handle ConvoAI webhooks
35
+ - `knowledge.ts` — connect your knowledge base or RAG pipeline
36
+
37
+ ### Add authentication
38
+ Edit `server/index.ts` — add Express middleware before the API routes.
39
+
40
+ ### Switch to Python
41
+ See `python-server/README.md`. Same API routes, same frontend.
42
+
43
+ ## Architecture
44
+
45
+ ```
46
+ [Your Frontend] --> [Your Server] --> [ConvoAI Engine]
47
+ HTML/JS Express/FastAPI Agora Cloud
48
+ Agora RTC SDK Token generation ASR + LLM + TTS
49
+ Voice capture Business logic Voice AI pipeline
50
+ ```
51
+
52
+ Future connectors plug in at the same server layer:
53
+ ```
54
+ [Phone / SIP] --> [Your Server] --> [ConvoAI Engine]
55
+ [IoT Device] --> [Your Server] --> [ConvoAI Engine]
56
+ [IM / Chat App] --> [Your Server] --> [ConvoAI Engine]
57
+ ```
58
+
59
+ ## From Local to Production
60
+
61
+ 1. **Local** — `npm run dev` (you are here)
62
+ 2. **Deploy server** — push `server/` to your cloud (Railway, Render, AWS, etc.)
63
+ 3. **Deploy frontend** — push `frontend/` to CDN or same server
64
+ 4. **Update .env** — swap local credentials for production ones
65
+
66
+ No code changes needed. Same architecture scales from laptop to production.
67
+
68
+ ## Environment Variables
69
+
70
+ See `.env.example` for the full list. Key variables:
71
+
72
+ | Variable | Required | Description |
73
+ |----------|----------|-------------|
74
+ | AGORA_APP_ID | Yes | From Agora Console |
75
+ | AGORA_APP_CERTIFICATE | Yes | From project settings |
76
+ | AGORA_CUSTOMER_ID | Yes | REST API credentials |
77
+ | AGORA_CUSTOMER_SECRET | Yes | REST API credentials |
78
+ | LLM_VENDOR | Yes | LLM provider (openai, anthropic, etc.) |
79
+ | LLM_API_KEY | Yes | LLM API key |
80
+ | TTS_VENDOR | Yes | TTS provider (microsoft, elevenlabs, etc.) |
81
+ | TTS_API_KEY | Yes | TTS API key |
@@ -0,0 +1,35 @@
1
+ # ConvoAI Connectors
2
+
3
+ This directory is reserved for future communication connectors.
4
+
5
+ ## Architecture
6
+
7
+ ConvoAI uses a three-layer architecture:
8
+
9
+ ```
10
+ [Connector] --> [Customer Server] --> [ConvoAI Engine]
11
+ ```
12
+
13
+ New communication capabilities extend through the Connector layer.
14
+ The Customer Server and ConvoAI Engine remain the same.
15
+
16
+ **Web is the first connector** — implemented in `frontend/`.
17
+
18
+ ## Planned Connectors
19
+
20
+ ### Telephony / SIP (Phase 2)
21
+ Inbound/outbound phone calls via SIP. Connector handles call signaling; server handles business logic.
22
+
23
+ ### Text / IM (Phase 3)
24
+ Chat platforms (Slack, WhatsApp, web chat widgets). Connector handles message transport.
25
+
26
+ ### Device / Edge (Phase 3)
27
+ IoT devices, smart speakers, embedded systems. Connector handles device communication.
28
+
29
+ ## Design Principle
30
+
31
+ Each connector only handles communication transport.
32
+ Business logic stays in the Customer Server.
33
+ AI capabilities stay in ConvoAI Engine.
34
+
35
+ Adding a new connector never requires rewriting your server or AI config.