Tool calling
Define tools, validate arguments, execute application functions, and return tool results to DeepSeek automatically through `@orcushq/deepseek`.
Tool calling allows a model to request actions that your application can perform, such as fetching weather information, looking up records, or calling an internal API. You define the available tools and their implementations, then pass them to model.invoke(). The SDK handles the tool-execution loop and returns the model’s final response.
The complete flow is: define a tool → send the prompt and tool definition → validate the requested arguments → execute the registered function → provide its result to the model → receive the final response. Your application implements the actual action; the model does not execute JavaScript functions by itself.
How tool calling works
This integration uses prompt-based tool orchestration and parsed model output. It is not provider-enforced function calling. The SDK handles the orchestration, but tool arguments and model output must still be treated as untrusted input.
Prerequisites
Install the DeepSeek SDK, Zod for runtime argument validation, and dotenv for loading credentials from your .env file.
npm install @orcushq/deepseek zod dotenv1. Configure the client
Create a DeepSeekWeb client using your model and authentication credentials. Both dsSessionId and authorization are required. The SDK does not load environment variables automatically; dotenv/config loads them in this example.
DEEPSEEK_SESSION_ID=your_ds_session_id_valueDEEPSEEK_AUTHORIZATION=your_authorization_valueimport 'dotenv/config'import { z } from 'zod'import { DeepSeekWeb } from '@orcushq/deepseek' const dsSessionId = process.env.DEEPSEEK_SESSION_IDconst authorization = process.env.DEEPSEEK_AUTHORIZATION if (!dsSessionId || !authorization) { throw new Error( 'Missing DeepSeek session or authorization credentials', )} const model = new DeepSeekWeb({ model: 'deepseek-v3', dsSessionId, authorization,})The credential check prevents the example from starting when either value is missing. It does not verify that DeepSeek accepts the credentials or that the account has access to a particular model.
2. Define a tool
A tool definition contains four important parts: name, description, schema, and func. The name identifies the action, the description tells the model when to use it, the Zod schema validates its arguments, and the function implements the action.
const tools = [ { name: 'get_weather', description: 'Get demo weather information for a city. Use this tool when the user asks about the weather.', schema: z.object({ city: z.string().trim().min(1).max(100), }), func: async (input: { city: string }) => { console.log('[Tool executed] get_weather') console.log('City:', input.city) // Demo data, not live weather information. return { city: input.city, temperatureCelsius: 28, condition: 'Partly cloudy', } }, },]Understand the tool definition
- `name` identifies the tool the model is requesting. Your application registers the implementation under this name.
- `description` explains the tool’s purpose and helps the model decide when to request it.
- `schema` defines and validates the expected arguments at runtime. Here,
citymust be a non-empty string with a maximum length of 100 characters. - `func` is the actual application function. The SDK executes it when a valid tool request is selected.
In this example, get_weather returns a fixed demo result. To retrieve real weather information, replace the function body with a call to your weather service and return its result.
3. Send the prompt and tools
Pass the tool definitions through the tools option to model.invoke(). In the example below, the prompt explicitly asks the model to use get_weather for Bengaluru. maxToolIterations limits how many tool-orchestration iterations the SDK can perform; its default is 8.
const response = await model.invoke( 'You must use the get_weather tool to check the weather in Bengaluru. After receiving the tool result, explain the weather to me in one sentence. Do not invent weather information.', { tools, maxToolIterations: 5, },)The SDK handles the orchestration internally. You do not need to manually inspect response.toolCalls, create tool messages, or implement another model-call loop for this standard workflow. A tool may not be called if the model does not request it, so explicit instructions are useful when testing.
4. Understand tool execution
When the model requests get_weather, the SDK validates the provided arguments against the Zod schema and executes the registered func. The function receives the validated city, logs the invocation, and returns a result object. That result is passed back into the model’s orchestration flow so the model can prepare its final response.
// The SDK invokes this function when the tool is requested.func: async (input: { city: string }) => { console.log('[Tool executed] get_weather') console.log('City:', input.city) return { city: input.city, temperatureCelsius: 28, condition: 'Partly cloudy', }}The function’s return value is the tool result, not the final answer shown to the user. The model interprets that result and generates the final response. The tool function can call an API, query a database, or perform another permitted application action.
5. Read the final response
After invoke() completes its tool orchestration, use response.content to read the final generated text. The example also counts actual function executions so you can verify that the tool ran during testing.
console.log('\n--- Final Response ---')console.log(response.content) console.log('\n--- Tool Execution Summary ---')console.log('Tool execution count:', toolExecutionCount)6. Complete end-to-end example
The following single-file example combines client configuration, tool definition, argument validation, automatic tool execution, final response handling, and a basic execution check. Save it as index.ts and run it using your existing TypeScript setup.
import 'dotenv/config'import { z } from 'zod'import { DeepSeekWeb } from '@orcushq/deepseek' const dsSessionId = process.env.DEEPSEEK_SESSION_IDconst authorization = process.env.DEEPSEEK_AUTHORIZATION if (!dsSessionId || !authorization) { throw new Error( 'Missing DEEPSEEK_SESSION_ID or DEEPSEEK_AUTHORIZATION', )} const model = new DeepSeekWeb({ model: 'deepseek-v3', dsSessionId, authorization,}) let toolExecutionCount = 0 const tools = [ { name: 'get_weather', description: 'Get demo weather information for a city. Use this tool when the user asks about the weather.', schema: z.object({ city: z.string().trim().min(1).max(100), }), func: async (input: { city: string }) => { toolExecutionCount++ console.log('\n[Tool executed] get_weather') console.log('City:', input.city) return { city: input.city, temperatureCelsius: 28, condition: 'Partly cloudy', } }, },] try { const response = await model.invoke( 'You must use the get_weather tool to check the weather in Bengaluru. After receiving the tool result, explain the weather to me in one sentence. Do not invent weather information.', { tools, maxToolIterations: 5, }, ) console.log('\n--- Final Response ---') console.log(response.content) console.log('\n--- Tool Execution Summary ---') console.log('Tool execution count:', toolExecutionCount) if (toolExecutionCount === 0) { console.error('Test failed: the tool was not executed.') process.exitCode = 1 } else { console.log('Tool calling execution was confirmed.') }} catch (error) { console.error('\nTool calling test failed:', error) process.exitCode = 1}7. Run and verify the example
Run npm start in your TypeScript test project. A successful test should show the tool execution log, the city passed to the function, the model’s final answer, and a tool execution count greater than zero.
[Tool executed] get_weatherCity: Bengaluru --- Final Response ---Bengaluru is currently 28°C and partly cloudy. --- Tool Execution Summary ---Tool execution count: 1Tool calling execution was confirmed.Interpreting the test result
The expected output demonstrates that the tool function executed and its result was used to generate a final response. The temperature and condition in this example are hard-coded demo data, not actual weather information.
Validation and security
- Treat model-generated tool names and arguments as untrusted input.
- Validate arguments at runtime with the tool’s Zod schema.
- Use an explicit allowlist of registered tools; never execute arbitrary function names supplied by the model.
- Check application-level permissions before accessing private data or performing side effects.
- Apply suitable timeouts and resource limits to external API calls.
- Sanitize errors returned to the model and never expose credentials, environment variables, or sensitive internal details.
- Treat tool results as data rather than trusted instructions.
- Use
maxToolIterationsto limit orchestration and avoid unbounded tool-call loops.
Important limitations
- Tool calling is emulated through prompt instructions and parsed output; it is not equivalent to provider-enforced function calling.
- The model may fail to request a tool or may produce malformed arguments. A successful tool function execution should be verified by the application.
- Tool execution is supported through
invoke(). Non-empty tool definitions passed tostream()orbatch()are unsupported. - The current API does not support
toolChoiceor a workingbindTools()workflow. - The SDK executes registered tool functions, but your application remains responsible for permissions, external service access, and side-effect safety.