How to Enable and Configure Thinking Capabilities for LLM Models in OpenMAIC

OpenMAIC automatically activates thinking capabilities when your LLM provider emits reasoning parts, which are mapped through createPartMapper in lib/agent/runtime/stream-fn.ts and rendered via the ThinkingBarState component.

OpenMAIC treats a model's reasoning process as a separate content stream called thinking, providing real-time visibility into the LLM's internal deliberation. Unlike static feature toggles, thinking capabilities require no manual activation; they engage automatically when you configure a provider that streams reasoning deltas. This guide explains the three-layer architecture—stream mapping, state management, and UI rendering—and provides the exact configuration steps to integrate thinking into your workspace.

Understanding the Thinking Architecture

OpenMAIC implements thinking capabilities through a three-tier pipeline that transforms raw provider streams into visible UI elements.

Stream Function Mapping

At the ingestion layer, the createPartMapper function in lib/agent/runtime/stream-fn.ts intercepts AI-SDK v6 parts such as reasoning-delta, reasoning-start, and reasoning-end. According to the OpenMAIC source code, this mapper translates provider-specific reasoning events into internal thinking events (thinking_start, thinking_delta, thinking_end) between lines 63-66 and 202-215, while isolating the final textual answer into a distinct content block.

State Management

The mapped events fold into the workbench state at state.chat. When the first reasoning part arrives, OpenMAIC instantiates a thinking node with kind: 'thinking'. Subsequent deltas update this node until a thinking_end event fires, at which point the node closes and its total duration is calculated from the attached timestamps.

UI Rendering

The ThinkingBarState component located in components/workbench/chat/thinking-bar-state.ts consumes the node’s streaming flag and optional duration field. While the model deliberates, the bar displays "思考中…" (thinking…); upon completion, it shows "已思考 ". This component is exercised by the test suite in tests/workbench/thinking-stream-seam.test.ts (lines 53-67), ensuring the thinking bar appears before the assistant message finalizes.

Enabling Thinking Capabilities

Thinking is not a binary toggle. It activates automatically when your chosen LLM model streams reasoning parts. Follow these steps to ensure your provider emits the necessary events.

Select a Compatible Provider

Choose an LLM provider that supports the reasoning channel. Compatible options include:

  • Google Gemini (gemini-1.5-flash)
  • Anthropic Claude (claude-3-haiku)
  • OpenAI models configured with response_format: {type: "json_object"} and stream_options: {include_reasoning: true}

These providers emit reasoning-* parts that createPartMapper recognizes and translates.

Configure Provider Options

Instantiate your LLM connector with provider-specific reasoning flags. In your workspace entry point (such as app/workspace/page.tsx), pass the appropriate options to createCallLlmStreamFn:

import { createCallLlmStreamFn } from '@/lib/agent/runtime/stream-fn';

const streamFn = createCallLlmStreamFn({
  model: 'gemini-1.5-flash',
  // Requests the reasoning channel from the provider
  extraProviderOptions: { includeReasoning: true },
});

When you invoke the session, the connector forwards the reasoning flag to the underlying SDK, ensuring the stream contains the required reasoning-* parts:

await session.run({
  messages: [{ role: 'user', content: 'Explain the algorithm step by step.' }],
  streamFn,
});

Verify UI Activation

The UI reads state.thinkingKey, which is set automatically when a thinking_start event arrives. No additional code is required for standard operation. However, for debugging purposes, you can force the thinking bar to appear by manually setting state.thinkingKey = Symbol(); in a custom hook, guaranteeing visibility even if the provider fails to emit reasoning parts.

Configuring the Thinking Display

Once thinking is active, you can customize how duration appears in the interface.

Customizing Duration Text

The display logic resides in the helper functions within components/workbench/chat/thinking-bar-state.ts. To modify the label or localization, edit the thinkingBarSummary function:

export const thinkingBarSummary = ({ streaming, duration }: { streaming: boolean; duration?: string }) =>
  streaming ? '思考中…' : `已思考${duration ? ` ${duration}` : ''}`;

Adjust the string literals or implement internationalization logic as needed. The duration calculation itself occurs in stream-fn.ts around line 2062, where timestamps from thinking_start and thinking_end events determine the elapsed time.

Complete Implementation Example

Combine provider selection, stream configuration, and optional UI customization in a single implementation:

// lib/agent/config.ts
import { createCallLlmStreamFn } from '@/lib/agent/runtime/stream-fn';

export function initializeThinkingStream() {
  return createCallLlmStreamFn({
    model: 'gemini-1.5-flash',
    extraProviderOptions: { includeReasoning: true },
  });
}
// components/CustomThinkingBar.tsx
import { thinkingBarSummary } from '@/components/workbench/chat/thinking-bar-state';

interface ThinkingBarProps {
  streaming: boolean;
  duration?: string;
}

export function CustomThinkingBar({ streaming, duration }: ThinkingBarProps) {
  return (
    <span className="my-thinking-indicator">
      {thinkingBarSummary({ streaming, duration })}
    </span>
  );
}

The ThinkingBarState component automatically manages the rendering lifecycle according to the events processed in lib/agent/runtime/stream-fn.ts.

Key Files and References

Summary

  • Thinking capabilities activate automatically when you use a provider that streams reasoning parts; no manual toggle exists in OpenMAIC.
  • Stream mapping occurs in lib/agent/runtime/stream-fn.ts via createPartMapper, which converts reasoning-delta events into thinking_start, thinking_delta, and thinking_end events.
  • Provider configuration requires passing extraProviderOptions: { includeReasoning: true } (or equivalent) to createCallLlmStreamFn in your workspace initialization.
  • State management creates a kind: 'thinking' node in state.chat that tracks duration from start to end timestamps.
  • UI rendering is handled by ThinkingBarState in components/workbench/chat/thinking-bar-state.ts, displaying real-time status and final duration.

Frequently Asked Questions

Is thinking enabled by default in OpenMAIC?

No explicit enablement is required. Thinking capabilities are automatically available whenever your configured LLM provider emits reasoning parts such as reasoning-delta. If the provider does not support or is not configured to stream reasoning content, the thinking UI will not appear, and the assistant's response will stream as plain text only.

Which LLM providers support thinking capabilities?

OpenMAIC supports any provider that implements AI-SDK v6 reasoning parts. Verified compatible providers include Google Gemini (e.g., gemini-1.5-flash), Anthropic Claude (e.g., claude-3-haiku), and OpenAI models when configured with stream_options: {include_reasoning: true}. The specific option names vary by provider, but all are passed through extraProviderOptions in createCallLlmStreamFn.

How can I customize the thinking duration display format?

Edit the thinkingBarSummary function in components/workbench/chat/thinking-bar-state.ts. This helper receives streaming (boolean) and duration (string) parameters, allowing you to modify the returned string literals or implement localization logic. The underlying duration calculation is performed in stream-fn.ts based on timestamps attached to thinking_start and thinking_end events.

What happens if my model doesn't emit reasoning parts?

If the LLM provider does not stream reasoning-start, reasoning-delta, or reasoning-end parts, the createPartMapper in lib/agent/runtime/stream-fn.ts will never generate thinking events. Consequently, no kind: 'thinking' node is created in state.chat, and the ThinkingBarState UI component remains hidden. The assistant's response will appear as a standard text stream without any thinking indicator.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →