Input mode determines one thing: whether your application can keep sending messages to the Agent after a task starts.
It does not distinguish between text, images, or other message content, and it does not determine whether responses are displayed incrementally. With either input mode, the SDK returns the Agent's responses as a message stream. To process those responses, see Streaming Output.
Qoder Agent SDK provides two input modes:
Choose between them by answering one question: will your application need to send more messages after the task starts?
Passing a string to
Single-message input does not disable tool approval. If the Agent needs to run a tool that has not been authorized,
Streaming input lets your application keep sending messages after a task starts. In addition to multi-turn chat, it can supply new information, redirect a running task, or queue a message for later.
The recommended interface differs by SDK:
For TypeScript message fields, see
Python
Use this form only for messages prepared in advance. It cannot choose the next message from content the Agent has just returned, and it cannot call
You can send another message while the Agent is responding.
Messages with the same priority are processed in send order. Use
Sometimes you only want to provide background information without asking the Agent to respond immediately. Set
Call
To cancel a message that has not started, first give it a UUID that is unique within the session. TypeScript uses the message's
Cancellation returns
You cannot send another message after the session closes.
| Input mode | TypeScript | Python | When to use it |
|---|---|---|---|
| Single-message input | query({ prompt: string }) | query(prompt=str) | One-off tasks, batch jobs, and CI scripts |
| Streaming input | query({ prompt: AsyncIterable<SDKUserMessage> }) | QoderSDKClient is recommended; a predetermined message stream can also be passed to query() | Chat interfaces, multi-message sessions, and tasks that need additional or revised instructions while running |
- No. Use single-message input.
- Yes. For example, the user may follow up, or the application may choose the next step based on the Agent's response. Use streaming input.
Single-message input
Passing a string to query() starts an independent task. After the task starts, you cannot append another user message to that call. The SDK ends the session when the task completes.
canUseTool / can_use_tool can still ask the user. You do not need to turn prompt into a message stream for that purpose. See Approval and User Input.
Streaming input
Streaming input lets your application keep sending messages after a task starts. In addition to multi-turn chat, it can supply new information, redirect a running task, or queue a message for later.
The recommended interface differs by SDK:
- TypeScript: pass an
AsyncIterable<SDKUserMessage>toquery(). The async iterator can continue toyielduser messages supplied by a chat UI, message queue, or another event source. - Python: use
QoderSDKClientto keep the session open. Callclient.query(...)to send a new message, then useclient.receive_response()to receive that turn's response.
Multi-message session
SDKUserMessage. In Python, each receive_response() call receives one turn. After receiving a ResultMessage, you can send the next message.
Python async message stream boundary
Python query() also accepts AsyncIterable[dict[str, Any]]. If every message is known before the task starts, you can send them sequentially this way. The following fragment only shows the core async-message-stream pattern; see the complete example above for the creation of query and options:
Python
interrupt() or cancel a queued message. Interactive applications such as chat interfaces should use QoderSDKClient.
Add input while the Agent is running
You can send another message while the Agent is responding. priority determines when the Agent processes it:
| Value | Behavior |
|---|---|
now | Stop the current response and process this message immediately |
next | Default; process the message at the next suitable opportunity |
later | Wait until the current response finishes |
priority: 'now' to redirect the current work immediately. If you only want to stop the current response without sending a new message, use Interrupt the current response.
Place the following snippets inside the TypeScript message generator or connected Python client session shown above:
Add context without triggering a response
Sometimes you only want to provide background information without asking the Agent to respond immediately. Set shouldQuery: false in TypeScript or should_query=False in Python. The message is still added to the conversation, and priority determines when it takes effect.
Interrupt the current response
Call interrupt() to stop the Agent's current response without ending the session. You can continue sending messages afterward. In TypeScript, call it on the object returned by query(); Python requires QoderSDKClient.
interrupt() does not remove messages waiting in the queue. Cancel any queued message that is no longer needed. To end the entire session, call a close method or leave the async with block.
Cancel a queued message
To cancel a message that has not started, first give it a UUID that is unique within the session. TypeScript uses the message's uuid field; Python uses the message_uuid argument:
The following fragments only show the cancellation operation and assume that q / client and the corresponding message UUID have already been created:
true / True when successful and false / False when the message does not exist or has already started. A message without a UUID cannot be cancelled individually. Do not reuse a UUID within the same session.
End input and close the session
- TypeScript: the SDK ends a string-prompt session when the task finishes. With an async message stream, completion of the iterator means no more messages will be sent. To close the entire session early, use
AbortControlleror callq.close(). - Python: one-off
query()calls end automatically. WithQoderSDKClient, useasync withto connect and disconnect automatically, or callconnect()/disconnect()manually.
messages(), and options definitions from the earlier examples: