@realtimex/sdk 1.4.0 → 1.4.3
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/package.json +5 -2
- package/skills/realtimex-moderator-sdk/SKILL.md +93 -0
- package/skills/realtimex-moderator-sdk/references/api-reference.md +662 -0
- package/skills/realtimex-moderator-sdk/references/known-issues.md +237 -0
- package/skills/realtimex-moderator-sdk/scripts/lib/sdk-init.js +119 -0
- package/skills/realtimex-moderator-sdk/scripts/rtx.js +492 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# Known Issues — Source-Detected
|
|
2
|
+
|
|
3
|
+
> Auto-generated by `scripts/generate-skill.mjs` · SDK **1.4.3** · 2026-03-26
|
|
4
|
+
|
|
5
|
+
Run `node scripts/generate-skill.mjs --force` after SDK source changes to refresh.
|
|
6
|
+
|
|
7
|
+
**12/12 issues confirmed in current source.**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. `sdk.webhook.triggerAgent()` sends `event: "task.trigger"` — server expects `"trigger-agent"`
|
|
12
|
+
|
|
13
|
+
**Status:** 🔴 DETECTED
|
|
14
|
+
**File:** `modules/webhook.ts`
|
|
15
|
+
**Evidence:** `Found `event: "task.trigger"` hardcoded in triggerAgent() body (line ~100)`
|
|
16
|
+
|
|
17
|
+
**Correct usage:**
|
|
18
|
+
```js
|
|
19
|
+
// ❌ WRONG — SDK sends 'task.trigger' but server enum only accepts 'trigger-agent'
|
|
20
|
+
await sdk.webhook.triggerAgent({ auto_run: true, agent_name: 'agent', ... });
|
|
21
|
+
|
|
22
|
+
// ✅ CORRECT — raw fetch with server-expected event string
|
|
23
|
+
const resp = await fetch('http://localhost:3001/webhooks/realtimex', {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
event: 'trigger-agent',
|
|
28
|
+
payload: { auto_run: true, agent_name: 'document2speech', workspace_slug: 'sdfsdf', prompt: '...' },
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. `sdk.task.start/complete/fail` take positional `(taskUuid, ...)` — NOT `{ task_uuid }` object
|
|
36
|
+
|
|
37
|
+
**Status:** 🔴 DETECTED
|
|
38
|
+
**File:** `modules/task.ts`
|
|
39
|
+
**Evidence:** `start(taskUuid: string, ...) | complete(taskUuid, result, ...) | fail(taskUuid, error: string, ...)`
|
|
40
|
+
|
|
41
|
+
**Correct usage:**
|
|
42
|
+
```js
|
|
43
|
+
// ❌ WRONG
|
|
44
|
+
await sdk.task.start({ task_uuid: uuid });
|
|
45
|
+
await sdk.task.complete({ task_uuid: uuid, result: { out: 'done' } });
|
|
46
|
+
|
|
47
|
+
// ✅ CORRECT
|
|
48
|
+
await sdk.task.start(uuid);
|
|
49
|
+
await sdk.task.complete(uuid, { out: 'done' });
|
|
50
|
+
await sdk.task.fail(uuid, 'error message');
|
|
51
|
+
await sdk.task.start(uuid, { machineId: 'machine-01' });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 3. `sdk.activities.list()` returns `Activity[]` directly — NOT `{ activities: [...] }`
|
|
57
|
+
|
|
58
|
+
**Status:** 🔴 DETECTED
|
|
59
|
+
**File:** `modules/activities.ts`
|
|
60
|
+
**Evidence:** `Return type is Promise<Activity[]>`
|
|
61
|
+
|
|
62
|
+
**Correct usage:**
|
|
63
|
+
```js
|
|
64
|
+
// ❌ WRONG
|
|
65
|
+
const { activities } = await sdk.activities.list();
|
|
66
|
+
|
|
67
|
+
// ✅ CORRECT
|
|
68
|
+
const activities = await sdk.activities.list();
|
|
69
|
+
for (const a of activities) { ... }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 4. `sdk.llm.chat()` response is `res.response?.content` — NOT `choices[0].message.content`
|
|
75
|
+
|
|
76
|
+
**Status:** 🔴 DETECTED
|
|
77
|
+
**File:** `modules/llm.ts`
|
|
78
|
+
**Evidence:** `ChatResponse shape: { success, response?: { content, model, metrics } }`
|
|
79
|
+
|
|
80
|
+
**Correct usage:**
|
|
81
|
+
```js
|
|
82
|
+
// ❌ WRONG (OpenAI style)
|
|
83
|
+
console.log(res.choices[0].message.content);
|
|
84
|
+
|
|
85
|
+
// ✅ CORRECT
|
|
86
|
+
const res = await sdk.llm.chat([{ role: 'user', content: 'Hello' }]);
|
|
87
|
+
console.log(res.response?.content);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 5. `sdk.llm.chatStream()` yields `chunk.textResponse` — NOT `choices[0].delta.content`
|
|
93
|
+
|
|
94
|
+
**Status:** 🔴 DETECTED
|
|
95
|
+
**File:** `modules/llm.ts`
|
|
96
|
+
**Evidence:** `StreamChunk interface has textResponse?: string`
|
|
97
|
+
|
|
98
|
+
**Correct usage:**
|
|
99
|
+
```js
|
|
100
|
+
// ❌ WRONG
|
|
101
|
+
chunk.choices?.[0]?.delta?.content
|
|
102
|
+
|
|
103
|
+
// ✅ CORRECT
|
|
104
|
+
for await (const chunk of sdk.llm.chatStream(messages)) {
|
|
105
|
+
if (chunk.textResponse) process.stdout.write(chunk.textResponse);
|
|
106
|
+
if (chunk.close) break;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 6. `sdk.llm.embedAndStore()` takes `{ texts: string[], documentId?, workspaceId?, ... }` — NOT `(text, options)`
|
|
113
|
+
|
|
114
|
+
**Status:** 🔴 DETECTED
|
|
115
|
+
**File:** `modules/llm.ts`
|
|
116
|
+
**Evidence:** `embedAndStore(params: { texts: string[]; documentId?; workspaceId?; ... })`
|
|
117
|
+
|
|
118
|
+
**Correct usage:**
|
|
119
|
+
```js
|
|
120
|
+
// ❌ WRONG
|
|
121
|
+
await sdk.llm.embedAndStore('text content', { id: 'doc-1' });
|
|
122
|
+
|
|
123
|
+
// ✅ CORRECT
|
|
124
|
+
await sdk.llm.embedAndStore({ texts: ['chunk 1', 'chunk 2'], documentId: 'doc-1', workspaceId: 'ws-123' });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 7. `sdk.llm.vectors.query()` takes a raw `number[]` embedding — NOT a text string
|
|
130
|
+
|
|
131
|
+
**Status:** 🔴 DETECTED
|
|
132
|
+
**File:** `modules/llm.ts`
|
|
133
|
+
**Evidence:** `query(vector: number[], options?)`
|
|
134
|
+
|
|
135
|
+
**Correct usage:**
|
|
136
|
+
```js
|
|
137
|
+
// ❌ WRONG
|
|
138
|
+
await sdk.llm.vectors.query('search text');
|
|
139
|
+
|
|
140
|
+
// ✅ CORRECT — raw vector
|
|
141
|
+
const { embeddings } = await sdk.llm.embed('search text');
|
|
142
|
+
await sdk.llm.vectors.query(embeddings[0], { topK: 5 });
|
|
143
|
+
|
|
144
|
+
// ✅ EASIER — high-level helper
|
|
145
|
+
const hits = await sdk.llm.search('search text', { topK: 5 });
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 8. `sdk.llm.vectors.delete()` requires `{ deleteAll: true }` — delete-by-ID not supported
|
|
151
|
+
|
|
152
|
+
**Status:** 🔴 DETECTED
|
|
153
|
+
**File:** `modules/llm.ts`
|
|
154
|
+
**Evidence:** `VectorDeleteOptions: { workspaceId?, deleteAll: true } (literal true)`
|
|
155
|
+
|
|
156
|
+
**Correct usage:**
|
|
157
|
+
```js
|
|
158
|
+
// ❌ WRONG
|
|
159
|
+
await sdk.llm.vectors.delete(['id-1', 'id-2']);
|
|
160
|
+
|
|
161
|
+
// ✅ CORRECT
|
|
162
|
+
await sdk.llm.vectors.delete({ deleteAll: true, workspaceId: 'ws-123' });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 9. `sdk.mcp.getServers()` takes a plain string — NOT `{ provider: "all" }`
|
|
168
|
+
|
|
169
|
+
**Status:** 🔴 DETECTED
|
|
170
|
+
**File:** `modules/mcp.ts`
|
|
171
|
+
**Evidence:** `getServers(provider: 'local' | 'remote' | 'all' = 'all')`
|
|
172
|
+
|
|
173
|
+
**Correct usage:**
|
|
174
|
+
```js
|
|
175
|
+
// ❌ WRONG
|
|
176
|
+
await sdk.mcp.getServers({ provider: 'all' });
|
|
177
|
+
|
|
178
|
+
// ✅ CORRECT
|
|
179
|
+
await sdk.mcp.getServers('all');
|
|
180
|
+
await sdk.mcp.getServers(); // defaults to 'all'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 10. `getAgents/getWorkspaces/getThreads/getTask` live on `sdk.api.*` — NOT directly on `sdk.*`
|
|
186
|
+
|
|
187
|
+
**Status:** 🔴 DETECTED
|
|
188
|
+
**File:** `index.ts`
|
|
189
|
+
**Evidence:** `this.api = new ApiModule(...) — separate sub-module in constructor`
|
|
190
|
+
|
|
191
|
+
**Correct usage:**
|
|
192
|
+
```js
|
|
193
|
+
// ❌ WRONG
|
|
194
|
+
await sdk.getAgents();
|
|
195
|
+
await sdk.getWorkspaces();
|
|
196
|
+
|
|
197
|
+
// ✅ CORRECT
|
|
198
|
+
await sdk.api.getAgents();
|
|
199
|
+
await sdk.api.getWorkspaces();
|
|
200
|
+
await sdk.api.getThreads('workspace-slug');
|
|
201
|
+
await sdk.api.getTask('task-uuid');
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 11. ACP `streamChat` uses named SSE (`event:` line); `text_delta.data.type === "thinking"` = internal reasoning
|
|
207
|
+
|
|
208
|
+
**Status:** 🔴 DETECTED
|
|
209
|
+
**File:** `modules/acpAgent.ts`
|
|
210
|
+
**Evidence:** `Uses parseNamedSSEStream() — reads both event: and data: SSE lines per spec`
|
|
211
|
+
|
|
212
|
+
**Correct usage:**
|
|
213
|
+
```js
|
|
214
|
+
for await (const event of sdk.acpAgent.streamChat(key, message)) {
|
|
215
|
+
if (event.type === 'text_delta') {
|
|
216
|
+
if (event.data.type !== 'thinking') { // skip internal reasoning
|
|
217
|
+
process.stdout.write(String(event.data.text ?? ''));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 12. ACP sessions stall without `approvalPolicy: "approve-all"` when tools need permission
|
|
226
|
+
|
|
227
|
+
**Status:** 🔴 DETECTED
|
|
228
|
+
**File:** `modules/acpAgent.ts`
|
|
229
|
+
**Evidence:** `AcpSessionOptions.approvalPolicy?: 'approve-all' | 'approve-reads' | 'deny-all'`
|
|
230
|
+
|
|
231
|
+
**Correct usage:**
|
|
232
|
+
```js
|
|
233
|
+
// ✅ Always set for autonomous scripts
|
|
234
|
+
await sdk.acpAgent.createSession({ agent_id: 'qwen', approvalPolicy: 'approve-all', cwd });
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* sdk-init.js — SDK initializer with automatic credential resolution
|
|
4
|
+
* AUTO-GENERATED by scripts/generate-skill.mjs — do not edit by hand.
|
|
5
|
+
*
|
|
6
|
+
* Source reference: typescript/src/index.ts (RealtimeXSDK constructor)
|
|
7
|
+
*
|
|
8
|
+
* Credential resolution priority:
|
|
9
|
+
* 1. Explicit override passed to initSDK({ apiKey } or { appId })
|
|
10
|
+
* 2. REALTIMEX_API_KEY / REALTIMEX_AI_API_KEY in <envDir>/.env
|
|
11
|
+
* 3. RTX_API_KEY / REALTIMEX_API_KEY / REALTIMEX_AI_API_KEY in process.env
|
|
12
|
+
* 4. RTX_APP_ID in process.env (injected by RealtimeX for agents / local apps)
|
|
13
|
+
* 5. ~/.realtimex.ai/.sdk-app-id file (written by RealtimeX server on startup)
|
|
14
|
+
* 6. Interactive readline prompt (dev fallback)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
const readline = require('readline');
|
|
21
|
+
|
|
22
|
+
const ALL_PERMISSIONS = [
|
|
23
|
+
'api.agents', 'api.workspaces', 'api.threads', 'api.task',
|
|
24
|
+
'webhook.trigger', 'activities.read', 'activities.write',
|
|
25
|
+
'llm.chat', 'llm.embed', 'llm.providers',
|
|
26
|
+
'vectors.read', 'vectors.write',
|
|
27
|
+
'tts.generate', 'mcp.servers', 'mcp.tools', 'acp.agent',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
/** Well-known file written by RealtimeX server for seamless SDK auth. */
|
|
31
|
+
const SDK_APP_ID_FILE = path.join(os.homedir(), '.realtimex.ai', '.sdk-app-id');
|
|
32
|
+
|
|
33
|
+
function parseEnvFile(filePath) {
|
|
34
|
+
const vars = {};
|
|
35
|
+
if (!fs.existsSync(filePath)) return vars;
|
|
36
|
+
for (const raw of fs.readFileSync(filePath, 'utf-8').split('\n')) {
|
|
37
|
+
const line = raw.trim();
|
|
38
|
+
if (!line || line.startsWith('#')) continue;
|
|
39
|
+
const eq = line.indexOf('=');
|
|
40
|
+
if (eq === -1) continue;
|
|
41
|
+
const key = line.slice(0, eq).trim();
|
|
42
|
+
const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, '');
|
|
43
|
+
vars[key] = val;
|
|
44
|
+
}
|
|
45
|
+
return vars;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve credentials using the full priority chain.
|
|
50
|
+
* Returns { apiKey, appId } — exactly one will be set.
|
|
51
|
+
*/
|
|
52
|
+
async function resolveCredentials({ envDir, apiKey, appId } = {}) {
|
|
53
|
+
// 1. Explicit overrides
|
|
54
|
+
if (apiKey) return { apiKey, appId: null };
|
|
55
|
+
if (appId) return { apiKey: null, appId };
|
|
56
|
+
|
|
57
|
+
// 2. .env file
|
|
58
|
+
const envVars = parseEnvFile(path.join(envDir || process.cwd(), '.env'));
|
|
59
|
+
const fromFile = envVars.REALTIMEX_API_KEY || envVars.REALTIMEX_AI_API_KEY;
|
|
60
|
+
if (fromFile) return { apiKey: fromFile, appId: null };
|
|
61
|
+
|
|
62
|
+
// 3. Process env — API key
|
|
63
|
+
const fromEnv = process.env.RTX_API_KEY || process.env.REALTIMEX_API_KEY || process.env.REALTIMEX_AI_API_KEY;
|
|
64
|
+
if (fromEnv) return { apiKey: fromEnv, appId: null };
|
|
65
|
+
|
|
66
|
+
// 4. Process env — App ID (injected by RealtimeX for agents / local apps)
|
|
67
|
+
const envAppId = process.env.RTX_APP_ID;
|
|
68
|
+
if (envAppId) return { apiKey: null, appId: envAppId };
|
|
69
|
+
|
|
70
|
+
// 5. Well-known file (written by RealtimeX server on startup)
|
|
71
|
+
try {
|
|
72
|
+
if (fs.existsSync(SDK_APP_ID_FILE)) {
|
|
73
|
+
const fileAppId = fs.readFileSync(SDK_APP_ID_FILE, 'utf-8').trim();
|
|
74
|
+
if (fileAppId) return { apiKey: null, appId: fileAppId };
|
|
75
|
+
}
|
|
76
|
+
} catch { /* ignore read errors */ }
|
|
77
|
+
|
|
78
|
+
// 6. Interactive prompt (dev fallback)
|
|
79
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
80
|
+
const answer = await new Promise((resolve) => {
|
|
81
|
+
rl.question('RealTimeX API key not found. Enter your API key: ', (ans) => {
|
|
82
|
+
rl.close();
|
|
83
|
+
resolve(ans.trim());
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
if (answer) return { apiKey: answer, appId: null };
|
|
87
|
+
|
|
88
|
+
return { apiKey: null, appId: null };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** @deprecated Use resolveCredentials() instead */
|
|
92
|
+
async function resolveApiKey(opts = {}) {
|
|
93
|
+
const { apiKey } = await resolveCredentials(opts);
|
|
94
|
+
return apiKey;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function initSDK(opts = {}) {
|
|
98
|
+
const { RealtimeXSDK } = require('@realtimex/sdk');
|
|
99
|
+
const { apiKey, appId } = await resolveCredentials(opts);
|
|
100
|
+
|
|
101
|
+
if (!apiKey && !appId) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
'No credentials found. Set REALTIMEX_API_KEY in .env, or run inside RealtimeX for automatic auth.'
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const sdk = new RealtimeXSDK({
|
|
108
|
+
realtimex: {
|
|
109
|
+
url: opts.url || 'http://localhost:3001',
|
|
110
|
+
...(apiKey ? { apiKey } : {}),
|
|
111
|
+
...(appId ? { appId } : {}),
|
|
112
|
+
},
|
|
113
|
+
permissions: opts.permissions || ALL_PERMISSIONS,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return { sdk, apiKey: apiKey || null, appId: appId || null };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = { initSDK, resolveCredentials, resolveApiKey, parseEnvFile, ALL_PERMISSIONS, SDK_APP_ID_FILE };
|