@baobox/sdk 0.1.1 → 0.2.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 +34 -7
- package/dist/index.d.ts +122 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +616 -102
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +274 -39
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +1 -1
- package/package.json +23 -6
package/dist/index.js
CHANGED
|
@@ -1,53 +1,121 @@
|
|
|
1
|
-
// @baobox/sdk — thin HTTP client for the BaoBox runtime.
|
|
2
|
-
// No business logic here — everything smart lives server-side. This file
|
|
3
|
-
// is ~300 lines on purpose; if it grows past ~500, something that belongs
|
|
4
|
-
// in the runtime has leaked out.
|
|
5
1
|
import { BaoBoxError } from "./errors.js";
|
|
6
2
|
export { BaoBoxError } from "./errors.js";
|
|
7
3
|
export class BaoBoxClient {
|
|
8
4
|
endpoint;
|
|
9
5
|
apiKey;
|
|
6
|
+
adminSecret;
|
|
10
7
|
fetch;
|
|
11
8
|
timeoutMs;
|
|
12
|
-
|
|
13
|
-
// call sites read as `bb.admin.skills.upsert(...)` rather than a flat
|
|
14
|
-
// `bb.upsertSkill(...)`. Matches Tech Arch §4.2.
|
|
9
|
+
health;
|
|
15
10
|
admin;
|
|
16
11
|
sessions;
|
|
12
|
+
skills;
|
|
13
|
+
tools;
|
|
14
|
+
eval;
|
|
17
15
|
events;
|
|
18
16
|
constructor(opts) {
|
|
19
17
|
if (!opts.endpoint)
|
|
20
18
|
throw new Error("BaoBoxClient: endpoint required");
|
|
21
|
-
if (!opts.apiKey)
|
|
22
|
-
throw new Error("BaoBoxClient: apiKey required");
|
|
19
|
+
if (!opts.apiKey && !opts.adminSecret) {
|
|
20
|
+
throw new Error("BaoBoxClient: apiKey or adminSecret required");
|
|
21
|
+
}
|
|
23
22
|
this.endpoint = opts.endpoint.replace(/\/+$/, "");
|
|
24
|
-
this.apiKey = opts.apiKey;
|
|
25
|
-
this.
|
|
23
|
+
this.apiKey = opts.apiKey ?? null;
|
|
24
|
+
this.adminSecret = opts.adminSecret ?? null;
|
|
25
|
+
const rawFetch = opts.fetch ?? globalThis.fetch;
|
|
26
|
+
this.fetch = rawFetch.bind(globalThis);
|
|
26
27
|
this.timeoutMs = opts.timeoutMs ?? 30_000;
|
|
28
|
+
this.health = {
|
|
29
|
+
get: () => this.getHealth(),
|
|
30
|
+
};
|
|
27
31
|
this.admin = {
|
|
32
|
+
keys: {
|
|
33
|
+
list: () => this.listApiKeys(),
|
|
34
|
+
create: (req) => this.createApiKey(req),
|
|
35
|
+
delete: (id) => this.deleteApiKey(id),
|
|
36
|
+
},
|
|
37
|
+
stats: {
|
|
38
|
+
get: (req) => this.getAdminStats(req),
|
|
39
|
+
},
|
|
40
|
+
logs: {
|
|
41
|
+
list: (req) => this.listAdminLogs(req),
|
|
42
|
+
},
|
|
43
|
+
tasks: {
|
|
44
|
+
list: () => this.listScheduledTasks(),
|
|
45
|
+
create: (req) => this.createScheduledTask(req),
|
|
46
|
+
update: (id, req) => this.updateScheduledTask(id, req),
|
|
47
|
+
delete: (id) => this.deleteScheduledTask(id),
|
|
48
|
+
},
|
|
28
49
|
skills: {
|
|
29
|
-
upsert: (req) => this.
|
|
50
|
+
upsert: (req) => this.saveSkill(req),
|
|
30
51
|
},
|
|
31
52
|
tools: {
|
|
32
|
-
upsert: (req) => this.
|
|
53
|
+
upsert: (req) => this.createTool(req),
|
|
33
54
|
},
|
|
34
55
|
};
|
|
35
56
|
this.sessions = {
|
|
36
57
|
create: (req) => this.createSession(req),
|
|
58
|
+
get: (id) => this.getSession(id),
|
|
37
59
|
messages: (id) => this.listMessages(id),
|
|
60
|
+
timeline: (id) => this.getSessionTimeline(id),
|
|
61
|
+
delete: (id) => this.deleteSession(id),
|
|
62
|
+
};
|
|
63
|
+
this.skills = {
|
|
64
|
+
list: () => this.listSkills(),
|
|
65
|
+
get: (id) => this.getSkill(id),
|
|
66
|
+
create: (req) => this.createSkill(req),
|
|
67
|
+
update: (id, req) => this.updateSkill(id, req),
|
|
68
|
+
save: (req) => this.saveSkill(req),
|
|
69
|
+
import: (req) => this.importSkill(req),
|
|
70
|
+
delete: (id) => this.deleteSkill(id),
|
|
71
|
+
files: {
|
|
72
|
+
list: (id) => this.listSkillFiles(id),
|
|
73
|
+
get: (id, path) => this.getSkillFile(id, path),
|
|
74
|
+
set: (id, path, req) => this.setSkillFile(id, path, req),
|
|
75
|
+
delete: (id, path) => this.deleteSkillFile(id, path),
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
this.tools = {
|
|
79
|
+
list: () => this.listTools(),
|
|
80
|
+
get: (id) => this.getTool(id),
|
|
81
|
+
create: (req) => this.createTool(req),
|
|
82
|
+
delete: (id) => this.deleteTool(id),
|
|
83
|
+
skills: {
|
|
84
|
+
list: (skillId) => this.listSkillTools(skillId),
|
|
85
|
+
attach: (skillId, toolId) => this.attachToolToSkill(skillId, toolId),
|
|
86
|
+
detach: (skillId, toolId) => this.detachToolFromSkill(skillId, toolId),
|
|
87
|
+
},
|
|
88
|
+
secrets: {
|
|
89
|
+
list: (skillId) => this.listSkillSecrets(skillId),
|
|
90
|
+
set: (skillId, req) => this.setSkillSecret(skillId, req),
|
|
91
|
+
delete: (skillId, key) => this.deleteSkillSecret(skillId, key),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
this.eval = {
|
|
95
|
+
tests: {
|
|
96
|
+
list: (skillId) => this.listEvalTests(skillId),
|
|
97
|
+
create: (skillId, req) => this.createEvalTest(skillId, req),
|
|
98
|
+
delete: (skillId, testId) => this.deleteEvalTest(skillId, testId),
|
|
99
|
+
},
|
|
100
|
+
run: (req) => this.runEval(req),
|
|
101
|
+
runs: {
|
|
102
|
+
get: (runId) => this.getEvalRun(runId),
|
|
103
|
+
},
|
|
104
|
+
stats: (req) => this.getEvalStats(req),
|
|
105
|
+
failures: (req) => this.listEvalFailures(req),
|
|
106
|
+
compare: (req) => this.compareEvalVersions(req),
|
|
38
107
|
};
|
|
39
108
|
this.events = {
|
|
40
109
|
list: (req) => this.listEvents(req),
|
|
41
110
|
};
|
|
42
111
|
}
|
|
43
|
-
// --- Chat (core) ---
|
|
44
112
|
async chat(req) {
|
|
45
|
-
const body = await this.
|
|
113
|
+
const body = await this.requestApi("POST", "/api/v1/chat", compactObject({
|
|
46
114
|
skill_id: req.skillId,
|
|
47
115
|
message: req.message,
|
|
48
116
|
session_id: req.sessionId,
|
|
49
117
|
metadata: req.metadata,
|
|
50
|
-
});
|
|
118
|
+
}));
|
|
51
119
|
return {
|
|
52
120
|
response: body.data.response,
|
|
53
121
|
usage: {
|
|
@@ -58,97 +126,302 @@ export class BaoBoxClient {
|
|
|
58
126
|
meta: body.meta,
|
|
59
127
|
};
|
|
60
128
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const body = await this.request("POST", "/api/v1/sessions", { skill_id: req.skillId });
|
|
129
|
+
async getHealth() {
|
|
130
|
+
const body = await this.requestNoAuth("GET", "/api/v1/health");
|
|
64
131
|
return {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
createdAt: body.data.created_at,
|
|
69
|
-
updatedAt: body.data.updated_at,
|
|
132
|
+
status: body.data.status,
|
|
133
|
+
version: body.data.version,
|
|
134
|
+
meta: body.meta,
|
|
70
135
|
};
|
|
71
136
|
}
|
|
137
|
+
async createSession(req = {}) {
|
|
138
|
+
const body = await this.requestAdmin("POST", "/api/v1/sessions", compactObject({ skill_id: req.skillId }));
|
|
139
|
+
return mapSession(body.data);
|
|
140
|
+
}
|
|
141
|
+
async getSession(sessionId) {
|
|
142
|
+
const body = await this.requestAdmin("GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
143
|
+
return mapSession(body.data);
|
|
144
|
+
}
|
|
72
145
|
async listMessages(sessionId) {
|
|
73
|
-
const body = await this.
|
|
74
|
-
return body.data.map(
|
|
75
|
-
id: m.id,
|
|
76
|
-
sessionId: m.session_id,
|
|
77
|
-
role: m.role,
|
|
78
|
-
content: m.content,
|
|
79
|
-
tokenCount: m.token_count,
|
|
80
|
-
createdAt: m.created_at,
|
|
81
|
-
}));
|
|
146
|
+
const body = await this.requestAdmin("GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`);
|
|
147
|
+
return body.data.map(mapSessionMessage);
|
|
82
148
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const body = await this.request("POST", "/api/v1/admin/skills", {
|
|
86
|
-
id: req.id,
|
|
87
|
-
name: req.name,
|
|
88
|
-
description: req.description,
|
|
89
|
-
system_prompt: req.systemPrompt,
|
|
90
|
-
model: req.model,
|
|
91
|
-
temperature: req.temperature,
|
|
92
|
-
max_tokens: req.maxTokens,
|
|
93
|
-
tools: req.tools,
|
|
94
|
-
});
|
|
149
|
+
async getSessionTimeline(sessionId) {
|
|
150
|
+
const body = await this.requestAdmin("GET", `/api/v1/sessions/${encodeURIComponent(sessionId)}/timeline`);
|
|
95
151
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
description: body.data.description,
|
|
99
|
-
systemPrompt: body.data.system_prompt,
|
|
100
|
-
model: body.data.model,
|
|
101
|
-
temperature: body.data.temperature,
|
|
102
|
-
maxTokens: body.data.max_tokens,
|
|
103
|
-
tenantId: body.data.tenant_id,
|
|
104
|
-
createdAt: body.data.created_at,
|
|
105
|
-
updatedAt: body.data.updated_at,
|
|
152
|
+
sessionId: body.data.session_id,
|
|
153
|
+
events: body.data.events.map(mapEvent),
|
|
106
154
|
};
|
|
107
155
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
156
|
+
async deleteSession(sessionId) {
|
|
157
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/sessions/${encodeURIComponent(sessionId)}`);
|
|
158
|
+
return body.data;
|
|
159
|
+
}
|
|
160
|
+
async listSkills() {
|
|
161
|
+
const body = await this.requestAdmin("GET", "/api/v1/skills");
|
|
162
|
+
return body.data.map(mapSkill);
|
|
163
|
+
}
|
|
164
|
+
async getSkill(skillId) {
|
|
165
|
+
const body = await this.requestAdmin("GET", `/api/v1/skills/${encodeURIComponent(skillId)}`);
|
|
166
|
+
return mapSkillWithFiles(body.data);
|
|
167
|
+
}
|
|
168
|
+
async createSkill(req) {
|
|
169
|
+
const body = await this.requestAdmin("POST", "/api/v1/skills", buildSkillWriteBody(req));
|
|
170
|
+
const skill = mapSkill(body.data);
|
|
171
|
+
if (req.tools)
|
|
172
|
+
await this.syncSkillTools(skill.id, req.tools);
|
|
173
|
+
return skill;
|
|
174
|
+
}
|
|
175
|
+
async updateSkill(skillId, req) {
|
|
176
|
+
const writeBody = buildSkillWriteBody(req);
|
|
177
|
+
const hasFieldUpdates = Object.keys(writeBody).length > 0;
|
|
178
|
+
const skill = hasFieldUpdates
|
|
179
|
+
? mapSkill((await this.requestAdmin("PUT", `/api/v1/skills/${encodeURIComponent(skillId)}`, writeBody)).data)
|
|
180
|
+
: skillWithoutFiles(await this.getSkill(skillId));
|
|
181
|
+
if (req.tools)
|
|
182
|
+
await this.syncSkillTools(skillId, req.tools);
|
|
183
|
+
return skill;
|
|
184
|
+
}
|
|
185
|
+
async saveSkill(req) {
|
|
186
|
+
return req.id ? this.updateSkill(req.id, req) : this.createSkill(req);
|
|
187
|
+
}
|
|
188
|
+
async importSkill(req) {
|
|
189
|
+
const body = await this.requestAdmin("POST", "/api/v1/skills/import", {
|
|
190
|
+
url: req.url,
|
|
191
|
+
name: req.name,
|
|
192
|
+
});
|
|
193
|
+
return mapSkill(body.data);
|
|
194
|
+
}
|
|
195
|
+
async deleteSkill(skillId) {
|
|
196
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/skills/${encodeURIComponent(skillId)}`);
|
|
197
|
+
return body.data;
|
|
198
|
+
}
|
|
199
|
+
async listSkillFiles(skillId) {
|
|
200
|
+
const body = await this.requestAdmin("GET", `/api/v1/skills/${encodeURIComponent(skillId)}/files`);
|
|
201
|
+
return body.data.map(mapSkillFileSummary);
|
|
202
|
+
}
|
|
203
|
+
async getSkillFile(skillId, path) {
|
|
204
|
+
const body = await this.requestAdmin("GET", `/api/v1/skills/${encodeURIComponent(skillId)}/files/${encodePath(path)}`);
|
|
205
|
+
return mapSkillFile(body.data);
|
|
206
|
+
}
|
|
207
|
+
async setSkillFile(skillId, path, req) {
|
|
208
|
+
const body = await this.requestAdmin("PUT", `/api/v1/skills/${encodeURIComponent(skillId)}/files/${encodePath(path)}`, { content: req.content });
|
|
209
|
+
return body.data;
|
|
210
|
+
}
|
|
211
|
+
async deleteSkillFile(skillId, path) {
|
|
212
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/skills/${encodeURIComponent(skillId)}/files/${encodePath(path)}`);
|
|
213
|
+
return body.data;
|
|
214
|
+
}
|
|
215
|
+
async listTools() {
|
|
216
|
+
const body = await this.requestAdmin("GET", "/api/v1/tools");
|
|
217
|
+
return body.data.map(mapTool);
|
|
218
|
+
}
|
|
219
|
+
async getTool(toolId) {
|
|
220
|
+
const body = await this.requestAdmin("GET", `/api/v1/tools/${encodeURIComponent(toolId)}`);
|
|
221
|
+
return mapTool(body.data);
|
|
222
|
+
}
|
|
223
|
+
async createTool(req) {
|
|
224
|
+
const body = await this.requestAdmin("POST", "/api/v1/tools", {
|
|
111
225
|
name: req.name,
|
|
112
226
|
description: req.description,
|
|
113
227
|
input_schema: req.inputSchema,
|
|
114
228
|
handler_type: req.handlerType,
|
|
115
229
|
handler_config: req.handlerConfig,
|
|
116
230
|
});
|
|
231
|
+
return mapTool(body.data);
|
|
232
|
+
}
|
|
233
|
+
async deleteTool(toolId) {
|
|
234
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/tools/${encodeURIComponent(toolId)}`);
|
|
235
|
+
return body.data;
|
|
236
|
+
}
|
|
237
|
+
async listSkillTools(skillId) {
|
|
238
|
+
const body = await this.requestAdmin("GET", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/tools`);
|
|
239
|
+
return body.data.map(mapTool);
|
|
240
|
+
}
|
|
241
|
+
async attachToolToSkill(skillId, toolId) {
|
|
242
|
+
const body = await this.requestAdmin("POST", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/tools/${encodeURIComponent(toolId)}`);
|
|
243
|
+
return body.data;
|
|
244
|
+
}
|
|
245
|
+
async detachToolFromSkill(skillId, toolId) {
|
|
246
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/tools/${encodeURIComponent(toolId)}`);
|
|
247
|
+
return body.data;
|
|
248
|
+
}
|
|
249
|
+
async listSkillSecrets(skillId) {
|
|
250
|
+
const body = await this.requestAdmin("GET", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/secrets`);
|
|
251
|
+
return body.data.map(mapSkillSecretSummary);
|
|
252
|
+
}
|
|
253
|
+
async setSkillSecret(skillId, req) {
|
|
254
|
+
const body = await this.requestAdmin("PUT", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/secrets`, { key: req.key, value: req.value });
|
|
255
|
+
return body.data;
|
|
256
|
+
}
|
|
257
|
+
async deleteSkillSecret(skillId, key) {
|
|
258
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/tools/skills/${encodeURIComponent(skillId)}/secrets/${encodeURIComponent(key)}`);
|
|
259
|
+
return body.data;
|
|
260
|
+
}
|
|
261
|
+
async listApiKeys() {
|
|
262
|
+
const body = await this.requestAdmin("GET", "/api/v1/admin/keys");
|
|
263
|
+
return body.data.map(mapApiKey);
|
|
264
|
+
}
|
|
265
|
+
async createApiKey(req) {
|
|
266
|
+
const body = await this.requestAdmin("POST", "/api/v1/admin/keys", compactObject({
|
|
267
|
+
name: req.name,
|
|
268
|
+
permissions: req.permissions,
|
|
269
|
+
rate_limit: req.rateLimit,
|
|
270
|
+
expires_at: req.expiresAt,
|
|
271
|
+
}));
|
|
117
272
|
return {
|
|
118
273
|
id: body.data.id,
|
|
274
|
+
key: body.data.key,
|
|
119
275
|
name: body.data.name,
|
|
120
|
-
|
|
121
|
-
inputSchema: body.data.input_schema,
|
|
122
|
-
handlerType: body.data.handler_type,
|
|
123
|
-
handlerConfig: body.data.handler_config,
|
|
124
|
-
createdAt: body.data.created_at,
|
|
276
|
+
tenantId: body.data.tenant_id,
|
|
125
277
|
};
|
|
126
278
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
279
|
+
async deleteApiKey(id) {
|
|
280
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/admin/keys/${encodeURIComponent(id)}`);
|
|
281
|
+
return body.data;
|
|
282
|
+
}
|
|
283
|
+
async getAdminStats(req) {
|
|
284
|
+
const body = await this.requestAdmin("GET", appendQuery("/api/v1/admin/stats", { since: req?.since }));
|
|
285
|
+
return body.data;
|
|
286
|
+
}
|
|
287
|
+
async listAdminLogs(req) {
|
|
288
|
+
const body = await this.requestAdmin("GET", appendQuery("/api/v1/admin/logs", {
|
|
289
|
+
limit: req?.limit !== undefined ? String(req.limit) : undefined,
|
|
290
|
+
}));
|
|
291
|
+
return body.data;
|
|
292
|
+
}
|
|
293
|
+
async listScheduledTasks() {
|
|
294
|
+
const body = await this.requestAdmin("GET", "/api/v1/admin/tasks");
|
|
295
|
+
return body.data.map(mapScheduledTask);
|
|
296
|
+
}
|
|
297
|
+
async createScheduledTask(req) {
|
|
298
|
+
const body = await this.requestAdmin("POST", "/api/v1/admin/tasks", compactObject({
|
|
299
|
+
name: req.name,
|
|
300
|
+
skill_id: req.skillId,
|
|
301
|
+
prompt: req.prompt,
|
|
302
|
+
telegram_chat_id: req.telegramChatId,
|
|
303
|
+
schedule: req.schedule,
|
|
304
|
+
}));
|
|
305
|
+
return body.data ? mapScheduledTask(body.data) : null;
|
|
306
|
+
}
|
|
307
|
+
async updateScheduledTask(id, req) {
|
|
308
|
+
const body = await this.requestAdmin("PATCH", `/api/v1/admin/tasks/${encodeURIComponent(id)}`, compactObject({
|
|
309
|
+
enabled: req.enabled,
|
|
310
|
+
schedule: req.schedule,
|
|
311
|
+
prompt: req.prompt,
|
|
312
|
+
}));
|
|
313
|
+
return body.data ? mapScheduledTask(body.data) : null;
|
|
314
|
+
}
|
|
315
|
+
async deleteScheduledTask(id) {
|
|
316
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/admin/tasks/${encodeURIComponent(id)}`);
|
|
317
|
+
return body.data;
|
|
318
|
+
}
|
|
319
|
+
async listEvalTests(skillId) {
|
|
320
|
+
const body = await this.requestAdmin("GET", `/api/v1/eval/skills/${encodeURIComponent(skillId)}/tests`);
|
|
321
|
+
return body.data.map(mapEvalCase);
|
|
322
|
+
}
|
|
323
|
+
async createEvalTest(skillId, req) {
|
|
324
|
+
const body = await this.requestAdmin("POST", `/api/v1/eval/skills/${encodeURIComponent(skillId)}/tests`, compactObject({
|
|
325
|
+
name: req.name,
|
|
326
|
+
input: req.input,
|
|
327
|
+
expected_behavior: req.expectedBehavior,
|
|
328
|
+
dimensions: req.dimensions,
|
|
329
|
+
passing_threshold: req.passingThreshold,
|
|
330
|
+
}));
|
|
331
|
+
return mapEvalCase(body.data);
|
|
332
|
+
}
|
|
333
|
+
async deleteEvalTest(skillId, testId) {
|
|
334
|
+
const body = await this.requestAdmin("DELETE", `/api/v1/eval/skills/${encodeURIComponent(skillId)}/tests/${encodeURIComponent(testId)}`);
|
|
335
|
+
return body.data;
|
|
336
|
+
}
|
|
337
|
+
async runEval(req) {
|
|
338
|
+
const body = await this.requestAdmin("POST", "/api/v1/eval/run", compactObject({
|
|
339
|
+
skill_id: req.skillId,
|
|
340
|
+
test_case_ids: req.testCaseIds,
|
|
341
|
+
prompt_version: req.promptVersion,
|
|
342
|
+
}));
|
|
343
|
+
return mapEvalRunExecution(body.data);
|
|
344
|
+
}
|
|
345
|
+
async getEvalRun(runId) {
|
|
346
|
+
const body = await this.requestAdmin("GET", `/api/v1/eval/runs/${encodeURIComponent(runId)}`);
|
|
347
|
+
return {
|
|
348
|
+
...mapEvalRun(body.data),
|
|
349
|
+
results: body.data.results.map(mapEvalRunResult),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
async getEvalStats(req) {
|
|
353
|
+
const body = await this.requestAdmin("GET", appendQuery("/api/v1/eval/stats", {
|
|
354
|
+
skill_id: req?.skillId,
|
|
355
|
+
since: req?.since,
|
|
356
|
+
}));
|
|
357
|
+
return {
|
|
358
|
+
skillId: body.data.skill_id,
|
|
359
|
+
period: body.data.period,
|
|
360
|
+
summary: body.data.summary
|
|
361
|
+
? {
|
|
362
|
+
total: body.data.summary.total,
|
|
363
|
+
avgScore: body.data.summary.avg_score,
|
|
364
|
+
distribution: body.data.summary.distribution,
|
|
365
|
+
}
|
|
366
|
+
: null,
|
|
367
|
+
trend: body.data.trend,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async listEvalFailures(req) {
|
|
371
|
+
const body = await this.requestAdmin("GET", appendQuery("/api/v1/eval/failures", {
|
|
372
|
+
skill_id: req?.skillId,
|
|
373
|
+
threshold: req?.threshold !== undefined ? String(req.threshold) : undefined,
|
|
374
|
+
limit: req?.limit !== undefined ? String(req.limit) : undefined,
|
|
146
375
|
}));
|
|
376
|
+
return body.data;
|
|
377
|
+
}
|
|
378
|
+
async compareEvalVersions(req) {
|
|
379
|
+
const body = await this.requestAdmin("GET", appendQuery("/api/v1/eval/compare", {
|
|
380
|
+
skill_id: req.skillId,
|
|
381
|
+
a: req.a,
|
|
382
|
+
b: req.b,
|
|
383
|
+
}));
|
|
384
|
+
return {
|
|
385
|
+
skillId: body.data.skill_id,
|
|
386
|
+
versionA: body.data.version_a,
|
|
387
|
+
versionB: body.data.version_b,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
async listEvents(req) {
|
|
391
|
+
const timeline = await this.getSessionTimeline(req.sessionId);
|
|
392
|
+
return timeline.events;
|
|
393
|
+
}
|
|
394
|
+
async syncSkillTools(skillId, desiredToolIds) {
|
|
395
|
+
const desired = new Set(desiredToolIds);
|
|
396
|
+
const current = await this.listSkillTools(skillId);
|
|
397
|
+
const currentIds = new Set(current.map((tool) => tool.id));
|
|
398
|
+
for (const toolId of currentIds) {
|
|
399
|
+
if (!desired.has(toolId)) {
|
|
400
|
+
await this.detachToolFromSkill(skillId, toolId);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
for (const toolId of desired) {
|
|
404
|
+
if (!currentIds.has(toolId)) {
|
|
405
|
+
await this.attachToolToSkill(skillId, toolId);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async requestNoAuth(method, path, body) {
|
|
410
|
+
return this.request(method, path, "none", body);
|
|
147
411
|
}
|
|
148
|
-
|
|
149
|
-
|
|
412
|
+
async requestApi(method, path, body) {
|
|
413
|
+
return this.request(method, path, "apiKey", body);
|
|
414
|
+
}
|
|
415
|
+
async requestAdmin(method, path, body) {
|
|
416
|
+
return this.request(method, path, "adminSecret", body);
|
|
417
|
+
}
|
|
418
|
+
async request(method, path, authMode, body) {
|
|
150
419
|
const url = `${this.endpoint}${path}`;
|
|
151
420
|
const controller = new AbortController();
|
|
421
|
+
const headers = {
|
|
422
|
+
...this.getAuthHeaders(authMode),
|
|
423
|
+
...(body !== undefined ? { "content-type": "application/json" } : {}),
|
|
424
|
+
};
|
|
152
425
|
const timer = this.timeoutMs > 0
|
|
153
426
|
? setTimeout(() => controller.abort(), this.timeoutMs)
|
|
154
427
|
: null;
|
|
@@ -156,10 +429,7 @@ export class BaoBoxClient {
|
|
|
156
429
|
try {
|
|
157
430
|
res = await this.fetch(url, {
|
|
158
431
|
method,
|
|
159
|
-
headers
|
|
160
|
-
authorization: `Bearer ${this.apiKey}`,
|
|
161
|
-
...(body !== undefined ? { "content-type": "application/json" } : {}),
|
|
162
|
-
},
|
|
432
|
+
headers,
|
|
163
433
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
164
434
|
signal: controller.signal,
|
|
165
435
|
});
|
|
@@ -177,27 +447,271 @@ export class BaoBoxClient {
|
|
|
177
447
|
const text = await res.text();
|
|
178
448
|
const parsed = text.length ? safeParseJson(text) : {};
|
|
179
449
|
if (!res.ok) {
|
|
180
|
-
const errObj = parsed
|
|
450
|
+
const errObj = parsed
|
|
451
|
+
.error;
|
|
181
452
|
throw new BaoBoxError(res.status, errObj?.code ?? "HTTP_ERROR", errObj?.message ?? res.statusText, errObj?.request_id ?? null, parsed);
|
|
182
453
|
}
|
|
183
454
|
const envelope = parsed;
|
|
184
455
|
return {
|
|
185
456
|
data: envelope.data,
|
|
186
|
-
meta: envelope.metadata
|
|
187
|
-
? {
|
|
188
|
-
requestId: envelope.metadata.request_id,
|
|
189
|
-
latencyMs: envelope.metadata.latency_ms,
|
|
190
|
-
model: envelope.metadata.model,
|
|
191
|
-
trace: envelope.metadata.trace?.map((t) => ({
|
|
192
|
-
toolName: t.tool_name,
|
|
193
|
-
input: t.input,
|
|
194
|
-
output: t.output,
|
|
195
|
-
latencyMs: t.latency_ms,
|
|
196
|
-
})),
|
|
197
|
-
}
|
|
198
|
-
: { requestId: "", latencyMs: 0 },
|
|
457
|
+
meta: mapResponseMeta(envelope.metadata),
|
|
199
458
|
};
|
|
200
459
|
}
|
|
460
|
+
getAuthHeaders(authMode) {
|
|
461
|
+
if (authMode === "none")
|
|
462
|
+
return {};
|
|
463
|
+
if (authMode === "apiKey") {
|
|
464
|
+
if (!this.apiKey) {
|
|
465
|
+
throw new Error("BaoBoxClient: apiKey required for chat methods");
|
|
466
|
+
}
|
|
467
|
+
return { authorization: `Bearer ${this.apiKey}` };
|
|
468
|
+
}
|
|
469
|
+
if (!this.adminSecret) {
|
|
470
|
+
throw new Error("BaoBoxClient: adminSecret required for admin methods");
|
|
471
|
+
}
|
|
472
|
+
return { authorization: `Bearer ${this.adminSecret}` };
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function mapResponseMeta(metadata) {
|
|
476
|
+
if (!metadata)
|
|
477
|
+
return { requestId: "", latencyMs: 0 };
|
|
478
|
+
return {
|
|
479
|
+
requestId: metadata.request_id,
|
|
480
|
+
latencyMs: metadata.latency_ms,
|
|
481
|
+
model: metadata.model,
|
|
482
|
+
trace: metadata.trace?.map((trace) => ({
|
|
483
|
+
toolName: trace.tool_name,
|
|
484
|
+
input: trace.input,
|
|
485
|
+
output: trace.output,
|
|
486
|
+
latencyMs: trace.latency_ms,
|
|
487
|
+
})),
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
function mapSession(raw) {
|
|
491
|
+
return {
|
|
492
|
+
id: raw.id,
|
|
493
|
+
skillId: raw.skill_id,
|
|
494
|
+
tenantId: raw.tenant_id,
|
|
495
|
+
createdAt: raw.created_at,
|
|
496
|
+
updatedAt: raw.updated_at,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
function mapSessionMessage(raw) {
|
|
500
|
+
return {
|
|
501
|
+
id: raw.id,
|
|
502
|
+
sessionId: raw.session_id,
|
|
503
|
+
role: raw.role,
|
|
504
|
+
content: raw.content,
|
|
505
|
+
tokenCount: raw.token_count,
|
|
506
|
+
createdAt: raw.created_at,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
function mapEvent(raw) {
|
|
510
|
+
return {
|
|
511
|
+
id: raw.id,
|
|
512
|
+
sessionId: raw.session_id,
|
|
513
|
+
requestId: raw.request_id,
|
|
514
|
+
eventType: raw.event_type,
|
|
515
|
+
content: raw.content,
|
|
516
|
+
metadata: toJsonObject(raw.metadata),
|
|
517
|
+
tokenCount: raw.token_count,
|
|
518
|
+
latencyMs: raw.latency_ms,
|
|
519
|
+
parentEventId: raw.parent_event_id,
|
|
520
|
+
createdAt: raw.created_at,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function mapSkill(raw) {
|
|
524
|
+
return {
|
|
525
|
+
id: raw.id,
|
|
526
|
+
name: raw.name,
|
|
527
|
+
description: raw.description,
|
|
528
|
+
systemPrompt: raw.system_prompt,
|
|
529
|
+
model: raw.model,
|
|
530
|
+
temperature: raw.temperature,
|
|
531
|
+
maxTokens: raw.max_tokens,
|
|
532
|
+
sourceUrl: raw.source_url,
|
|
533
|
+
tenantId: raw.tenant_id,
|
|
534
|
+
createdAt: raw.created_at,
|
|
535
|
+
updatedAt: raw.updated_at,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function mapSkillWithFiles(raw) {
|
|
539
|
+
return {
|
|
540
|
+
...mapSkill(raw),
|
|
541
|
+
files: raw.files.map((file) => ({
|
|
542
|
+
path: file.path,
|
|
543
|
+
size: file.size,
|
|
544
|
+
})),
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function skillWithoutFiles(skill) {
|
|
548
|
+
const { files: _files, ...rest } = skill;
|
|
549
|
+
return rest;
|
|
550
|
+
}
|
|
551
|
+
function mapSkillFileSummary(raw) {
|
|
552
|
+
return {
|
|
553
|
+
path: raw.path,
|
|
554
|
+
size: raw.size,
|
|
555
|
+
updatedAt: raw.updated_at,
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function mapSkillFile(raw) {
|
|
559
|
+
return {
|
|
560
|
+
id: raw.id,
|
|
561
|
+
skillId: raw.skill_id,
|
|
562
|
+
path: raw.path,
|
|
563
|
+
content: raw.content,
|
|
564
|
+
createdAt: raw.created_at,
|
|
565
|
+
updatedAt: raw.updated_at,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function mapTool(raw) {
|
|
569
|
+
return {
|
|
570
|
+
id: raw.id,
|
|
571
|
+
name: raw.name,
|
|
572
|
+
description: raw.description,
|
|
573
|
+
inputSchema: raw.input_schema,
|
|
574
|
+
handlerType: raw.handler_type,
|
|
575
|
+
handlerConfig: raw.handler_config,
|
|
576
|
+
createdAt: raw.created_at,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
function mapSkillSecretSummary(raw) {
|
|
580
|
+
return {
|
|
581
|
+
id: raw.id,
|
|
582
|
+
key: raw.key,
|
|
583
|
+
createdAt: raw.created_at,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function mapApiKey(raw) {
|
|
587
|
+
return {
|
|
588
|
+
apiKeyId: raw.apiKeyId,
|
|
589
|
+
name: raw.name,
|
|
590
|
+
permissions: raw.permissions,
|
|
591
|
+
rateLimit: raw.rateLimit,
|
|
592
|
+
tenantId: raw.tenantId,
|
|
593
|
+
createdAt: raw.createdAt,
|
|
594
|
+
expiresAt: raw.expiresAt,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function mapScheduledTask(raw) {
|
|
598
|
+
return {
|
|
599
|
+
id: raw.id,
|
|
600
|
+
name: raw.name,
|
|
601
|
+
skillId: raw.skill_id,
|
|
602
|
+
prompt: raw.prompt,
|
|
603
|
+
telegramChatId: raw.telegram_chat_id,
|
|
604
|
+
schedule: raw.schedule,
|
|
605
|
+
enabled: raw.enabled,
|
|
606
|
+
createdAt: raw.created_at,
|
|
607
|
+
lastRunAt: raw.last_run_at,
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function mapEvalCase(raw) {
|
|
611
|
+
return {
|
|
612
|
+
id: raw.id,
|
|
613
|
+
skillId: raw.skill_id,
|
|
614
|
+
name: raw.name,
|
|
615
|
+
input: raw.input,
|
|
616
|
+
expectedBehavior: raw.expected_behavior,
|
|
617
|
+
dimensions: raw.dimensions,
|
|
618
|
+
passingThreshold: raw.passing_threshold,
|
|
619
|
+
createdAt: raw.created_at,
|
|
620
|
+
updatedAt: raw.updated_at,
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function mapEvalRunExecution(raw) {
|
|
624
|
+
return {
|
|
625
|
+
runId: raw.run_id,
|
|
626
|
+
status: raw.status,
|
|
627
|
+
totalCases: raw.total_cases,
|
|
628
|
+
passed: raw.passed,
|
|
629
|
+
failed: raw.failed,
|
|
630
|
+
avgScore: raw.avg_score,
|
|
631
|
+
results: raw.results.map(mapEvalRunResultSummary),
|
|
632
|
+
durationMs: raw.duration_ms,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function mapEvalRunResultSummary(raw) {
|
|
636
|
+
return {
|
|
637
|
+
testCaseId: raw.test_case_id,
|
|
638
|
+
status: raw.status,
|
|
639
|
+
score: raw.score,
|
|
640
|
+
scores: raw.scores,
|
|
641
|
+
response: raw.response,
|
|
642
|
+
reasoning: raw.reasoning,
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function mapEvalRun(raw) {
|
|
646
|
+
return {
|
|
647
|
+
id: raw.id,
|
|
648
|
+
skillId: raw.skill_id,
|
|
649
|
+
promptVersion: raw.prompt_version,
|
|
650
|
+
status: raw.status,
|
|
651
|
+
totalCases: raw.total_cases,
|
|
652
|
+
passed: raw.passed,
|
|
653
|
+
failed: raw.failed,
|
|
654
|
+
avgScore: raw.avg_score,
|
|
655
|
+
metadata: raw.metadata,
|
|
656
|
+
createdAt: raw.created_at,
|
|
657
|
+
completedAt: raw.completed_at,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function mapEvalRunResult(raw) {
|
|
661
|
+
return {
|
|
662
|
+
id: raw.id,
|
|
663
|
+
runId: raw.run_id,
|
|
664
|
+
testCaseId: raw.test_case_id,
|
|
665
|
+
sessionId: raw.session_id,
|
|
666
|
+
status: raw.status,
|
|
667
|
+
score: raw.score,
|
|
668
|
+
scoresJson: raw.scores_json,
|
|
669
|
+
response: raw.response,
|
|
670
|
+
reasoning: raw.reasoning,
|
|
671
|
+
latencyMs: raw.latency_ms,
|
|
672
|
+
createdAt: raw.created_at,
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function buildSkillWriteBody(req) {
|
|
676
|
+
return compactObject({
|
|
677
|
+
name: req.name,
|
|
678
|
+
description: req.description,
|
|
679
|
+
system_prompt: req.systemPrompt,
|
|
680
|
+
model: req.model,
|
|
681
|
+
temperature: req.temperature,
|
|
682
|
+
max_tokens: req.maxTokens,
|
|
683
|
+
source_url: req.sourceUrl,
|
|
684
|
+
files: req.files,
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function appendQuery(path, query) {
|
|
688
|
+
const qs = new URLSearchParams();
|
|
689
|
+
for (const [key, value] of Object.entries(query)) {
|
|
690
|
+
if (value !== undefined)
|
|
691
|
+
qs.set(key, value);
|
|
692
|
+
}
|
|
693
|
+
const suffix = qs.toString();
|
|
694
|
+
return suffix ? `${path}?${suffix}` : path;
|
|
695
|
+
}
|
|
696
|
+
function encodePath(path) {
|
|
697
|
+
return path
|
|
698
|
+
.split("/")
|
|
699
|
+
.filter((segment) => segment.length > 0)
|
|
700
|
+
.map((segment) => encodeURIComponent(segment))
|
|
701
|
+
.join("/");
|
|
702
|
+
}
|
|
703
|
+
function compactObject(obj) {
|
|
704
|
+
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
705
|
+
}
|
|
706
|
+
function toJsonObject(input) {
|
|
707
|
+
if (typeof input === "string") {
|
|
708
|
+
const parsed = safeParseJson(input);
|
|
709
|
+
return isJsonObject(parsed) ? parsed : {};
|
|
710
|
+
}
|
|
711
|
+
return isJsonObject(input) ? input : {};
|
|
712
|
+
}
|
|
713
|
+
function isJsonObject(value) {
|
|
714
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
201
715
|
}
|
|
202
716
|
function safeParseJson(text) {
|
|
203
717
|
try {
|