playkit-sdk 1.1.4-beta.3 → 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 +446 -15
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +155 -3
- package/dist/playkit-sdk.esm.js +446 -15
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +446 -15
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/playkit-sdk.umd.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
|
*/
|
|
@@ -371,6 +371,54 @@
|
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Chat and text generation types
|
|
376
|
+
*/
|
|
377
|
+
/**
|
|
378
|
+
* Helper to convert NpcAction to ChatTool
|
|
379
|
+
*/
|
|
380
|
+
function npcActionToTool(action) {
|
|
381
|
+
var _a;
|
|
382
|
+
const properties = {};
|
|
383
|
+
const required = [];
|
|
384
|
+
for (const param of action.parameters || []) {
|
|
385
|
+
const propDef = { description: param.description };
|
|
386
|
+
switch (param.type) {
|
|
387
|
+
case 'string':
|
|
388
|
+
propDef.type = 'string';
|
|
389
|
+
break;
|
|
390
|
+
case 'number':
|
|
391
|
+
propDef.type = 'number';
|
|
392
|
+
break;
|
|
393
|
+
case 'boolean':
|
|
394
|
+
propDef.type = 'boolean';
|
|
395
|
+
break;
|
|
396
|
+
case 'stringEnum':
|
|
397
|
+
propDef.type = 'string';
|
|
398
|
+
if ((_a = param.enumOptions) === null || _a === void 0 ? void 0 : _a.length) {
|
|
399
|
+
propDef.enum = param.enumOptions;
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
properties[param.name] = propDef;
|
|
404
|
+
if (param.required !== false) {
|
|
405
|
+
required.push(param.name);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
type: 'function',
|
|
410
|
+
function: {
|
|
411
|
+
name: action.actionName,
|
|
412
|
+
description: action.description,
|
|
413
|
+
parameters: {
|
|
414
|
+
type: 'object',
|
|
415
|
+
properties,
|
|
416
|
+
required,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
374
422
|
/**
|
|
375
423
|
* Token storage with encryption using Web Crypto API
|
|
376
424
|
* Stores tokens in localStorage with AES-128-GCM encryption
|
|
@@ -2807,30 +2855,199 @@
|
|
|
2807
2855
|
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
|
|
2808
2856
|
}
|
|
2809
2857
|
}
|
|
2858
|
+
/**
|
|
2859
|
+
* Make a chat completion request with tools (non-streaming)
|
|
2860
|
+
*/
|
|
2861
|
+
async chatCompletionWithTools(chatConfig) {
|
|
2862
|
+
var _a, _b;
|
|
2863
|
+
const token = this.authManager.getToken();
|
|
2864
|
+
if (!token) {
|
|
2865
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2866
|
+
}
|
|
2867
|
+
const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2868
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2869
|
+
const requestBody = {
|
|
2870
|
+
model,
|
|
2871
|
+
messages: chatConfig.messages,
|
|
2872
|
+
temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
|
|
2873
|
+
stream: false,
|
|
2874
|
+
max_tokens: chatConfig.maxTokens || null,
|
|
2875
|
+
seed: chatConfig.seed || null,
|
|
2876
|
+
stop: chatConfig.stop || null,
|
|
2877
|
+
top_p: chatConfig.topP || null,
|
|
2878
|
+
};
|
|
2879
|
+
// Add tools if provided
|
|
2880
|
+
if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
|
|
2881
|
+
requestBody.tools = chatConfig.tools;
|
|
2882
|
+
}
|
|
2883
|
+
if (chatConfig.tool_choice) {
|
|
2884
|
+
requestBody.tool_choice = chatConfig.tool_choice;
|
|
2885
|
+
}
|
|
2886
|
+
try {
|
|
2887
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
2888
|
+
method: 'POST',
|
|
2889
|
+
headers: {
|
|
2890
|
+
Authorization: `Bearer ${token}`,
|
|
2891
|
+
'Content-Type': 'application/json',
|
|
2892
|
+
},
|
|
2893
|
+
body: JSON.stringify(requestBody),
|
|
2894
|
+
});
|
|
2895
|
+
if (!response.ok) {
|
|
2896
|
+
const error = await response.json().catch(() => ({ message: 'Chat request failed' }));
|
|
2897
|
+
const playKitError = new PlayKitError(error.message || 'Chat request failed', error.code, response.status);
|
|
2898
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
2899
|
+
if (this.playerClient) {
|
|
2900
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
throw playKitError;
|
|
2904
|
+
}
|
|
2905
|
+
const result = await response.json();
|
|
2906
|
+
if (this.playerClient) {
|
|
2907
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
2908
|
+
}
|
|
2909
|
+
return result;
|
|
2910
|
+
}
|
|
2911
|
+
catch (error) {
|
|
2912
|
+
if (error instanceof PlayKitError) {
|
|
2913
|
+
throw error;
|
|
2914
|
+
}
|
|
2915
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_ERROR');
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Make a streaming chat completion request with tools
|
|
2920
|
+
*/
|
|
2921
|
+
async chatCompletionWithToolsStream(chatConfig) {
|
|
2922
|
+
var _a, _b;
|
|
2923
|
+
const token = this.authManager.getToken();
|
|
2924
|
+
if (!token) {
|
|
2925
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2926
|
+
}
|
|
2927
|
+
const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2928
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2929
|
+
const requestBody = {
|
|
2930
|
+
model,
|
|
2931
|
+
messages: chatConfig.messages,
|
|
2932
|
+
temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
|
|
2933
|
+
stream: true,
|
|
2934
|
+
max_tokens: chatConfig.maxTokens || null,
|
|
2935
|
+
seed: chatConfig.seed || null,
|
|
2936
|
+
stop: chatConfig.stop || null,
|
|
2937
|
+
top_p: chatConfig.topP || null,
|
|
2938
|
+
};
|
|
2939
|
+
// Add tools if provided
|
|
2940
|
+
if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
|
|
2941
|
+
requestBody.tools = chatConfig.tools;
|
|
2942
|
+
}
|
|
2943
|
+
if (chatConfig.tool_choice) {
|
|
2944
|
+
requestBody.tool_choice = chatConfig.tool_choice;
|
|
2945
|
+
}
|
|
2946
|
+
try {
|
|
2947
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
2948
|
+
method: 'POST',
|
|
2949
|
+
headers: {
|
|
2950
|
+
Authorization: `Bearer ${token}`,
|
|
2951
|
+
'Content-Type': 'application/json',
|
|
2952
|
+
},
|
|
2953
|
+
body: JSON.stringify(requestBody),
|
|
2954
|
+
});
|
|
2955
|
+
if (!response.ok) {
|
|
2956
|
+
const error = await response.json().catch(() => ({ message: 'Chat stream request failed' }));
|
|
2957
|
+
const playKitError = new PlayKitError(error.message || 'Chat stream request failed', error.code, response.status);
|
|
2958
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
2959
|
+
if (this.playerClient) {
|
|
2960
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
throw playKitError;
|
|
2964
|
+
}
|
|
2965
|
+
if (!response.body) {
|
|
2966
|
+
throw new PlayKitError('Response body is null', 'NO_RESPONSE_BODY');
|
|
2967
|
+
}
|
|
2968
|
+
if (this.playerClient) {
|
|
2969
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
2970
|
+
}
|
|
2971
|
+
return response.body.getReader();
|
|
2972
|
+
}
|
|
2973
|
+
catch (error) {
|
|
2974
|
+
if (error instanceof PlayKitError) {
|
|
2975
|
+
throw error;
|
|
2976
|
+
}
|
|
2977
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2810
2980
|
/**
|
|
2811
2981
|
* Generate structured output using JSON schema
|
|
2982
|
+
* Uses the /chat endpoint with response_format for structured output
|
|
2812
2983
|
*/
|
|
2813
|
-
async generateStructured(schemaName, prompt, model, temperature) {
|
|
2984
|
+
async generateStructured(schemaName, prompt, model, temperature, schema, schemaDescription) {
|
|
2814
2985
|
var _a;
|
|
2986
|
+
const token = this.authManager.getToken();
|
|
2987
|
+
if (!token) {
|
|
2988
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
2989
|
+
}
|
|
2990
|
+
const modelToUse = model || this.config.defaultChatModel || 'gpt-4o-mini';
|
|
2991
|
+
const endpoint = `/ai/${this.config.gameId}/v1/chat`;
|
|
2815
2992
|
const messages = [{ role: 'user', content: prompt }];
|
|
2816
|
-
const
|
|
2993
|
+
const requestBody = {
|
|
2994
|
+
model: modelToUse,
|
|
2817
2995
|
messages,
|
|
2818
|
-
model: model || this.config.defaultChatModel,
|
|
2819
2996
|
temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7,
|
|
2997
|
+
stream: false,
|
|
2820
2998
|
};
|
|
2821
|
-
// Add
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2999
|
+
// Add response_format with json_schema if schema is provided
|
|
3000
|
+
if (schema) {
|
|
3001
|
+
requestBody.response_format = {
|
|
3002
|
+
type: 'json_schema',
|
|
3003
|
+
json_schema: {
|
|
3004
|
+
name: schemaName,
|
|
3005
|
+
description: schemaDescription || '',
|
|
3006
|
+
schema: schema,
|
|
3007
|
+
strict: true,
|
|
3008
|
+
},
|
|
3009
|
+
};
|
|
2828
3010
|
}
|
|
2829
3011
|
try {
|
|
2830
|
-
|
|
3012
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
3013
|
+
method: 'POST',
|
|
3014
|
+
headers: {
|
|
3015
|
+
Authorization: `Bearer ${token}`,
|
|
3016
|
+
'Content-Type': 'application/json',
|
|
3017
|
+
},
|
|
3018
|
+
body: JSON.stringify(requestBody),
|
|
3019
|
+
});
|
|
3020
|
+
if (!response.ok) {
|
|
3021
|
+
const error = await response.json().catch(() => ({ message: 'Structured generation failed' }));
|
|
3022
|
+
const playKitError = new PlayKitError(error.message || 'Structured generation failed', error.code, response.status);
|
|
3023
|
+
if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
|
|
3024
|
+
if (this.playerClient) {
|
|
3025
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
throw playKitError;
|
|
3029
|
+
}
|
|
3030
|
+
const result = await response.json();
|
|
3031
|
+
if (this.playerClient) {
|
|
3032
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => { });
|
|
3033
|
+
}
|
|
3034
|
+
// Parse the response content as JSON
|
|
3035
|
+
const content = (_a = result.choices[0]) === null || _a === void 0 ? void 0 : _a.message.content;
|
|
3036
|
+
if (!content) {
|
|
3037
|
+
throw new PlayKitError('No content in response', 'NO_CONTENT');
|
|
3038
|
+
}
|
|
3039
|
+
try {
|
|
3040
|
+
return JSON.parse(content);
|
|
3041
|
+
}
|
|
3042
|
+
catch (parseError) {
|
|
3043
|
+
throw new PlayKitError('Failed to parse structured output', 'PARSE_ERROR');
|
|
3044
|
+
}
|
|
2831
3045
|
}
|
|
2832
3046
|
catch (error) {
|
|
2833
|
-
|
|
3047
|
+
if (error instanceof PlayKitError) {
|
|
3048
|
+
throw error;
|
|
3049
|
+
}
|
|
3050
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'STRUCTURED_GENERATION_ERROR');
|
|
2834
3051
|
}
|
|
2835
3052
|
}
|
|
2836
3053
|
}
|
|
@@ -3186,6 +3403,56 @@
|
|
|
3186
3403
|
onComplete,
|
|
3187
3404
|
});
|
|
3188
3405
|
}
|
|
3406
|
+
/**
|
|
3407
|
+
* Generate text with tool calling support (non-streaming)
|
|
3408
|
+
*/
|
|
3409
|
+
async textGenerationWithTools(config) {
|
|
3410
|
+
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
3411
|
+
const response = await this.provider.chatCompletionWithTools(chatConfig);
|
|
3412
|
+
const choice = response.choices[0];
|
|
3413
|
+
if (!choice) {
|
|
3414
|
+
throw new Error('No choices in response');
|
|
3415
|
+
}
|
|
3416
|
+
return {
|
|
3417
|
+
content: choice.message.content || '',
|
|
3418
|
+
model: response.model,
|
|
3419
|
+
finishReason: choice.finish_reason,
|
|
3420
|
+
usage: response.usage
|
|
3421
|
+
? {
|
|
3422
|
+
promptTokens: response.usage.prompt_tokens,
|
|
3423
|
+
completionTokens: response.usage.completion_tokens,
|
|
3424
|
+
totalTokens: response.usage.total_tokens,
|
|
3425
|
+
}
|
|
3426
|
+
: undefined,
|
|
3427
|
+
id: response.id,
|
|
3428
|
+
created: response.created,
|
|
3429
|
+
tool_calls: choice.message.tool_calls,
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
/**
|
|
3433
|
+
* Generate text with tool calling support (streaming)
|
|
3434
|
+
* Text streams first, complete result with tool_calls returned in onComplete
|
|
3435
|
+
*/
|
|
3436
|
+
async textGenerationWithToolsStream(config) {
|
|
3437
|
+
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
3438
|
+
const reader = await this.provider.chatCompletionWithToolsStream(chatConfig);
|
|
3439
|
+
let fullContent = '';
|
|
3440
|
+
let toolCalls = [];
|
|
3441
|
+
await StreamParser.streamWithCallbacks(reader, (chunk) => {
|
|
3442
|
+
fullContent += chunk;
|
|
3443
|
+
config.onChunk(chunk);
|
|
3444
|
+
}, () => {
|
|
3445
|
+
// On complete, provide full result
|
|
3446
|
+
if (config.onComplete) {
|
|
3447
|
+
config.onComplete({
|
|
3448
|
+
content: fullContent,
|
|
3449
|
+
model: chatConfig.model || this.model,
|
|
3450
|
+
finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
|
|
3451
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
}, config.onError);
|
|
3455
|
+
}
|
|
3189
3456
|
}
|
|
3190
3457
|
|
|
3191
3458
|
/**
|
|
@@ -3335,8 +3602,10 @@
|
|
|
3335
3602
|
}
|
|
3336
3603
|
/**
|
|
3337
3604
|
* Talk with structured output
|
|
3605
|
+
* @deprecated Use talkWithActions instead for NPC decision-making with actions
|
|
3338
3606
|
*/
|
|
3339
3607
|
async talkStructured(message, schemaName) {
|
|
3608
|
+
console.warn('[NPCClient] talkStructured is deprecated. Use talkWithActions instead for NPC decision-making with actions.');
|
|
3340
3609
|
// Add user message to history
|
|
3341
3610
|
const userMessage = { role: 'user', content: message };
|
|
3342
3611
|
this.history.push(userMessage);
|
|
@@ -3356,6 +3625,153 @@
|
|
|
3356
3625
|
this.trimHistory();
|
|
3357
3626
|
return result;
|
|
3358
3627
|
}
|
|
3628
|
+
/**
|
|
3629
|
+
* Talk to the NPC with available actions (non-streaming)
|
|
3630
|
+
* @param message The message to send
|
|
3631
|
+
* @param actions List of actions the NPC can perform
|
|
3632
|
+
* @returns Response containing text and any action calls
|
|
3633
|
+
*/
|
|
3634
|
+
async talkWithActions(message, actions) {
|
|
3635
|
+
// Add user message to history
|
|
3636
|
+
const userMessage = { role: 'user', content: message };
|
|
3637
|
+
this.history.push(userMessage);
|
|
3638
|
+
// Convert NpcActions to ChatTools
|
|
3639
|
+
const tools = actions
|
|
3640
|
+
.filter(a => a && a.enabled !== false)
|
|
3641
|
+
.map(a => npcActionToTool(a));
|
|
3642
|
+
// Build messages array with system prompt
|
|
3643
|
+
const messages = [
|
|
3644
|
+
{ role: 'system', content: this.systemPrompt },
|
|
3645
|
+
...this.history,
|
|
3646
|
+
];
|
|
3647
|
+
// Generate response with tools
|
|
3648
|
+
const result = await this.chatClient.textGenerationWithTools({
|
|
3649
|
+
messages,
|
|
3650
|
+
temperature: this.temperature,
|
|
3651
|
+
tools,
|
|
3652
|
+
tool_choice: 'auto',
|
|
3653
|
+
});
|
|
3654
|
+
// Build response
|
|
3655
|
+
const response = {
|
|
3656
|
+
text: result.content || '',
|
|
3657
|
+
actionCalls: [],
|
|
3658
|
+
hasActions: false,
|
|
3659
|
+
};
|
|
3660
|
+
// Extract tool calls if any
|
|
3661
|
+
if (result.tool_calls) {
|
|
3662
|
+
response.actionCalls = result.tool_calls.map(tc => ({
|
|
3663
|
+
id: tc.id,
|
|
3664
|
+
actionName: tc.function.name,
|
|
3665
|
+
arguments: this.parseToolArguments(tc.function.arguments),
|
|
3666
|
+
}));
|
|
3667
|
+
response.hasActions = response.actionCalls.length > 0;
|
|
3668
|
+
}
|
|
3669
|
+
// Add assistant response to history
|
|
3670
|
+
const assistantMessage = {
|
|
3671
|
+
role: 'assistant',
|
|
3672
|
+
content: response.text,
|
|
3673
|
+
tool_calls: result.tool_calls,
|
|
3674
|
+
};
|
|
3675
|
+
this.history.push(assistantMessage);
|
|
3676
|
+
this.trimHistory();
|
|
3677
|
+
this.emit('response', response.text);
|
|
3678
|
+
if (response.hasActions) {
|
|
3679
|
+
this.emit('actions', response.actionCalls);
|
|
3680
|
+
}
|
|
3681
|
+
return response;
|
|
3682
|
+
}
|
|
3683
|
+
/**
|
|
3684
|
+
* Talk to the NPC with actions (streaming)
|
|
3685
|
+
* Text streams first, action calls are returned in onComplete
|
|
3686
|
+
*/
|
|
3687
|
+
async talkWithActionsStream(message, actions, onChunk, onComplete) {
|
|
3688
|
+
// Add user message to history
|
|
3689
|
+
const userMessage = { role: 'user', content: message };
|
|
3690
|
+
this.history.push(userMessage);
|
|
3691
|
+
// Convert NpcActions to ChatTools
|
|
3692
|
+
const tools = actions
|
|
3693
|
+
.filter(a => a && a.enabled !== false)
|
|
3694
|
+
.map(a => npcActionToTool(a));
|
|
3695
|
+
// Build messages array with system prompt
|
|
3696
|
+
const messages = [
|
|
3697
|
+
{ role: 'system', content: this.systemPrompt },
|
|
3698
|
+
...this.history,
|
|
3699
|
+
];
|
|
3700
|
+
// Generate response with tools (streaming)
|
|
3701
|
+
await this.chatClient.textGenerationWithToolsStream({
|
|
3702
|
+
messages,
|
|
3703
|
+
temperature: this.temperature,
|
|
3704
|
+
tools,
|
|
3705
|
+
tool_choice: 'auto',
|
|
3706
|
+
onChunk,
|
|
3707
|
+
onComplete: (result) => {
|
|
3708
|
+
// Build response
|
|
3709
|
+
const response = {
|
|
3710
|
+
text: result.content || '',
|
|
3711
|
+
actionCalls: [],
|
|
3712
|
+
hasActions: false,
|
|
3713
|
+
};
|
|
3714
|
+
// Extract tool calls if any
|
|
3715
|
+
if (result.tool_calls) {
|
|
3716
|
+
response.actionCalls = result.tool_calls.map(tc => ({
|
|
3717
|
+
id: tc.id,
|
|
3718
|
+
actionName: tc.function.name,
|
|
3719
|
+
arguments: this.parseToolArguments(tc.function.arguments),
|
|
3720
|
+
}));
|
|
3721
|
+
response.hasActions = response.actionCalls.length > 0;
|
|
3722
|
+
}
|
|
3723
|
+
// Add assistant response to history
|
|
3724
|
+
const assistantMessage = {
|
|
3725
|
+
role: 'assistant',
|
|
3726
|
+
content: response.text,
|
|
3727
|
+
tool_calls: result.tool_calls,
|
|
3728
|
+
};
|
|
3729
|
+
this.history.push(assistantMessage);
|
|
3730
|
+
this.trimHistory();
|
|
3731
|
+
this.emit('response', response.text);
|
|
3732
|
+
if (response.hasActions) {
|
|
3733
|
+
this.emit('actions', response.actionCalls);
|
|
3734
|
+
}
|
|
3735
|
+
if (onComplete) {
|
|
3736
|
+
onComplete(response);
|
|
3737
|
+
}
|
|
3738
|
+
},
|
|
3739
|
+
});
|
|
3740
|
+
}
|
|
3741
|
+
/**
|
|
3742
|
+
* Report action results back to the conversation
|
|
3743
|
+
* Call this after executing actions to let the NPC know the results
|
|
3744
|
+
*/
|
|
3745
|
+
reportActionResults(results) {
|
|
3746
|
+
for (const [callId, result] of Object.entries(results)) {
|
|
3747
|
+
this.history.push({
|
|
3748
|
+
role: 'tool',
|
|
3749
|
+
tool_call_id: callId,
|
|
3750
|
+
content: result,
|
|
3751
|
+
});
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
/**
|
|
3755
|
+
* Report a single action result
|
|
3756
|
+
*/
|
|
3757
|
+
reportActionResult(callId, result) {
|
|
3758
|
+
this.history.push({
|
|
3759
|
+
role: 'tool',
|
|
3760
|
+
tool_call_id: callId,
|
|
3761
|
+
content: result,
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3764
|
+
/**
|
|
3765
|
+
* Parse tool arguments from JSON string
|
|
3766
|
+
*/
|
|
3767
|
+
parseToolArguments(args) {
|
|
3768
|
+
try {
|
|
3769
|
+
return JSON.parse(args);
|
|
3770
|
+
}
|
|
3771
|
+
catch (_a) {
|
|
3772
|
+
return {};
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3359
3775
|
/**
|
|
3360
3776
|
* Get conversation history
|
|
3361
3777
|
*/
|
|
@@ -3499,12 +3915,27 @@
|
|
|
3499
3915
|
}
|
|
3500
3916
|
}
|
|
3501
3917
|
catch (error) {
|
|
3502
|
-
// If token is invalid, logout and
|
|
3918
|
+
// If token is invalid, logout and restart auth flow
|
|
3503
3919
|
if (this.config.debug) {
|
|
3504
3920
|
console.error('[PlayKitSDK] Token validation failed:', error);
|
|
3505
3921
|
}
|
|
3506
3922
|
await this.authManager.logout();
|
|
3507
|
-
|
|
3923
|
+
// Auto-restart login flow in browser environment
|
|
3924
|
+
if (typeof window !== 'undefined') {
|
|
3925
|
+
if (this.config.debug) {
|
|
3926
|
+
console.log('[PlayKitSDK] Restarting authentication flow...');
|
|
3927
|
+
}
|
|
3928
|
+
const useExternalAuth = this.config.authMethod === 'external-auth';
|
|
3929
|
+
await this.authManager.startAuthFlow(useExternalAuth);
|
|
3930
|
+
// Retry getting player info after re-authentication
|
|
3931
|
+
await this.playerClient.getPlayerInfo();
|
|
3932
|
+
if (this.config.debug) {
|
|
3933
|
+
console.log('[PlayKitSDK] Re-authentication successful, token validated');
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
else {
|
|
3937
|
+
throw new Error('Token validation failed: ' + (error instanceof Error ? error.message : String(error)));
|
|
3938
|
+
}
|
|
3508
3939
|
}
|
|
3509
3940
|
}
|
|
3510
3941
|
this.emit('ready');
|