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