playkit-sdk 1.4.0-beta.1 → 1.4.0-beta.3
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 +31 -0
- package/dist/playkit-sdk.cjs.js +192 -88
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +125 -56
- package/dist/playkit-sdk.esm.js +192 -88
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +192 -88
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,33 @@ await chat.chatStream(
|
|
|
68
68
|
);
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### Reasoning (Thinking)
|
|
72
|
+
|
|
73
|
+
Reasoning-capable models can think before answering. Enable it with the
|
|
74
|
+
`thinking` option (set the `effort` level) and read the model's reasoning
|
|
75
|
+
separately from its answer.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Non-streaming: reasoning is returned on `result.reasoning`
|
|
79
|
+
const result = await chat.textGeneration({
|
|
80
|
+
messages: [{ role: 'user', content: 'Solve: 17 * 24, show your work.' }],
|
|
81
|
+
thinking: { effort: 'high' },
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
console.log('Answer:', result.content);
|
|
85
|
+
console.log('Reasoning:', result.reasoning);
|
|
86
|
+
|
|
87
|
+
// Streaming: reasoning arrives via the `onReasoning` callback,
|
|
88
|
+
// kept separate from the answer text in `onChunk`
|
|
89
|
+
await chat.textGenerationStream({
|
|
90
|
+
messages: [{ role: 'user', content: 'Solve: 17 * 24, show your work.' }],
|
|
91
|
+
thinking: { effort: 'high' },
|
|
92
|
+
onReasoning: (chunk) => process.stdout.write(`[thinking] ${chunk}`),
|
|
93
|
+
onChunk: (chunk) => process.stdout.write(chunk),
|
|
94
|
+
onComplete: (fullText) => console.log('\nComplete:', fullText),
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
71
98
|
### Image Generation
|
|
72
99
|
|
|
73
100
|
```typescript
|
|
@@ -256,6 +283,10 @@ This SDK is proprietary software owned by Agentland Lab. Use of this SDK is subj
|
|
|
256
283
|
|
|
257
284
|
## Changelog
|
|
258
285
|
|
|
286
|
+
### 1.4.0-beta.3
|
|
287
|
+
- Added `thinking` reasoning-effort option on chat (`thinking: { effort: 'high' }`)
|
|
288
|
+
- Surface model reasoning: `result.reasoning` (non-streaming) and the `onReasoning` callback (streaming)
|
|
289
|
+
|
|
259
290
|
### 1.0.0-beta.1
|
|
260
291
|
- Initial public beta release
|
|
261
292
|
- AI chat support (text generation)
|
package/dist/playkit-sdk.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.4.0-beta.
|
|
2
|
+
* playkit-sdk v1.4.0-beta.3
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -830,7 +830,7 @@ class TokenStorage {
|
|
|
830
830
|
}
|
|
831
831
|
|
|
832
832
|
const SDK_TYPE = 'Javascript';
|
|
833
|
-
const SDK_VERSION = '"1.4.0-beta.
|
|
833
|
+
const SDK_VERSION = '"1.4.0-beta.3"';
|
|
834
834
|
function getSDKHeaders() {
|
|
835
835
|
return {
|
|
836
836
|
'X-SDK-Type': SDK_TYPE,
|
|
@@ -3930,6 +3930,9 @@ class ChatProvider {
|
|
|
3930
3930
|
stop: chatConfig.stop || null,
|
|
3931
3931
|
top_p: chatConfig.topP || null,
|
|
3932
3932
|
};
|
|
3933
|
+
if (chatConfig.thinking) {
|
|
3934
|
+
requestBody.thinking = chatConfig.thinking;
|
|
3935
|
+
}
|
|
3933
3936
|
try {
|
|
3934
3937
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
3935
3938
|
method: 'POST',
|
|
@@ -3987,6 +3990,9 @@ class ChatProvider {
|
|
|
3987
3990
|
stop: chatConfig.stop || null,
|
|
3988
3991
|
top_p: chatConfig.topP || null,
|
|
3989
3992
|
};
|
|
3993
|
+
if (chatConfig.thinking) {
|
|
3994
|
+
requestBody.thinking = chatConfig.thinking;
|
|
3995
|
+
}
|
|
3990
3996
|
try {
|
|
3991
3997
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
3992
3998
|
method: 'POST',
|
|
@@ -4051,6 +4057,9 @@ class ChatProvider {
|
|
|
4051
4057
|
if (chatConfig.tool_choice) {
|
|
4052
4058
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4053
4059
|
}
|
|
4060
|
+
if (chatConfig.thinking) {
|
|
4061
|
+
requestBody.thinking = chatConfig.thinking;
|
|
4062
|
+
}
|
|
4054
4063
|
try {
|
|
4055
4064
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
4056
4065
|
method: 'POST',
|
|
@@ -4109,6 +4118,9 @@ class ChatProvider {
|
|
|
4109
4118
|
if (chatConfig.tool_choice) {
|
|
4110
4119
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4111
4120
|
}
|
|
4121
|
+
if (chatConfig.thinking) {
|
|
4122
|
+
requestBody.thinking = chatConfig.thinking;
|
|
4123
|
+
}
|
|
4112
4124
|
try {
|
|
4113
4125
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
4114
4126
|
method: 'POST',
|
|
@@ -4418,6 +4430,19 @@ class TranscriptionProvider {
|
|
|
4418
4430
|
*/
|
|
4419
4431
|
// @ts-ignore - replaced at build time
|
|
4420
4432
|
const DEFAULT_BASE_URL$1 = "https://api.playkit.ai";
|
|
4433
|
+
/** Decode a base64 string to an ArrayBuffer (browser + Node). */
|
|
4434
|
+
function base64ToArrayBuffer(b64) {
|
|
4435
|
+
if (typeof atob === 'function') {
|
|
4436
|
+
const bin = atob(b64);
|
|
4437
|
+
const bytes = new Uint8Array(bin.length);
|
|
4438
|
+
for (let i = 0; i < bin.length; i++)
|
|
4439
|
+
bytes[i] = bin.charCodeAt(i);
|
|
4440
|
+
return bytes.buffer;
|
|
4441
|
+
}
|
|
4442
|
+
// Node fallback
|
|
4443
|
+
const buf = globalThis.Buffer.from(b64, 'base64');
|
|
4444
|
+
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
4445
|
+
}
|
|
4421
4446
|
class TTSProvider {
|
|
4422
4447
|
constructor(authManager, config) {
|
|
4423
4448
|
this.authManager = authManager;
|
|
@@ -4430,69 +4455,69 @@ class TTSProvider {
|
|
|
4430
4455
|
setPlayerClient(playerClient) {
|
|
4431
4456
|
this.playerClient = playerClient;
|
|
4432
4457
|
}
|
|
4433
|
-
/**
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4458
|
+
/** Build the shared request body from a TTS config (new fields + legacy). */
|
|
4459
|
+
buildRequestBody(ttsConfig) {
|
|
4460
|
+
const model = ttsConfig.model || this.config.defaultTTSModel || 'default-tts-model';
|
|
4461
|
+
const body = { model, text: ttsConfig.text };
|
|
4462
|
+
if (ttsConfig.voice !== undefined)
|
|
4463
|
+
body.voice = ttsConfig.voice;
|
|
4464
|
+
if (ttsConfig.voiceMix !== undefined)
|
|
4465
|
+
body.voice_mix = ttsConfig.voiceMix;
|
|
4466
|
+
if (ttsConfig.voiceSettings !== undefined) {
|
|
4467
|
+
body.voice_settings = ttsConfig.voiceSettings;
|
|
4468
|
+
}
|
|
4469
|
+
if (ttsConfig.outputFormat !== undefined) {
|
|
4470
|
+
body.output_format = ttsConfig.outputFormat;
|
|
4471
|
+
}
|
|
4472
|
+
if (ttsConfig.language !== undefined)
|
|
4473
|
+
body.language = ttsConfig.language;
|
|
4474
|
+
if (ttsConfig.providerOptions !== undefined) {
|
|
4475
|
+
body.provider_options = ttsConfig.providerOptions;
|
|
4476
|
+
}
|
|
4477
|
+
return body;
|
|
4478
|
+
}
|
|
4479
|
+
/** POST to a TTS endpoint; throws a PlayKitError on a non-ok response. */
|
|
4480
|
+
async post(endpoint, body) {
|
|
4438
4481
|
await this.authManager.ensureValidToken();
|
|
4439
4482
|
const token = this.authManager.getToken();
|
|
4440
4483
|
if (!token) {
|
|
4441
4484
|
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
4442
4485
|
}
|
|
4443
|
-
const
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
}
|
|
4462
|
-
if (ttsConfig.emotion !== undefined) {
|
|
4463
|
-
requestBody.emotion = ttsConfig.emotion;
|
|
4464
|
-
}
|
|
4465
|
-
if (ttsConfig.languageBoost !== undefined) {
|
|
4466
|
-
requestBody.language_boost = ttsConfig.languageBoost;
|
|
4467
|
-
}
|
|
4468
|
-
if (ttsConfig.format !== undefined) {
|
|
4469
|
-
requestBody.response_format = ttsConfig.format;
|
|
4470
|
-
}
|
|
4471
|
-
if (ttsConfig.voiceSetting !== undefined) {
|
|
4472
|
-
requestBody.voice_setting = ttsConfig.voiceSetting;
|
|
4486
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
4487
|
+
method: 'POST',
|
|
4488
|
+
headers: Object.assign({ Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
4489
|
+
body: JSON.stringify(body),
|
|
4490
|
+
});
|
|
4491
|
+
if (!response.ok) {
|
|
4492
|
+
const error = await response
|
|
4493
|
+
.json()
|
|
4494
|
+
.catch(() => ({ message: 'Speech synthesis failed' }));
|
|
4495
|
+
const playKitError = new PlayKitError(error.message || 'Speech synthesis failed', error.code, response.status);
|
|
4496
|
+
if (error.code === 'INSUFFICIENT_CREDITS' ||
|
|
4497
|
+
error.code === 'PLAYER_INSUFFICIENT_CREDIT' ||
|
|
4498
|
+
response.status === 402) {
|
|
4499
|
+
if (this.playerClient) {
|
|
4500
|
+
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
throw playKitError;
|
|
4473
4504
|
}
|
|
4474
|
-
|
|
4475
|
-
|
|
4505
|
+
return response;
|
|
4506
|
+
}
|
|
4507
|
+
checkBalanceAfter() {
|
|
4508
|
+
if (this.playerClient) {
|
|
4509
|
+
this.playerClient.checkBalanceAfterApiCall().catch(() => {
|
|
4510
|
+
/* silently fail */
|
|
4511
|
+
});
|
|
4476
4512
|
}
|
|
4513
|
+
}
|
|
4514
|
+
/**
|
|
4515
|
+
* Synthesize text into speech audio (raw bytes).
|
|
4516
|
+
*/
|
|
4517
|
+
async synthesize(ttsConfig) {
|
|
4518
|
+
const endpoint = `/ai/${this.config.gameId}/v2/audio/speech`;
|
|
4477
4519
|
try {
|
|
4478
|
-
const response = await
|
|
4479
|
-
method: 'POST',
|
|
4480
|
-
headers: Object.assign({ Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
4481
|
-
body: JSON.stringify(requestBody),
|
|
4482
|
-
});
|
|
4483
|
-
if (!response.ok) {
|
|
4484
|
-
const error = await response.json().catch(() => ({ message: 'Speech synthesis failed' }));
|
|
4485
|
-
const playKitError = new PlayKitError(error.message || 'Speech synthesis failed', error.code, response.status);
|
|
4486
|
-
// Check for insufficient credits error
|
|
4487
|
-
if (error.code === 'INSUFFICIENT_CREDITS' ||
|
|
4488
|
-
error.code === 'PLAYER_INSUFFICIENT_CREDIT' ||
|
|
4489
|
-
response.status === 402) {
|
|
4490
|
-
if (this.playerClient) {
|
|
4491
|
-
await this.playerClient.handleInsufficientCredits(playKitError);
|
|
4492
|
-
}
|
|
4493
|
-
}
|
|
4494
|
-
throw playKitError;
|
|
4495
|
-
}
|
|
4520
|
+
const response = await this.post(endpoint, this.buildRequestBody(ttsConfig));
|
|
4496
4521
|
// SUCCESS: response is raw audio bytes, NOT JSON.
|
|
4497
4522
|
const audio = await response.arrayBuffer();
|
|
4498
4523
|
const contentType = response.headers.get('Content-Type');
|
|
@@ -4500,24 +4525,66 @@ class TTSProvider {
|
|
|
4500
4525
|
const audioLengthHeader = response.headers.get('X-Audio-Length-Ms');
|
|
4501
4526
|
const result = {
|
|
4502
4527
|
audio,
|
|
4503
|
-
format: contentType ||
|
|
4528
|
+
format: contentType || 'mp3',
|
|
4504
4529
|
usageCharacters: Number(usageHeader) || 0,
|
|
4505
4530
|
};
|
|
4506
4531
|
if (audioLengthHeader !== null) {
|
|
4507
4532
|
result.audioLengthMs = Number(audioLengthHeader) || 0;
|
|
4508
4533
|
}
|
|
4509
|
-
|
|
4510
|
-
if (this.playerClient) {
|
|
4511
|
-
this.playerClient.checkBalanceAfterApiCall().catch(() => {
|
|
4512
|
-
// Silently fail
|
|
4513
|
-
});
|
|
4514
|
-
}
|
|
4534
|
+
this.checkBalanceAfter();
|
|
4515
4535
|
return result;
|
|
4516
4536
|
}
|
|
4517
4537
|
catch (error) {
|
|
4518
|
-
if (error instanceof PlayKitError)
|
|
4538
|
+
if (error instanceof PlayKitError)
|
|
4519
4539
|
throw error;
|
|
4540
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
/**
|
|
4544
|
+
* Synthesize text into speech AND return timestamp alignment. Hits the
|
|
4545
|
+
* `speech-with-timestamps` variant, whose success response is a JSON envelope
|
|
4546
|
+
* (base64 audio + alignment), so it is parsed as JSON — not raw bytes.
|
|
4547
|
+
*/
|
|
4548
|
+
async synthesizeWithTimestamps(ttsConfig) {
|
|
4549
|
+
const endpoint = `/ai/${this.config.gameId}/v2/audio/speech-with-timestamps`;
|
|
4550
|
+
const body = this.buildRequestBody(ttsConfig);
|
|
4551
|
+
if (ttsConfig.granularity !== undefined) {
|
|
4552
|
+
body.subtitle_type = ttsConfig.granularity;
|
|
4553
|
+
}
|
|
4554
|
+
try {
|
|
4555
|
+
const response = await this.post(endpoint, body);
|
|
4556
|
+
const json = (await response.json());
|
|
4557
|
+
let alignment = null;
|
|
4558
|
+
if (json.alignment && Array.isArray(json.alignment.items)) {
|
|
4559
|
+
alignment = {
|
|
4560
|
+
granularity: json.alignment.granularity || 'word',
|
|
4561
|
+
items: json.alignment.items.map((it) => {
|
|
4562
|
+
var _a, _b, _c;
|
|
4563
|
+
return ({
|
|
4564
|
+
text: (_a = it.text) !== null && _a !== void 0 ? _a : '',
|
|
4565
|
+
startMs: (_b = it.start_ms) !== null && _b !== void 0 ? _b : 0,
|
|
4566
|
+
endMs: (_c = it.end_ms) !== null && _c !== void 0 ? _c : 0,
|
|
4567
|
+
textStart: it.text_start,
|
|
4568
|
+
textEnd: it.text_end,
|
|
4569
|
+
});
|
|
4570
|
+
}),
|
|
4571
|
+
};
|
|
4572
|
+
}
|
|
4573
|
+
const result = {
|
|
4574
|
+
audio: base64ToArrayBuffer(json.audio_base64),
|
|
4575
|
+
format: json.format || 'mp3',
|
|
4576
|
+
usageCharacters: Number(json.usage_characters) || 0,
|
|
4577
|
+
alignment,
|
|
4578
|
+
};
|
|
4579
|
+
if (json.audio_length_ms != null) {
|
|
4580
|
+
result.audioLengthMs = Number(json.audio_length_ms) || 0;
|
|
4520
4581
|
}
|
|
4582
|
+
this.checkBalanceAfter();
|
|
4583
|
+
return result;
|
|
4584
|
+
}
|
|
4585
|
+
catch (error) {
|
|
4586
|
+
if (error instanceof PlayKitError)
|
|
4587
|
+
throw error;
|
|
4521
4588
|
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4522
4589
|
}
|
|
4523
4590
|
}
|
|
@@ -4601,6 +4668,7 @@ function createDecoder() {
|
|
|
4601
4668
|
class StreamParser {
|
|
4602
4669
|
/**
|
|
4603
4670
|
* Parse SSE stream using ReadableStream
|
|
4671
|
+
* Yields typed parts so callers can separate text from reasoning.
|
|
4604
4672
|
*/
|
|
4605
4673
|
static parseStream(reader) {
|
|
4606
4674
|
return __asyncGenerator(this, arguments, function* parseStream_1() {
|
|
@@ -4631,9 +4699,9 @@ class StreamParser {
|
|
|
4631
4699
|
const data = trimmed.substring(6); // Remove 'data: ' prefix
|
|
4632
4700
|
try {
|
|
4633
4701
|
const parsed = JSON.parse(data);
|
|
4634
|
-
const
|
|
4635
|
-
if (
|
|
4636
|
-
yield yield __await(
|
|
4702
|
+
const part = this.extractPartFromChunk(parsed);
|
|
4703
|
+
if (part) {
|
|
4704
|
+
yield yield __await(part);
|
|
4637
4705
|
}
|
|
4638
4706
|
// Stream termination events
|
|
4639
4707
|
if (parsed.type === 'done' || parsed.type === 'finish' || parsed.finish_reason) {
|
|
@@ -4650,7 +4718,7 @@ class StreamParser {
|
|
|
4650
4718
|
}
|
|
4651
4719
|
catch (error) {
|
|
4652
4720
|
// If JSON parse fails, treat as plain text
|
|
4653
|
-
yield yield __await(data);
|
|
4721
|
+
yield yield __await({ kind: 'text', delta: data });
|
|
4654
4722
|
}
|
|
4655
4723
|
}
|
|
4656
4724
|
}
|
|
@@ -4662,22 +4730,33 @@ class StreamParser {
|
|
|
4662
4730
|
});
|
|
4663
4731
|
}
|
|
4664
4732
|
/**
|
|
4665
|
-
* Extract text from a stream chunk
|
|
4666
|
-
* Supports multiple formats (UI Message Stream and OpenAI)
|
|
4733
|
+
* Extract a typed part (text or reasoning) from a stream chunk
|
|
4734
|
+
* Supports multiple formats (UI Message Stream and OpenAI).
|
|
4735
|
+
* Reasoning is detected before the generic text fallback so thinking
|
|
4736
|
+
* deltas never leak into the text stream.
|
|
4667
4737
|
*/
|
|
4668
|
-
static
|
|
4669
|
-
var _a, _b;
|
|
4670
|
-
// UI Message Stream
|
|
4738
|
+
static extractPartFromChunk(chunk) {
|
|
4739
|
+
var _a, _b, _c, _d;
|
|
4740
|
+
// UI Message Stream reasoning: { type: "reasoning-delta", delta: "..." }
|
|
4741
|
+
if (chunk.type === 'reasoning-delta' && chunk.delta) {
|
|
4742
|
+
return { kind: 'reasoning', delta: chunk.delta };
|
|
4743
|
+
}
|
|
4744
|
+
// UI Message Stream text: { type: "text-delta", delta: "..." }
|
|
4671
4745
|
if (chunk.type === 'text-delta' && chunk.delta) {
|
|
4672
|
-
return chunk.delta;
|
|
4746
|
+
return { kind: 'text', delta: chunk.delta };
|
|
4747
|
+
}
|
|
4748
|
+
// OpenAI reasoning (defensive): { choices: [{ delta: { reasoning_content: "..." } }] }
|
|
4749
|
+
if (chunk.choices && ((_b = (_a = chunk.choices[0]) === null || _a === void 0 ? void 0 : _a.delta) === null || _b === void 0 ? void 0 : _b.reasoning_content)) {
|
|
4750
|
+
return { kind: 'reasoning', delta: chunk.choices[0].delta.reasoning_content };
|
|
4673
4751
|
}
|
|
4674
|
-
// OpenAI
|
|
4675
|
-
if (chunk.choices && ((
|
|
4676
|
-
return chunk.choices[0].delta.content;
|
|
4752
|
+
// OpenAI text: { choices: [{ delta: { content: "..." } }] }
|
|
4753
|
+
if (chunk.choices && ((_d = (_c = chunk.choices[0]) === null || _c === void 0 ? void 0 : _c.delta) === null || _d === void 0 ? void 0 : _d.content)) {
|
|
4754
|
+
return { kind: 'text', delta: chunk.choices[0].delta.content };
|
|
4677
4755
|
}
|
|
4678
|
-
// Direct delta format
|
|
4756
|
+
// Direct delta format (text)
|
|
4679
4757
|
if (chunk.delta) {
|
|
4680
|
-
|
|
4758
|
+
const text = typeof chunk.delta === 'string' ? chunk.delta : chunk.delta.content || null;
|
|
4759
|
+
return text ? { kind: 'text', delta: text } : null;
|
|
4681
4760
|
}
|
|
4682
4761
|
return null;
|
|
4683
4762
|
}
|
|
@@ -4691,8 +4770,10 @@ class StreamParser {
|
|
|
4691
4770
|
for (var _d = true, _e = __asyncValues(this.parseStream(reader)), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
|
|
4692
4771
|
_c = _f.value;
|
|
4693
4772
|
_d = false;
|
|
4694
|
-
const
|
|
4695
|
-
|
|
4773
|
+
const part = _c;
|
|
4774
|
+
if (part.kind === 'text') {
|
|
4775
|
+
fullText += part.delta;
|
|
4776
|
+
}
|
|
4696
4777
|
}
|
|
4697
4778
|
}
|
|
4698
4779
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
@@ -4706,8 +4787,9 @@ class StreamParser {
|
|
|
4706
4787
|
}
|
|
4707
4788
|
/**
|
|
4708
4789
|
* Stream with callbacks
|
|
4790
|
+
* Text deltas go to onChunk; reasoning (thinking) deltas go to onReasoning.
|
|
4709
4791
|
*/
|
|
4710
|
-
static async streamWithCallbacks(reader, onChunk, onComplete, onError) {
|
|
4792
|
+
static async streamWithCallbacks(reader, onChunk, onComplete, onError, onReasoning) {
|
|
4711
4793
|
var _a, e_2, _b, _c;
|
|
4712
4794
|
let fullText = '';
|
|
4713
4795
|
try {
|
|
@@ -4715,9 +4797,15 @@ class StreamParser {
|
|
|
4715
4797
|
for (var _d = true, _e = __asyncValues(this.parseStream(reader)), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
|
|
4716
4798
|
_c = _f.value;
|
|
4717
4799
|
_d = false;
|
|
4718
|
-
const
|
|
4719
|
-
|
|
4720
|
-
|
|
4800
|
+
const part = _c;
|
|
4801
|
+
if (part.kind === 'reasoning') {
|
|
4802
|
+
if (onReasoning) {
|
|
4803
|
+
onReasoning(part.delta);
|
|
4804
|
+
}
|
|
4805
|
+
continue;
|
|
4806
|
+
}
|
|
4807
|
+
fullText += part.delta;
|
|
4808
|
+
onChunk(part.delta);
|
|
4721
4809
|
}
|
|
4722
4810
|
}
|
|
4723
4811
|
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
@@ -4818,6 +4906,7 @@ class ChatClient {
|
|
|
4818
4906
|
: undefined,
|
|
4819
4907
|
id: response.id,
|
|
4820
4908
|
created: response.created,
|
|
4909
|
+
reasoning: choice.message.reasoning_content,
|
|
4821
4910
|
};
|
|
4822
4911
|
}
|
|
4823
4912
|
/**
|
|
@@ -4826,7 +4915,7 @@ class ChatClient {
|
|
|
4826
4915
|
async textGenerationStream(config) {
|
|
4827
4916
|
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
4828
4917
|
const reader = await this.provider.chatCompletionStream(chatConfig);
|
|
4829
|
-
await StreamParser.streamWithCallbacks(reader, config.onChunk, config.onComplete, config.onError);
|
|
4918
|
+
await StreamParser.streamWithCallbacks(reader, config.onChunk, config.onComplete, config.onError, config.onReasoning);
|
|
4830
4919
|
}
|
|
4831
4920
|
// ===== Structured Output Generation =====
|
|
4832
4921
|
/**
|
|
@@ -4984,6 +5073,7 @@ class ChatClient {
|
|
|
4984
5073
|
id: response.id,
|
|
4985
5074
|
created: response.created,
|
|
4986
5075
|
tool_calls: choice.message.tool_calls,
|
|
5076
|
+
reasoning: choice.message.reasoning_content,
|
|
4987
5077
|
};
|
|
4988
5078
|
}
|
|
4989
5079
|
/**
|
|
@@ -4994,6 +5084,7 @@ class ChatClient {
|
|
|
4994
5084
|
const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
|
|
4995
5085
|
const reader = await this.provider.chatCompletionWithToolsStream(chatConfig);
|
|
4996
5086
|
let fullContent = '';
|
|
5087
|
+
let fullReasoning = '';
|
|
4997
5088
|
let toolCalls = [];
|
|
4998
5089
|
await StreamParser.streamWithCallbacks(reader, (chunk) => {
|
|
4999
5090
|
fullContent += chunk;
|
|
@@ -5006,9 +5097,14 @@ class ChatClient {
|
|
|
5006
5097
|
model: chatConfig.model || this.model,
|
|
5007
5098
|
finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
|
|
5008
5099
|
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
5100
|
+
reasoning: fullReasoning || undefined,
|
|
5009
5101
|
});
|
|
5010
5102
|
}
|
|
5011
|
-
}, config.onError)
|
|
5103
|
+
}, config.onError, (chunk) => {
|
|
5104
|
+
var _a;
|
|
5105
|
+
fullReasoning += chunk;
|
|
5106
|
+
(_a = config.onReasoning) === null || _a === void 0 ? void 0 : _a.call(config, chunk);
|
|
5107
|
+
});
|
|
5012
5108
|
}
|
|
5013
5109
|
}
|
|
5014
5110
|
|
|
@@ -5236,6 +5332,14 @@ class TTSClient {
|
|
|
5236
5332
|
async synthesize(config) {
|
|
5237
5333
|
return this.provider.synthesize(Object.assign(Object.assign({}, config), { model: config.model || this.model }));
|
|
5238
5334
|
}
|
|
5335
|
+
/**
|
|
5336
|
+
* Synthesize text into speech AND return timestamp alignment (word/sentence
|
|
5337
|
+
* timings). Returns the audio bytes plus an `alignment` object.
|
|
5338
|
+
* @param config - TTS configuration; `granularity` defaults to 'word'.
|
|
5339
|
+
*/
|
|
5340
|
+
async synthesizeWithTimestamps(config) {
|
|
5341
|
+
return this.provider.synthesizeWithTimestamps(Object.assign(Object.assign({}, config), { model: config.model || this.model }));
|
|
5342
|
+
}
|
|
5239
5343
|
/**
|
|
5240
5344
|
* Synthesize text into speech and return it as a Blob (browser-friendly)
|
|
5241
5345
|
* @param config - Full TTS configuration
|