Skip to main content
对话与会话

输入模式

输入模式决定的是:任务开始后,你的应用还能不能继续给 Agent 发送消息 它不区分文本、图片等消息内容,也不决定回复是否逐块显示。无论选择哪种输入模式,SDK 都会以消息流返回 Agent 的回复。如何处理回复,见流式输出 Qoder Agent SDK 提供两类输入方式:
输入方式TypeScriptPython什么时候使用
单消息输入query({ prompt: string })query(prompt=str)一次性任务、批处理、CI 脚本
流式输入query({ prompt: AsyncIterable<SDKUserMessage> })推荐使用 QoderSDKClient;预先确定的消息流也可传给 query()聊天界面、多消息会话、运行中追加或调整任务
选择时只需要考虑一个问题:任务开始后,是否还要继续给 Agent 发消息?
  • 不需要。使用单消息输入。
  • 需要。例如用户还会追问,或者应用要根据 Agent 的回复决定下一步。使用流式输入。

单消息输入

把字符串传给 query() 会启动一个独立任务。任务开始后,不能再向这次调用追加用户消息。任务完成后,SDK 自动结束会话。
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

for await (const message of query({
  prompt: '检查当前项目中缺少测试覆盖的函数,并给出报告。',
  options: {
    auth: accessTokenFromEnv(),
    allowedTools: ['Read', 'Glob', 'Grep'],
  },
})) {
  if (message.type === 'result' && message.subtype === 'success') {
    console.log(message.result);
  }
}
单消息输入不影响工具审批。如果 Agent 需要执行尚未获得许可的工具,canUseTool / can_use_tool 仍然可以询问用户。你不需要为此把 prompt 改成消息流。详见审批与用户输入

流式输入

流式输入允许你的应用在任务开始后继续发送消息。除了聊天中的多轮对话,它还可以在任务进行中补充信息、改变执行方向,或安排稍后处理的消息。 两个 SDK 的推荐接口不同:
  • TypeScript:把 AsyncIterable<SDKUserMessage> 传给 query()。它是一个可以持续 yield 用户消息的异步迭代器。聊天 UI、消息队列或其他事件都可以向它提供消息。
  • Python:使用 QoderSDKClient 保持会话。调用 client.query(...) 发送一条新消息,再用 client.receive_response() 接收这一轮的回复。

多消息会话

import {
  accessTokenFromEnv,
  query,
  type SDKUserMessage,
} from '@qoder-ai/qoder-agent-sdk';

async function* messages(): AsyncGenerator<SDKUserMessage> {
  yield {
    type: 'user',
    message: {
      role: 'user',
      content: [{ type: 'text', text: '检查这个代码库中的安全问题。' }],
    },
    parent_tool_use_id: null,
  };

  // 实际应用中,这里可以等待 UI、消息队列或其他外部事件。
  await new Promise((resolve) => setTimeout(resolve, 2_000));

  yield {
    type: 'user',
    message: {
      role: 'user',
      content: [{ type: 'text', text: '完成当前分析后,再生成一份简短报告。' }],
    },
    parent_tool_use_id: null,
    priority: 'later',
  };
}

for await (const message of query({
  prompt: messages(),
  options: {
    auth: accessTokenFromEnv(),
    allowedTools: ['Read', 'Glob', 'Grep'],
  },
})) {
  if (message.type === 'result' && message.subtype === 'success') {
    console.log(message.result);
  }
}
TypeScript 的消息字段见 SDKUserMessage。在 Python 中,每次 receive_response() 接收一轮回复。收到 ResultMessage 后,可以继续发送下一条消息。

Python 异步消息流的边界

Python 的 query() 也接受 AsyncIterable[dict[str, Any]]。如果多条消息在任务开始前就已经确定,可以用这种方式依次发送。下面只展示 Python 异步消息流的核心写法,queryoptions 的创建方式见前面的完整示例:
Python
async def prompts():
    yield {
        "type": "user",
        "message": {"role": "user", "content": "检查认证模块。"},
        "parent_tool_use_id": None,
    }
    yield {
        "type": "user",
        "message": {"role": "user", "content": "然后汇总发现的问题。"},
        "parent_tool_use_id": None,
    }


async for message in query(prompt=prompts(), options=options):
    print(message)
这种写法只适合预先准备好的消息。它不能根据 Agent 刚刚返回的内容决定下一条消息,也不能调用 interrupt() 或取消排队消息。聊天界面等交互式应用应使用 QoderSDKClient

运行中追加输入

Agent 回复期间,也可以继续发送消息。priority 决定 Agent 什么时候处理这条消息:
行为
now停止当前回复,立即处理这条消息
next默认值;在下一个合适的时机处理
later等当前回复结束后处理
相同优先级的消息按发送顺序处理。要立即改变当前方向,使用 priority: 'now'。如果只想停止当前回复,不想发送新消息,请使用中断当前回复 下面的代码需要放入前面的 TypeScript 消息生成器或已连接的 Python client 会话中:
yield {
  type: 'user',
  message: {
    role: 'user',
    content: [{ type: 'text', text: '停止当前方向,只分析失败的测试。' }],
  },
  parent_tool_use_id: null,
  priority: 'now',
};

添加上下文但不触发回复

有时你只想补充背景信息,不希望 Agent 立即回复。此时设置 shouldQuery: false(TypeScript)或 should_query=False(Python)。这条消息仍会加入对话,何时生效由 priority 决定。
yield {
  type: 'user',
  message: {
    role: 'user',
    content: [{ type: 'text', text: '后续建议都必须兼容 Python 3.10。' }],
  },
  parent_tool_use_id: null,
  shouldQuery: false,
};

中断当前回复

调用 interrupt() 可以停止 Agent 当前的回复,但不会结束会话。中断后仍可继续发送消息。TypeScript 在 query() 返回的对象上调用;Python 需要使用 QoderSDKClient
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: '检查项目中的所有文件。',
  options: { auth: accessTokenFromEnv() },
});

const interruptTimer = setTimeout(() => {
  void q.interrupt().catch(console.error);
}, 5_000);

try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  clearTimeout(interruptTimer);
}
interrupt() 不会删除等待处理的消息。如果其中某条消息已经不需要,请单独取消。要结束整个会话,请调用关闭方法或退出 async with 代码块。

取消排队消息

要取消一条尚未开始处理的消息,先给它设置会话内唯一的 UUID。TypeScript 使用消息的 uuid 字段,Python 使用 message_uuid 参数: 下面只展示取消操作本身,假设 q / client 和对应的消息 UUID 已经创建:
const cancelled = await q.cancelAsyncMessage(uuid);
取消成功返回 true / True。如果消息不存在或已经开始处理,则返回 false / False。没有 UUID 的消息不能单独取消;同一会话中不要重复使用 UUID。

结束输入和关闭会话

  • TypeScript:字符串任务完成后,SDK 自动结束会话。使用异步消息流时,迭代器结束表示不再发送消息。要提前关闭整个会话,可以使用 AbortController 或调用 q.close()
  • Python:一次性 query() 会自动结束。使用 QoderSDKClient 时,推荐用 async with 自动连接和断开;也可以手动调用 connect() / disconnect()
下面的代码只展示会话如何结束,并沿用前面示例中的导入、messages()options

自动关闭

const q = query({
  prompt: messages(),
  options: { auth: accessTokenFromEnv() },
});

try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  await q.close();
}

根据外部条件提前关闭

const abortController = new AbortController();
const q = query({
  prompt: '检查项目中的所有文件。',
  options: { auth: accessTokenFromEnv(), abortController },
});

const taskTimeout = setTimeout(() => abortController.abort(), 5_000);
try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  clearTimeout(taskTimeout);
}
会话关闭后,不能再向它发送消息。