Use conversations for most application flows. The
conversation API manages threads, parent messages, durable turns, event replay, cancellation, and final-response
fallback behavior for you.
Use the direct API when you need to build the Agent API request body yourself, choose a wire-level response mode,
manage thread and run IDs directly, or create and update saved agent objects.
Use background mode when work might outlive one HTTP request or client connection. If you are using the high-level
conversation API, every conversation.send() already starts durable server-side work and returns a Turn.
Use the threads resource only when you need to manage thread_id and parent_message_id yourself. For most
multi-turn application flows, use client.conversations instead.
An agent object is a Snowflake object created with CREATE AGENT. It stores an agent
specification under a fully qualified name so you can reuse governed tools, resources, and instructions without sending
the full configuration on every request.
Use a saved agent object through the direct API when you need explicit wire-level controls. For the normal
conversation path, select the saved agent object in conversation.send(). See
Conversations.
Feedback is available for saved agent objects. The feedback request_id is the HTTP request ID, not the run ID.
if (!answer.requestId) {
thrownewError("The response did not include a request ID.");
}
awaitapi.feedback.send(target, {
request_id: answer.requestId,
positive: true,
});
if answer.request_id isNone:
raiseRuntimeError("The response did not include a request ID.")
api.feedback.send(
target={"database": "ANALYTICS", "schema": "PUBLIC", "name": "SALES_AGENT"},
request_id=answer.request_id,
positive=True,
feedback_message="Helpful answer.",
categories=["helpful"],
)
Use the direct coding-agent resource when you need the Agent API response shape with the coding-agent toolset attached.
For the bundled Cortex Code session API with query() and long-lived local sessions, see
Cortex Code.
always_allow automatically approves coding-agent tool operations that would otherwise require approval, including
destructive-looking shell commands. Use it only when your application intentionally trusts the input source and scopes
workspace mounts, stages, credentials, and network access for that workload. Use an approval-based permission policy
when a person or application approval flow must inspect tool requests before they run.
For approval-based flows, set permissionPolicy or permission_policy to always_ask and stream the run. When a
response.tool_use event includes permission options, show those options to the approver. Send the selected option
back as a permission_decision content item in a follow-up request.
The following example starts a coding-agent run, captures the approval request, sends Allow this command on the same
thread, and waits for the continued response.
import {
CortexAgentClient,
typeAgentResponseView,
typeAsyncRun,
typeServerSentEvent,
} from"@snowflake/cortex-agent-sdk/api";
constapi:CortexAgentClient=newCortexAgentClient({
account: process.env.SNOWFLAKE_ACCOUNT!,
auth: process.env.SNOWFLAKE_PAT!,
});
constprompt="Run this exact bash command and report the stdout: "+"rm -rf /tmp/cortex-agent-sdk-permission-example-does-not-exist && echo permission-example-ok";
functiongetToolUseId(event:ServerSentEvent):string {
constid= (eventas { tool_use_id?:unknown }).tool_use_id;
if (typeofid!=="string") thrownewError("Permission event missing tool_use_id.");
returnid;
}
constthread=awaitapi.threads.create({});
constthreadId=String(thread.responseBody.thread_id);
constapprovalRun:AsyncRun=awaitapi.codingAgent.run({
thread_id: threadId,
parent_message_id: 0,
messages: [{ role: "user", content: [{ type: "text", text: prompt }] }],
permissionPolicy: "always_ask",
models: { orchestration: "claude-sonnet-4-5" },
stream: false,
background: true,
});
letpermissionEvent:ServerSentEvent|undefined;
forawait (consteventofapprovalRun.events()) {
if (event.event==="response.tool_use"&&"permission"inevent) {
permissionEvent=event;
}
}
constapprovalResponse:AgentResponseView=awaitapprovalRun.result();
if (!permissionEvent) thrownewError("The run did not request permission.");
if (!approvalResponse.messageId) thrownewError("The approval response did not include a message id.");
constcontinuedRun:AsyncRun=awaitapi.codingAgent.run({
thread_id: threadId,
parent_message_id: approvalResponse.messageId,
messages: [
{
role: "user",
content: [
{
type: "permission_decision",
permission_decision: {
tool_use_id: getToolUseId(permissionEvent),
decision: "Allow this command",
},
},
],
},
],
permissionPolicy: "always_ask",
models: { orchestration: "claude-sonnet-4-5" },
stream: false,
background: true,
});
constcontinuedResponse=awaitcontinuedRun.result();
console.log(continuedResponse.text);
import os
from cortex_agent_sdk.api import AgentEvent, CortexAgentClient
api: CortexAgentClient = CortexAgentClient(
account=os.environ["SNOWFLAKE_ACCOUNT"],
auth=os.environ["SNOWFLAKE_PAT"],
)
prompt = (
"Run this exact bash command and report the stdout: ""rm -rf /tmp/cortex-agent-sdk-permission-example-does-not-exist && echo permission-example-ok"
)
defget_tool_use_id(event: AgentEvent) -> str:
value = event.get("tool_use_id")
ifnotisinstance(value, str):
raiseRuntimeError("Permission event missing tool_use_id")
return value
thread = api.threads.create()
thread_id =str(thread["thread_id"])
approval_run = api.coding_agent.run(
{
"thread_id": thread_id,
"parent_message_id": 0,
"messages": [{"role": "user", "content": [{"type": "text", "text": prompt}]}],
"permission_policy": "always_ask",
"models": {"orchestration": "claude-sonnet-4-5"},
"stream": False,
"background": True,
}
)
permission_event: AgentEvent |None=Nonefor event in api.runs.stream(approval_run.run_id):
if event.get("event") =="response.tool_use"and"permission"in event:
permission_event = event
approval_response = approval_run.wait()
if permission_event isNone:
raiseRuntimeError("The run did not request permission")
if approval_response.message_id isNone:
raiseRuntimeError("The approval response did not include a message id")
continued_run = api.coding_agent.run(
{
"thread_id": thread_id,
"parent_message_id": approval_response.message_id,
"messages": [
{
"role": "user",
"content": [
{
"type": "permission_decision",
"permission_decision": {
"tool_use_id": get_tool_use_id(permission_event),
"decision": "Allow this command",
},
}
],
}
],
"permission_policy": "always_ask",
"models": {"orchestration": "claude-sonnet-4-5"},
"stream": False,
"background": True,
}
)
continued_response = continued_run.wait()
print(continued_response.text)
Where your configuration of Cortex Code uses a model provided on the
Model and Service Pass-Through Terms,
your use of that model is further subject to the terms for that model on that page.
The data classification of inputs and outputs are as set forth in the following table.