Reasoning
For reasoning models, the SDK also outputs ReasoningPart
:
interface ReasoningPart { type: "reasoning"; /** * The reasoning text content */ text: string; /** * The reasoning internal signature */ signature?: string; /** * The ID of the reasoning part, if applicable */ id?: string;}
pub struct ReasoningPart { /// The reasoning text content. pub text: String, /// The reasoning internal signature #[serde(skip_serializing_if = "Option::is_none")] pub signature: Option<String>, /// The ID of the reasoning part, if applicable #[serde(skip_serializing_if = "Option::is_none")] pub id: Option<String>,}
type ReasoningPart struct { // The reasoning text content Text string `json:"text"` // The reasoning internal signature Signature *string `json:"signature,omitempty"` // The ID of the reasoning part, if applicable. ID *string `json:"id,omitempty"`}
This may enabled by default for supported models, but can be configured using reasoning
input:
interface ReasoningOptions { /** * Whether to enable reasoning output. */ enabled: boolean; /** * Specify the budget tokens for reasoning generation. */ budget_tokens?: number;}
pub struct ReasoningOptions { /// Whether to enable reasoning output. pub enabled: bool, /// Specify the budget tokens for reasoning generation. #[serde(skip_serializing_if = "Option::is_none")] pub budget_tokens: Option<u32>,}
type ReasoningOptions struct { // Whether to enable reasoning output. Enabled bool `json:"enabled"` // Specify the budget tokens for reasoning generation. BudgetTokens *uint32 `json:"budget_tokens,omitempty"`}
Once enabled, the model will output ReasoningPart
s in addition to other parts.
import type { Part } from "@hoangvvo/llm-sdk";import { getModel } from "./get-model.ts";
const model = getModel("openai", "o1");
const response = await model.generate({ messages: [ { role: "user", content: [ { type: "text", text: `A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?`, }, ], }, ], reasoning: { enabled: true, },});
const { reasoningParts, otherParts } = response.content.reduce( (acc, part) => { if (part.type === "reasoning") { acc.reasoningParts.push(part); } else { acc.otherParts.push(part); } return acc; }, { reasoningParts: [] as Part[], otherParts: [] as Part[] },);
console.log("Reasoning");console.dir(reasoningParts, { depth: null });
console.log("\nAnswer");console.dir(otherParts, { depth: null });
use dotenvy::dotenv;use llm_sdk::{LanguageModelInput, Message, Part, ReasoningOptions};
mod common;
#[tokio::main]async fn main() { dotenv().ok();
let model = common::get_model("openai", "o1");
let response = model .generate(LanguageModelInput { messages: vec![ Message::user( vec![Part::text(r"A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?")] ) ], reasoning: Some(ReasoningOptions { enabled: true, ..Default::default() }), ..Default::default() }) .await .unwrap();
let (reasoning_parts, other_parts): (Vec<Part>, Vec<Part>) = response .content .into_iter() .partition(|part| matches!(part, Part::Reasoning { .. })); println!("Reasoning:"); for part in reasoning_parts { println!("{part:#?}"); } println!("\nAnswer:"); for part in other_parts { println!("{part:#?}"); }}
package main
import ( "context" "log"
llmsdk "github.com/hoangvvo/llm-sdk/sdk-go" "github.com/hoangvvo/llm-sdk/sdk-go/examples" "github.com/sanity-io/litter")
func main() { model := examples.GetModel("openai", "o1")
response, err := model.Generate(context.Background(), &llmsdk.LanguageModelInput{ Messages: []llmsdk.Message{ llmsdk.NewUserMessage( llmsdk.NewTextPart(`A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?`), ), }, Reasoning: &llmsdk.ReasoningOptions{ Enabled: true, }, })
if err != nil { log.Fatalf("Generation failed: %v", err) }
var reasoningParts, otherParts []llmsdk.Part for _, part := range response.Content { if part.Type() == llmsdk.PartTypeReasoning { reasoningParts = append(reasoningParts, part) } else { otherParts = append(otherParts, part) } }
log.Println("Reasoning") litter.Dump(reasoningParts)
log.Println("\nAnswer") litter.Dump(otherParts)}
Reasoning parts are also emitted in streaming mode in the form of ReasoningPartDelta
.
interface ReasoningPartDelta { type: "reasoning"; /** * The reasoning text content */ text: string; /** * The reasoning internal signature */ signature?: string; /** * The ID of the reasoning part, if applicable */ id?: string;}
pub struct ReasoningPartDelta { /// The reasoning text content. #[serde(skip_serializing_if = "Option::is_none")] pub text: Option<String>, /// The reasoning internal signature #[serde(skip_serializing_if = "Option::is_none")] pub signature: Option<String>, /// The ID of the reasoning part, if applicable #[serde(skip_serializing_if = "Option::is_none")] pub id: Option<String>,}
type ReasoningPartDelta struct { Text string `json:"text,omitempty"` Signature *string `json:"signature,omitempty"` ID *string `json:"id,omitempty"`}
Accessing reasoning parts in streaming mode like other parts:
import { StreamAccumulator } from "@hoangvvo/llm-sdk";import { getModel } from "./get-model.ts";
const model = getModel("openai", "o1");
const stream = model.stream({ messages: [ { role: "user", content: [ { type: "text", text: `A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?`, }, ], }, ], reasoning: { enabled: true, },});
const accumulator = new StreamAccumulator();
let current = await stream.next();while (!current.done) { if (current.value.delta?.part.type === "reasoning") { console.log("Reasoning:"); console.dir(current.value.delta.part, { depth: null }); } else if (current.value.delta) { console.log("Answer:"); console.dir(current.value.delta.part, { depth: null }); } accumulator.addPartial(current.value); current = await stream.next();}
const finalResponse = accumulator.computeResponse();console.dir(finalResponse, { depth: null });
use dotenvy::dotenv;use futures::StreamExt;use llm_sdk::{LanguageModelInput, Message, Part, PartDelta, ReasoningOptions};
mod common;
#[tokio::main]async fn main() { dotenv().ok();
let model = common::get_model("openai", "o1");
let mut stream = model .stream(LanguageModelInput { messages: vec![ Message::user( vec![Part::text(r"A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?")] ) ], reasoning: Some(ReasoningOptions { enabled: true, ..Default::default() }), ..Default::default() }) .await .unwrap();
while let Some(partial) = stream.next().await { let partial = partial.expect("stream error"); if let Some(delta) = partial.delta { if let PartDelta::Reasoning { .. } = delta.part { println!("Reasoning:"); println!("{delta:#?}"); } else { println!("Answer:"); println!("{delta:#?}"); } } }}
package main
import ( "context" "log"
llmsdk "github.com/hoangvvo/llm-sdk/sdk-go" "github.com/hoangvvo/llm-sdk/sdk-go/examples" "github.com/sanity-io/litter")
func main() { model := examples.GetModel("openai", "o1")
stream, err := model.Stream(context.Background(), &llmsdk.LanguageModelInput{ Messages: []llmsdk.Message{ llmsdk.NewUserMessage( llmsdk.NewTextPart(`A car starts from rest and accelerates at a constant rate of 4 m/s^2 for 10 seconds.1. What is the final velocity of the car after 10 seconds?2. How far does the car travel in those 10 seconds?`), ), }, Reasoning: &llmsdk.ReasoningOptions{ Enabled: true, }, })
if err != nil { log.Fatalf("Generation failed: %v", err) }
for stream.Next() { partial := stream.Current() if partial.Delta.Part.ReasoningPartDelta != nil { log.Println("Reasoning:") litter.Dump(partial.Delta.Part) } else { log.Println("Answer:") litter.Dump(partial.Delta.Part) } }}