Skip to content

Commit

Permalink
feat: add reasoning token support (#4462)
Browse files Browse the repository at this point in the history
Co-authored-by: Lars Grammel <lars.grammel@gmail.com>
  • Loading branch information
shaper and lgrammel authored Jan 22, 2025
1 parent ca1b5cd commit 0a699f1
Show file tree
Hide file tree
Showing 30 changed files with 887 additions and 13 deletions.
9 changes: 9 additions & 0 deletions .changeset/tiny-rice-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@ai-sdk/openai-compatible': patch
'@ai-sdk/deepseek': patch
'@ai-sdk/provider': patch
'@ai-sdk/ui-utils': patch
'ai': patch
---

feat: add reasoning token support
1 change: 1 addition & 0 deletions content/docs/02-foundations/02-providers-and-models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Here are the capabilities of popular models:
| [xAI Grok](/providers/ai-sdk-providers/xai) | `grok-beta` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [xAI Grok](/providers/ai-sdk-providers/xai) | `grok-vision-beta` | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
| [DeepSeek](/providers/ai-sdk-providers/deepseek) | `deepseek-chat` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [DeepSeek](/providers/ai-sdk-providers/deepseek) | `deepseek-reasoner` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.1-8b` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.1-70b` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.3-70b` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
Expand Down
6 changes: 6 additions & 0 deletions content/docs/03-ai-sdk-core/05-generating-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The result object of `generateText` contains several promises that resolve when
- `result.text`: The generated text.
- `result.finishReason`: The reason the model finished generating text.
- `result.usage`: The usage of the model during text generation.
- `result.reasoning`: The reasoning text of the model (only available for some models).

## `streamText`

Expand Down Expand Up @@ -100,6 +101,7 @@ When using `streamText`, you can provide an `onChunk` callback that is triggered
It receives the following chunk types:

- `text-delta`
- `reasoning`
- `tool-call`
- `tool-result`
- `tool-call-streaming-start` (when `experimental_toolCallStreaming` is enabled)
Expand Down Expand Up @@ -170,6 +172,10 @@ for await (const part of result.fullStream) {
// handle text delta here
break;
}
case 'reasoning': {
// handle reasoning here
break;
}
case 'tool-call': {
switch (part.toolName) {
case 'cityAttractions': {
Expand Down
8 changes: 8 additions & 0 deletions content/docs/04-ai-sdk-ui/50-stream-protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ Example: `0:"example"\n`
height={1148}
/>

### Reasoning Part

The reasoning parts are appended to the message as they are received. The reasoning part is available through `reasoning`.

Format: `g:string\n`

Example: `g:"I will open the conversation with witty banter."\n`

### Data Part

The data parts are parsed as JSON and appended to the message as they are received. The data part is available through `data`.
Expand Down
12 changes: 12 additions & 0 deletions content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,12 @@ To see `generateText` in action, check out [these examples](#examples).
type: 'string',
description: 'The generated text by the model.',
},
{
name: 'reasoning',
type: 'string | undefined',
description:
'The reasoning text of the model (only available for some models).',
},
{
name: 'toolCalls',
type: 'array',
Expand Down Expand Up @@ -841,6 +847,12 @@ To see `generateText` in action, check out [these examples](#examples).
type: 'string',
description: 'The generated text by the model.',
},
{
name: 'reasoning',
type: 'string | undefined',
description:
'The reasoning text of the model (only available for some models).',
},
{
name: 'toolCalls',
type: 'array',
Expand Down
43 changes: 43 additions & 0 deletions content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,22 @@ To see `streamText` in action, check out [these examples](#examples).
},
],
},
{
type: 'TextStreamPart',
parameters: [
{
name: 'type',
type: "'reasoning'",
description:
'The type to identify the object as reasoning.',
},
{
name: 'textDelta',
type: 'string',
description: 'The reasoning text delta.',
},
],
},
{
type: 'TextStreamPart',
parameters: [
Expand Down Expand Up @@ -1056,6 +1072,12 @@ To see `streamText` in action, check out [these examples](#examples).
description:
'The full text that has been generated. Resolved when the response is finished.',
},
{
name: 'reasoning',
type: 'Promise<string | undefined>',
description:
'The reasoning text of the model (only available for some models). Resolved when the response is finished.',
},
{
name: 'toolCalls',
type: 'Promise<ToolCall[]>',
Expand Down Expand Up @@ -1156,6 +1178,12 @@ To see `streamText` in action, check out [these examples](#examples).
type: 'string',
description: 'The generated text by the model.',
},
{
name: 'reasoning',
type: 'string | undefined',
description:
'The reasoning text of the model (only available for some models).',
},
{
name: 'toolCalls',
type: 'array',
Expand Down Expand Up @@ -1312,6 +1340,21 @@ To see `streamText` in action, check out [these examples](#examples).
},
],
},
{
type: 'TextStreamPart',
parameters: [
{
name: 'type',
type: "'reasoning'",
description: 'The type to identify the object as reasoning.',
},
{
name: 'textDelta',
type: 'string',
description: 'The reasoning text delta.',
},
],
},
{
type: 'TextStreamPart',
parameters: [
Expand Down
7 changes: 4 additions & 3 deletions content/providers/01-ai-sdk-providers/30-deepseek.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ DeepSeek language models can be used in the `streamText` and `streamUI` function

## Model Capabilities

| Model | Image Input | Object Generation | Tool Usage | Tool Streaming |
| --------------- | ------------------- | ------------------- | ------------------- | ------------------- |
| `deepseek-chat` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| Model | Image Input | Object Generation | Tool Usage | Tool Streaming |
| ------------------- | ------------------- | ------------------- | ------------------- | ------------------- |
| `deepseek-chat` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| `deepseek-reasoner` | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |

<Note>
Please see the [DeepSeek docs](https://api-docs.deepseek.com) for a full list
Expand Down
1 change: 1 addition & 0 deletions content/providers/01-ai-sdk-providers/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Not all providers support all AI SDK features. Here's a quick comparison of the
| [xAI Grok](/providers/ai-sdk-providers/xai) | `grok-beta` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [xAI Grok](/providers/ai-sdk-providers/xai) | `grok-vision-beta` | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
| [DeepSeek](/providers/ai-sdk-providers/deepseek) | `deepseek-chat` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [DeepSeek](/providers/ai-sdk-providers/deepseek) | `deepseek-reasoner` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.1-8b` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Cerebras](/providers/ai-sdk-providers/cerebras) | `llama3.3-70b` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Groq](/providers/ai-sdk-providers/groq) | `llama-3.3-70b-versatile` | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
Expand Down
8 changes: 7 additions & 1 deletion examples/ai-core/src/generate-text/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import 'dotenv/config';

async function main() {
const result = await generateText({
model: deepseek('deepseek-chat'),
model: deepseek('deepseek-reasoner'),
prompt: 'Invent a new holiday and describe its traditions.',
});

console.log('Reasoning:');
console.log(result.reasoning);
console.log();

console.log('Text:');
console.log(result.text);
console.log();

console.log('Token usage:', result.usage);
console.log('Finish reason:', result.finishReason);
}
Expand Down
38 changes: 38 additions & 0 deletions examples/ai-core/src/stream-text/deepseek-fullstream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { deepseek } from '@ai-sdk/deepseek';
import { streamText } from 'ai';
import 'dotenv/config';

async function main() {
const result = streamText({
model: deepseek('deepseek-reasoner'),
prompt: 'Invent a new holiday and describe its traditions.',
});

let enteredReasoning = false;
let enteredText = false;
for await (const part of result.fullStream) {
if (part.type === 'reasoning') {
if (!enteredReasoning) {
enteredReasoning = true;
console.log('\nSTREAMING REASONING:\n');
}
process.stdout.write(part.textDelta);
} else if (part.type === 'text-delta') {
if (!enteredText) {
enteredText = true;
console.log('\nSTREAMING TEXT:\n');
}
process.stdout.write(part.textDelta);
}
}

console.log();
console.log('\nFINAL REASONING:\n', await result.reasoning);
console.log('\nFINAL TEXT:\n', await result.text);

console.log();
console.log('Token usage:', await result.usage);
console.log('Finish reason:', await result.finishReason);
}

main().catch(console.error);
23 changes: 23 additions & 0 deletions examples/ai-core/src/stream-text/deepseek-reasoning-on-chunk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { deepseek } from '@ai-sdk/deepseek';
import { streamText } from 'ai';
import 'dotenv/config';

async function main() {
const result = streamText({
model: deepseek('deepseek-reasoner'),
prompt: 'Invent a new holiday and describe its traditions.',
onChunk({ chunk }) {
if (chunk.type === 'reasoning') {
console.log('reasoning', chunk.textDelta);
}
},
});

// consume stream:
for await (const part of result.fullStream) {
}

console.log('reasoning', await result.reasoning);
}

main().catch(console.error);
2 changes: 1 addition & 1 deletion examples/ai-core/src/stream-text/deepseek.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'dotenv/config';

async function main() {
const result = streamText({
model: deepseek('deepseek-chat'),
model: deepseek('deepseek-reasoner'),
prompt: 'Invent a new holiday and describe its traditions.',
});

Expand Down
Loading

0 comments on commit 0a699f1

Please sign in to comment.