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
A Java one-shot query ends after the CLI returns the turn's
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
Java can also start the CLI before user input arrives.
A
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
Java's
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
In Java, after another thread closes the session, a cursor that is reading ends with
| Input mode | TypeScript | Python | Java | When to use it |
|---|---|---|---|---|
| Single-message input | query({ prompt: string }) | query(prompt=str) | client.query(OneShotQueryRequest) | 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() | QoderSession returned by client.openSession(options) | 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.
ResultMessage. Still read the message stream to the end, then close the cursor or the QoderQuery. ResultOutcome.ERROR means the turn failed; the absence of an exception does not mean success.
Single-message input does not disable tool approval. If the Agent needs to run a tool that has not been authorized, 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. - Java: open a
QoderSessionwithclient.openSession(options). Callsession.send(...)to send a new message, then read the reply from the same message cursor; aResultMessagemarks the end of the turn.
Multi-message session
SDKUserMessage. In Python, each receive_response() call receives one turn. After receiving a ResultMessage, you can send the next message.
In Java, each input is a UserInput. Completion of send() only means the input was written to the CLI, not that the reply has finished. A session's message stream can be consumed only once, so reuse the same cursor across turns; closing the cursor also closes the session.
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.
Prestart the CLI (Java)
Java can also start the CLI before user input arrives. client.prepare(options) completes startup, authentication, and initialization without sending input, which removes the startup latency from the first request:
Java
PreparedQuery can be converted only once. After conversion, the new QoderSession or QoderQuery owns the resources; if it is never used, call close() to discard it.
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.
In Java, set the priority with priority(SendPriority.NOW / NEXT / LATER) on UserInput.Builder. The default priority of a Java UserInput is NOW, not next; set it explicitly when you add messages during a run.
Place the following snippets inside the TypeScript message generator, the connected Python client session, or the Java QoderSession 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, should_query=False in Python, or shouldQuery(false) in Java. 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; in Java, call it on QoderQuery or QoderSession.
interrupt() returns InterruptResult. Success only means the CLI accepted the interrupt request; the turn still ends when its ResultMessage arrives.
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. Java does not need you to generate an ID: send with session.submit(input) instead of send(input), and the returned MessageSubmission immediately carries the SDK-assigned MessageId:
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.
In Java, the SDK cancels a message locally if it has not been written to the CLI yet; that message's written() completes with CancellationException, and the session is unaffected. For a message that has started writing, the SDK attempts a remote cancel only when the CLI supports the corresponding capability; otherwise it returns false. Use send() when you only need write confirmation, and submit() when you need the ID before the write.
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. - Java: after reading a one-shot query's stream to the end, close the cursor or the
QoderQuery. Close aQoderSessionwhen you are done with it; to make sure all accepted input reaches the CLI, wait forcompleteInput()first. It rejects further input but does not wait for replies. Closing theQoderClientcascades to every query and session it created.
messages(), and options definitions from the earlier examples:
Close automatically
Close early in response to an external condition
SessionClosedException. Do not call the blocking close() in SDK callbacks or push handlers; use closeAsync() there.
You cannot send another message after the session closes.