mioku-service-ai 2.2.1 → 2.2.2
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/index.ts +32 -14
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -8,7 +8,11 @@ import type {
|
|
|
8
8
|
} from "openai/resources/chat/completions";
|
|
9
9
|
import type { AISkill, AITool, MiokuService } from "mioku";
|
|
10
10
|
import { createAIUsageStore } from "./usage/store";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
UsageTracker,
|
|
13
|
+
extractUsageTokens,
|
|
14
|
+
mergeMeasuredTokens,
|
|
15
|
+
} from "./usage/tracker";
|
|
12
16
|
import {
|
|
13
17
|
runToolLoop,
|
|
14
18
|
parseToolArguments,
|
|
@@ -68,7 +72,9 @@ class AIInstanceImpl implements AIInstance {
|
|
|
68
72
|
: [...options.messages];
|
|
69
73
|
|
|
70
74
|
// Some upstreams reject system-only requests with 400 "chat content is empty".
|
|
71
|
-
const messages: ChatCompletionMessageParam[] = composed.some(
|
|
75
|
+
const messages: ChatCompletionMessageParam[] = composed.some(
|
|
76
|
+
(m) => m.role === "user",
|
|
77
|
+
)
|
|
72
78
|
? composed
|
|
73
79
|
: [...composed, { role: "user", content: "." }];
|
|
74
80
|
|
|
@@ -94,8 +100,8 @@ class AIInstanceImpl implements AIInstance {
|
|
|
94
100
|
? [{ role: "system", content: options.prompt }, ...messages]
|
|
95
101
|
: messages;
|
|
96
102
|
|
|
97
|
-
const withUserTurn: ChatCompletionMessageParam[] = composed.some(
|
|
98
|
-
m.role === "user",
|
|
103
|
+
const withUserTurn: ChatCompletionMessageParam[] = composed.some(
|
|
104
|
+
(m) => m.role === "user",
|
|
99
105
|
)
|
|
100
106
|
? composed
|
|
101
107
|
: [...composed, { role: "user", content: "." }];
|
|
@@ -223,7 +229,7 @@ class AIInstanceImpl implements AIInstance {
|
|
|
223
229
|
tools: args.tools,
|
|
224
230
|
temperature: args.temperature,
|
|
225
231
|
...(args.max_tokens != null && {
|
|
226
|
-
|
|
232
|
+
max_tokens: args.max_tokens,
|
|
227
233
|
}),
|
|
228
234
|
});
|
|
229
235
|
|
|
@@ -285,7 +291,8 @@ class AIInstanceImpl implements AIInstance {
|
|
|
285
291
|
for await (const chunk of stream as AsyncIterable<any>) {
|
|
286
292
|
const choice = chunk?.choices?.[0];
|
|
287
293
|
const chunkUsage = extractUsageTokens(chunk);
|
|
288
|
-
if (chunkUsage)
|
|
294
|
+
if (chunkUsage)
|
|
295
|
+
streamUsage = mergeMeasuredTokens(streamUsage, chunkUsage);
|
|
289
296
|
const delta = choice?.delta;
|
|
290
297
|
if (!delta) continue;
|
|
291
298
|
|
|
@@ -301,11 +308,17 @@ class AIInstanceImpl implements AIInstance {
|
|
|
301
308
|
reasoning += delta.reasoning;
|
|
302
309
|
}
|
|
303
310
|
|
|
304
|
-
const deltaToolCalls = Array.isArray(delta.tool_calls)
|
|
311
|
+
const deltaToolCalls = Array.isArray(delta.tool_calls)
|
|
312
|
+
? delta.tool_calls
|
|
313
|
+
: [];
|
|
305
314
|
for (const item of deltaToolCalls) {
|
|
306
315
|
const index =
|
|
307
316
|
typeof item?.index === "number" && item.index >= 0 ? item.index : 0;
|
|
308
|
-
const acc = toolCallsByIndex.get(index) || {
|
|
317
|
+
const acc = toolCallsByIndex.get(index) || {
|
|
318
|
+
id: "",
|
|
319
|
+
name: "",
|
|
320
|
+
arguments: "",
|
|
321
|
+
};
|
|
309
322
|
if (typeof item?.id === "string" && item.id) acc.id = item.id;
|
|
310
323
|
if (typeof item?.function?.name === "string" && item.function.name) {
|
|
311
324
|
acc.name += item.function.name;
|
|
@@ -392,7 +405,10 @@ class AIInstanceImpl implements AIInstance {
|
|
|
392
405
|
}
|
|
393
406
|
return (messages as MultimodalMessage[]).map((msg) => {
|
|
394
407
|
if (typeof msg.content === "string") {
|
|
395
|
-
return {
|
|
408
|
+
return {
|
|
409
|
+
role: msg.role,
|
|
410
|
+
content: msg.content,
|
|
411
|
+
} as ChatCompletionMessageParam;
|
|
396
412
|
}
|
|
397
413
|
return {
|
|
398
414
|
role: msg.role,
|
|
@@ -409,7 +425,8 @@ class AIInstanceImpl implements AIInstance {
|
|
|
409
425
|
}
|
|
410
426
|
|
|
411
427
|
registerPrompt(name: string, prompt: string): boolean {
|
|
412
|
-
if (this.prompts.has(name))
|
|
428
|
+
if (this.prompts.has(name))
|
|
429
|
+
logger.warn(`Prompt ${name} already exists, overwriting`);
|
|
413
430
|
this.prompts.set(name, prompt);
|
|
414
431
|
logger.info(`Prompt ${name} registered successfully`);
|
|
415
432
|
return true;
|
|
@@ -527,7 +544,9 @@ class AIServiceImpl implements AIService {
|
|
|
527
544
|
}
|
|
528
545
|
this.globalSkills.set(skill.name, skill);
|
|
529
546
|
this.rebuildToolIndex();
|
|
530
|
-
logger.info(
|
|
547
|
+
logger.info(
|
|
548
|
+
`Skill ${skill.name} registered with ${skill.tools.length} tools`,
|
|
549
|
+
);
|
|
531
550
|
return true;
|
|
532
551
|
}
|
|
533
552
|
|
|
@@ -605,9 +624,8 @@ function extractTextContent(
|
|
|
605
624
|
if (typeof content === "string") return content;
|
|
606
625
|
if (!Array.isArray(content)) return "";
|
|
607
626
|
return content
|
|
608
|
-
.filter(
|
|
609
|
-
(part
|
|
610
|
-
Boolean(part && part.type === "text"),
|
|
627
|
+
.filter((part): part is { type: "text"; text: string } =>
|
|
628
|
+
Boolean(part && part.type === "text"),
|
|
611
629
|
)
|
|
612
630
|
.map((part) => part.text)
|
|
613
631
|
.join("\n")
|