playkit-sdk 1.1.4-beta.4 → 1.2.0-beta
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/dist/playkit-sdk.cjs.js +429 -13
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +155 -3
- package/dist/playkit-sdk.esm.js +429 -13
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +429 -13
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/playkit-sdk.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.
|
|
2
|
+
* playkit-sdk v1.2.0-beta
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -24,6 +24,54 @@ class PlayKitError extends Error {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Chat and text generation types
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Helper to convert NpcAction to ChatTool
|
|
32
|
+
*/
|
|
33
|
+
function npcActionToTool(action) {
|
|
34
|
+
var _a;
|
|
35
|
+
const properties = {};
|
|
36
|
+
const required = [];
|
|
37
|
+
for (const param of action.parameters || []) {
|
|
38
|
+
const propDef = { description: param.description };
|
|
39
|
+
switch (param.type) {
|
|
40
|
+
case 'string':
|
|
41
|
+
propDef.type = 'string';
|
|
42
|
+
break;
|
|
43
|
+
case 'number':
|
|
44
|
+
propDef.type = 'number';
|
|
45
|
+
break;
|
|
46
|
+
case 'boolean':
|
|
47
|
+
propDef.type = 'boolean';
|
|
48
|
+
break;
|
|
49
|
+
case 'stringEnum':
|
|
50
|
+
propDef.type = 'string';
|
|
51
|
+
if ((_a = param.enumOptions) === null || _a === void 0 ? void 0 : _a.length) {
|
|
52
|
+
propDef.enum = param.enumOptions;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
properties[param.name] = propDef;
|
|
57
|
+
if (param.required !== false) {
|
|
58
|
+
required.push(param.name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
type: 'function',
|
|
63
|
+
function: {
|
|
64
|
+
name: action.actionName,
|
|
65
|
+
description: action.description,
|
|
66
|
+
parameters: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties,
|
|
69
|
+
required,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
27
75
|
/**
|
|
28
76
|
* Token storage with encryption using Web Crypto API
|
|
29
77
|
* Stores tokens in localStorage with AES-128-GCM encryption
|
|
@@ -2460,30 +2508,199 @@ class ChatProvider {
|
|
|
2460
2508
|
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
|
|
2461
2509
|
}
|
|
2462
2510
|
}
|
|
2511
|
+
/**
|
|
2512
|
+
* Make a chat completion request with tools (non-streaming)
|
|
2513
|
+
*/
|
|
2514
|
+
async chatCompletionWithTools(chatConfig) {
|
|
2515
|
+
var _a, _b;
|
|
2516
|
+
const token = this.authManager.getToken();
|
|
2517
|
+
if (!token) {
|
|
2518
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2519
|
+
}
|
|
2520
|
+
const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2521
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2522
|
+
const requestBody = {
|
|
2523
|
+
model,
|
|
2524
|
+
messages: chatConfig.messages,
|
|
2525
|
+
temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
|
|
2526
|
+
stream: false,
|
|
2527
|
+
max_tokens: chatConfig.maxTokens || null,
|
|
2528
|
+
seed: chatConfig.seed || null,
|
|
2529
|
+
stop: chatConfig.stop || null,
|
|
2530
|
+
top_p: chatConfig.topP || null,
|
|
2531
|
+
};
|
|
2532
|
+
// Add tools if provided
|
|
2533
|
+
if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
|
|
2534
|
+
requestBody.tools = chatConfig.tools;
|
|
2535
|
+
}
|
|
2536
|
+
if (chatConfig.tool_choice) {
|
|
2537
|
+
requestBody.tool_choice = chatConfig.tool_choice;
|
|
2538
|
+
}
|
|
2539
|
+
try {
|
|
2540
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
2541
|
+
method: 'POST',
|
|
2542
|
+
headers: {
|
|
2543
|
+
Authorization: `Bearer ${token}`,
|
|
2544
|
+
'Content-Type': 'application/json',
|
|
2545
|
+
},
|
|
2546
|
+
body: JSON.stringify(requestBody),
|
|
2547
|
+
});
|
|
2548
|
+
if (!response.ok) {
|
|
2549
|
+
const error = await response.json().catch(() => ({ message: 'Chat request failed' }));
|
|
2550
|
+
const playKitError = new PlayKitError(error.message || 'Chat request failed', error.code, response.status);
|
|
2551
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
2552
|
+
if (this.playerClient) {
|
|
2553
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
throw playKitError;
|
|
2557
|
+
}
|
|
2558
|
+
const result = await response.json();
|
|
2559
|
+
if (this.playerClient) {
|
|
2560
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
2561
|
+
}
|
|
2562
|
+
return result;
|
|
2563
|
+
}
|
|
2564
|
+
catch (error) {
|
|
2565
|
+
if (error instanceof PlayKitError) {
|
|
2566
|
+
throw error;
|
|
2567
|
+
}
|
|
2568
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_ERROR');
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
/**
|
|
2572
|
+
* Make a streaming chat completion request with tools
|
|
2573
|
+
*/
|
|
2574
|
+
async chatCompletionWithToolsStream(chatConfig) {
|
|
2575
|
+
var _a, _b;
|
|
2576
|
+
const token = this.authManager.getToken();
|
|
2577
|
+
if (!token) {
|
|
2578
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2579
|
+
}
|
|
2580
|
+
const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2581
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2582
|
+
const requestBody = {
|
|
2583
|
+
model,
|
|
2584
|
+
messages: chatConfig.messages,
|
|
2585
|
+
temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
|
|
2586
|
+
stream: true,
|
|
2587
|
+
max_tokens: chatConfig.maxTokens || null,
|
|
2588
|
+
seed: chatConfig.seed || null,
|
|
2589
|
+
stop: chatConfig.stop || null,
|
|
2590
|
+
top_p: chatConfig.topP || null,
|
|
2591
|
+
};
|
|
2592
|
+
// Add tools if provided
|
|
2593
|
+
if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
|
|
2594
|
+
requestBody.tools = chatConfig.tools;
|
|
2595
|
+
}
|
|
2596
|
+
if (chatConfig.tool_choice) {
|
|
2597
|
+
requestBody.tool_choice = chatConfig.tool_choice;
|
|
2598
|
+
}
|
|
2599
|
+
try {
|
|
2600
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
2601
|
+
method: 'POST',
|
|
2602
|
+
headers: {
|
|
2603
|
+
Authorization: `Bearer ${token}`,
|
|
2604
|
+
'Content-Type': 'application/json',
|
|
2605
|
+
},
|
|
2606
|
+
body: JSON.stringify(requestBody),
|
|
2607
|
+
});
|
|
2608
|
+
if (!response.ok) {
|
|
2609
|
+
const error = await response.json().catch(() => ({ message: 'Chat stream request failed' }));
|
|
2610
|
+
const playKitError = new PlayKitError(error.message || 'Chat stream request failed', error.code, response.status);
|
|
2611
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
2612
|
+
if (this.playerClient) {
|
|
2613
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
throw playKitError;
|
|
2617
|
+
}
|
|
2618
|
+
if (!response.body) {
|
|
2619
|
+
throw new PlayKitError('Response body is null', 'NO_RESPONSE_BODY');
|
|
2620
|
+
}
|
|
2621
|
+
if (this.playerClient) {
|
|
2622
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
2623
|
+
}
|
|
2624
|
+
return response.body.getReader();
|
|
2625
|
+
}
|
|
2626
|
+
catch (error) {
|
|
2627
|
+
if (error instanceof PlayKitError) {
|
|
2628
|
+
throw error;
|
|
2629
|
+
}
|
|
2630
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2463
2633
|
/**
|
|
2464
2634
|
* Generate structured output using JSON schema
|
|
2635
|
+
* Uses the /chat endpoint with response_format for structured output
|
|
2465
2636
|
*/
|
|
2466
|
-
async generateStructured(schemaName, prompt, model, temperature) {
|
|
2637
|
+
async generateStructured(schemaName, prompt, model, temperature, schema, schemaDescription) {
|
|
2467
2638
|
var _a;
|
|
2639
|
+
const token = this.authManager.getToken();
|
|
2640
|
+
if (!token) {
|
|
2641
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2642
|
+
}
|
|
2643
|
+
const modelToUse = model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2644
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2468
2645
|
const messages = [{ role: 'user', content: prompt }];
|
|
2469
|
-
const
|
|
2646
|
+
const requestBody = {
|
|
2647
|
+
model: modelToUse,
|
|
2470
2648
|
messages,
|
|
2471
|
-
model: model || this.config.defaultChatModel,
|
|
2472
2649
|
temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7,
|
|
2650
|
+
stream: false,
|
|
2473
2651
|
};
|
|
2474
|
-
// Add
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2652
|
+
// Add response_format with json_schema if schema is provided
|
|
2653
|
+
if (schema) {
|
|
2654
|
+
requestBody.response_format = {
|
|
2655
|
+
type: 'json_schema',
|
|
2656
|
+
json_schema: {
|
|
2657
|
+
name: schemaName,
|
|
2658
|
+
description: schemaDescription || '',
|
|
2659
|
+
schema: schema,
|
|
2660
|
+
strict: true,
|
|
2661
|
+
},
|
|
2662
|
+
};
|
|
2481
2663
|
}
|
|
2482
2664
|
try {
|
|
2483
|
-
|
|
2665
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
2666
|
+
method: 'POST',
|
|
2667
|
+
headers: {
|
|
2668
|
+
Authorization: `Bearer ${token}`,
|
|
2669
|
+
'Content-Type': 'application/json',
|
|
2670
|
+
},
|
|
2671
|
+
body: JSON.stringify(requestBody),
|
|
2672
|
+
});
|
|
2673
|
+
if (!response.ok) {
|
|
2674
|
+
const error = await response.json().catch(() => ({ message: 'Structured generation failed' }));
|
|
2675
|
+
const playKitError = new PlayKitError(error.message || 'Structured generation failed', error.code, response.status);
|
|
2676
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
2677
|
+
if (this.playerClient) {
|
|
2678
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
throw playKitError;
|
|
2682
|
+
}
|
|
2683
|
+
const result = await response.json();
|
|
2684
|
+
if (this.playerClient) {
|
|
2685
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
2686
|
+
}
|
|
2687
|
+
// Parse the response content as JSON
|
|
2688
|
+
const content = (_a = result.choices[0]) === null || _a === void 0 ? void 0 : _a.message.content;
|
|
2689
|
+
if (!content) {
|
|
2690
|
+
throw new PlayKitError('No content in response', 'NO_CONTENT');
|
|
2691
|
+
}
|
|
2692
|
+
try {
|
|
2693
|
+
return JSON.parse(content);
|
|
2694
|
+
}
|
|
2695
|
+
catch (parseError) {
|
|
2696
|
+
throw new PlayKitError('Failed to parse structured output', 'PARSE_ERROR');
|
|
2697
|
+
}
|
|
2484
2698
|
}
|
|
2485
2699
|
catch (error) {
|
|
2486
|
-
|
|
2700
|
+
if (error instanceof PlayKitError) {
|
|
2701
|
+
throw error;
|
|
2702
|
+
}
|
|
2703
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'STRUCTURED_GENERATION_ERROR');
|
|
2487
2704
|
}
|
|
2488
2705
|
}
|
|
2489
2706
|
}
|
|
@@ -2839,6 +3056,56 @@ class ChatClient {
|
|
|
2839
3056
|
onComplete,
|
|
2840
3057
|
});
|
|
2841
3058
|
}
|
|
3059
|
+
/**
|
|
3060
|
+
* Generate text with tool calling support (non-streaming)
|
|
3061
|
+
*/
|
|
3062
|
+
async textGenerationWithTools(config) {
|
|
3063
|
+
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
3064
|
+
const response = await this.provider.chatCompletionWithTools(chatConfig);
|
|
3065
|
+
const choice = response.choices[0];
|
|
3066
|
+
if (!choice) {
|
|
3067
|
+
throw new Error('No choices in response');
|
|
3068
|
+
}
|
|
3069
|
+
return {
|
|
3070
|
+
content: choice.message.content || '',
|
|
3071
|
+
model: response.model,
|
|
3072
|
+
finishReason: choice.finish_reason,
|
|
3073
|
+
usage: response.usage
|
|
3074
|
+
? {
|
|
3075
|
+
promptTokens: response.usage.prompt_tokens,
|
|
3076
|
+
completionTokens: response.usage.completion_tokens,
|
|
3077
|
+
totalTokens: response.usage.total_tokens,
|
|
3078
|
+
}
|
|
3079
|
+
: undefined,
|
|
3080
|
+
id: response.id,
|
|
3081
|
+
created: response.created,
|
|
3082
|
+
tool_calls: choice.message.tool_calls,
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
/**
|
|
3086
|
+
* Generate text with tool calling support (streaming)
|
|
3087
|
+
* Text streams first, complete result with tool_calls returned in onComplete
|
|
3088
|
+
*/
|
|
3089
|
+
async textGenerationWithToolsStream(config) {
|
|
3090
|
+
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
3091
|
+
const reader = await this.provider.chatCompletionWithToolsStream(chatConfig);
|
|
3092
|
+
let fullContent = '';
|
|
3093
|
+
let toolCalls = [];
|
|
3094
|
+
await StreamParser.streamWithCallbacks(reader, (chunk) => {
|
|
3095
|
+
fullContent += chunk;
|
|
3096
|
+
config.onChunk(chunk);
|
|
3097
|
+
}, () => {
|
|
3098
|
+
// On complete, provide full result
|
|
3099
|
+
if (config.onComplete) {
|
|
3100
|
+
config.onComplete({
|
|
3101
|
+
content: fullContent,
|
|
3102
|
+
model: chatConfig.model || this.model,
|
|
3103
|
+
finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
|
|
3104
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3107
|
+
}, config.onError);
|
|
3108
|
+
}
|
|
2842
3109
|
}
|
|
2843
3110
|
|
|
2844
3111
|
/**
|
|
@@ -2988,8 +3255,10 @@ class NPCClient extends EventEmitter {
|
|
|
2988
3255
|
}
|
|
2989
3256
|
/**
|
|
2990
3257
|
* Talk with structured output
|
|
3258
|
+
* @deprecated Use talkWithActions instead for NPC decision-making with actions
|
|
2991
3259
|
*/
|
|
2992
3260
|
async talkStructured(message, schemaName) {
|
|
3261
|
+
console.warn('[NPCClient] talkStructured is deprecated. Use talkWithActions instead for NPC decision-making with actions.');
|
|
2993
3262
|
// Add user message to history
|
|
2994
3263
|
const userMessage = { role: 'user', content: message };
|
|
2995
3264
|
this.history.push(userMessage);
|
|
@@ -3009,6 +3278,153 @@ class NPCClient extends EventEmitter {
|
|
|
3009
3278
|
this.trimHistory();
|
|
3010
3279
|
return result;
|
|
3011
3280
|
}
|
|
3281
|
+
/**
|
|
3282
|
+
* Talk to the NPC with available actions (non-streaming)
|
|
3283
|
+
* @param message The message to send
|
|
3284
|
+
* @param actions List of actions the NPC can perform
|
|
3285
|
+
* @returns Response containing text and any action calls
|
|
3286
|
+
*/
|
|
3287
|
+
async talkWithActions(message, actions) {
|
|
3288
|
+
// Add user message to history
|
|
3289
|
+
const userMessage = { role: 'user', content: message };
|
|
3290
|
+
this.history.push(userMessage);
|
|
3291
|
+
// Convert NpcActions to ChatTools
|
|
3292
|
+
const tools = actions
|
|
3293
|
+
.filter(a => a && a.enabled !== false)
|
|
3294
|
+
.map(a => npcActionToTool(a));
|
|
3295
|
+
// Build messages array with system prompt
|
|
3296
|
+
const messages = [
|
|
3297
|
+
{ role: 'system', content: this.systemPrompt },
|
|
3298
|
+
...this.history,
|
|
3299
|
+
];
|
|
3300
|
+
// Generate response with tools
|
|
3301
|
+
const result = await this.chatClient.textGenerationWithTools({
|
|
3302
|
+
messages,
|
|
3303
|
+
temperature: this.temperature,
|
|
3304
|
+
tools,
|
|
3305
|
+
tool_choice: 'auto',
|
|
3306
|
+
});
|
|
3307
|
+
// Build response
|
|
3308
|
+
const response = {
|
|
3309
|
+
text: result.content || '',
|
|
3310
|
+
actionCalls: [],
|
|
3311
|
+
hasActions: false,
|
|
3312
|
+
};
|
|
3313
|
+
// Extract tool calls if any
|
|
3314
|
+
if (result.tool_calls) {
|
|
3315
|
+
response.actionCalls = result.tool_calls.map(tc => ({
|
|
3316
|
+
id: tc.id,
|
|
3317
|
+
actionName: tc.function.name,
|
|
3318
|
+
arguments: this.parseToolArguments(tc.function.arguments),
|
|
3319
|
+
}));
|
|
3320
|
+
response.hasActions = response.actionCalls.length > 0;
|
|
3321
|
+
}
|
|
3322
|
+
// Add assistant response to history
|
|
3323
|
+
const assistantMessage = {
|
|
3324
|
+
role: 'assistant',
|
|
3325
|
+
content: response.text,
|
|
3326
|
+
tool_calls: result.tool_calls,
|
|
3327
|
+
};
|
|
3328
|
+
this.history.push(assistantMessage);
|
|
3329
|
+
this.trimHistory();
|
|
3330
|
+
this.emit('response', response.text);
|
|
3331
|
+
if (response.hasActions) {
|
|
3332
|
+
this.emit('actions', response.actionCalls);
|
|
3333
|
+
}
|
|
3334
|
+
return response;
|
|
3335
|
+
}
|
|
3336
|
+
/**
|
|
3337
|
+
* Talk to the NPC with actions (streaming)
|
|
3338
|
+
* Text streams first, action calls are returned in onComplete
|
|
3339
|
+
*/
|
|
3340
|
+
async talkWithActionsStream(message, actions, onChunk, onComplete) {
|
|
3341
|
+
// Add user message to history
|
|
3342
|
+
const userMessage = { role: 'user', content: message };
|
|
3343
|
+
this.history.push(userMessage);
|
|
3344
|
+
// Convert NpcActions to ChatTools
|
|
3345
|
+
const tools = actions
|
|
3346
|
+
.filter(a => a && a.enabled !== false)
|
|
3347
|
+
.map(a => npcActionToTool(a));
|
|
3348
|
+
// Build messages array with system prompt
|
|
3349
|
+
const messages = [
|
|
3350
|
+
{ role: 'system', content: this.systemPrompt },
|
|
3351
|
+
...this.history,
|
|
3352
|
+
];
|
|
3353
|
+
// Generate response with tools (streaming)
|
|
3354
|
+
await this.chatClient.textGenerationWithToolsStream({
|
|
3355
|
+
messages,
|
|
3356
|
+
temperature: this.temperature,
|
|
3357
|
+
tools,
|
|
3358
|
+
tool_choice: 'auto',
|
|
3359
|
+
onChunk,
|
|
3360
|
+
onComplete: (result) => {
|
|
3361
|
+
// Build response
|
|
3362
|
+
const response = {
|
|
3363
|
+
text: result.content || '',
|
|
3364
|
+
actionCalls: [],
|
|
3365
|
+
hasActions: false,
|
|
3366
|
+
};
|
|
3367
|
+
// Extract tool calls if any
|
|
3368
|
+
if (result.tool_calls) {
|
|
3369
|
+
response.actionCalls = result.tool_calls.map(tc => ({
|
|
3370
|
+
id: tc.id,
|
|
3371
|
+
actionName: tc.function.name,
|
|
3372
|
+
arguments: this.parseToolArguments(tc.function.arguments),
|
|
3373
|
+
}));
|
|
3374
|
+
response.hasActions = response.actionCalls.length > 0;
|
|
3375
|
+
}
|
|
3376
|
+
// Add assistant response to history
|
|
3377
|
+
const assistantMessage = {
|
|
3378
|
+
role: 'assistant',
|
|
3379
|
+
content: response.text,
|
|
3380
|
+
tool_calls: result.tool_calls,
|
|
3381
|
+
};
|
|
3382
|
+
this.history.push(assistantMessage);
|
|
3383
|
+
this.trimHistory();
|
|
3384
|
+
this.emit('response', response.text);
|
|
3385
|
+
if (response.hasActions) {
|
|
3386
|
+
this.emit('actions', response.actionCalls);
|
|
3387
|
+
}
|
|
3388
|
+
if (onComplete) {
|
|
3389
|
+
onComplete(response);
|
|
3390
|
+
}
|
|
3391
|
+
},
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
/**
|
|
3395
|
+
* Report action results back to the conversation
|
|
3396
|
+
* Call this after executing actions to let the NPC know the results
|
|
3397
|
+
*/
|
|
3398
|
+
reportActionResults(results) {
|
|
3399
|
+
for (const [callId, result] of Object.entries(results)) {
|
|
3400
|
+
this.history.push({
|
|
3401
|
+
role: 'tool',
|
|
3402
|
+
tool_call_id: callId,
|
|
3403
|
+
content: result,
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
/**
|
|
3408
|
+
* Report a single action result
|
|
3409
|
+
*/
|
|
3410
|
+
reportActionResult(callId, result) {
|
|
3411
|
+
this.history.push({
|
|
3412
|
+
role: 'tool',
|
|
3413
|
+
tool_call_id: callId,
|
|
3414
|
+
content: result,
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* Parse tool arguments from JSON string
|
|
3419
|
+
*/
|
|
3420
|
+
parseToolArguments(args) {
|
|
3421
|
+
try {
|
|
3422
|
+
return JSON.parse(args);
|
|
3423
|
+
}
|
|
3424
|
+
catch (_a) {
|
|
3425
|
+
return {};
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3012
3428
|
/**
|
|
3013
3429
|
* Get conversation history
|
|
3014
3430
|
*/
|