Think ターンを耐久的に受け付け、推論が始まる前に返します。webhook ハンドラー、RPC 呼び出し元、素早い受付、安全な再試行、あとからの状態確認が必要な親 Workers では submitMessages() を使います。
宣言的な スケジュール済みプロンプトタスク も、内部では同じ耐久受付パスを使います。トリガーが繰り返しでコード宣言なら getScheduledTasks() を使います。外部の呼び出し元や webhook が単発の作業を作る場合は、submitMessages() を直接使います。応答をインラインで待つ場合は、代わりに saveMessages() を使います。
async submitMessages(
messages: UIMessage[],
options?: {
submissionId?: string;
idempotencyKey?: string;
metadata?: Record<string, unknown>;
},
): Promise<SubmitMessagesResult>submitMessages() が受け付けるのはシリアライズ可能な UIMessage[] です。saveMessages((messages) => ...) が対応している関数形式は使えません。耐久送信は実行前に作業を永続化するため、クロージャは保存できないからです。配列には少なくとも 1 件のメッセージが必要です。
const submission = await this.submitMessages(
[
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Process webhook event 123" }],
},
],
{ idempotencyKey: "webhook-event-123" },
);
return Response.json({
submissionId: submission.submissionId,
status: submission.status,
accepted: submission.accepted,
});const submission = await this.submitMessages(
[
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Process webhook event 123" }],
},
],
{ idempotencyKey: "webhook-event-123" },
);
return Response.json({
submissionId: submission.submissionId,
status: submission.status,
accepted: submission.accepted,
});| ステータス | 意味 |
|---|---|
pending |
受け付け済みで、自分のターンを待っています |
running |
エージェントが取得し、実行中です |
completed |
Think ターンが正常に完了しました |
aborted |
送信がキャンセルされました |
skipped |
送信の実行前にターン状態がリセットされました |
error |
実行に失敗したか、復旧が安全ではありませんでした |
外部システムの idempotencyKey を渡します。同じキーで再試行すると、重複メッセージを挿入せず、既存の送信を accepted: false で返します。
const first = await this.submitMessages(messages, {
idempotencyKey: payload.id,
});
const retry = await this.submitMessages(messages, {
idempotencyKey: payload.id,
});
console.log(first.submissionId === retry.submissionId); // true
console.log(retry.accepted); // falseconst first = await this.submitMessages(messages, {
idempotencyKey: payload.id,
});
const retry = await this.submitMessages(messages, {
idempotencyKey: payload.id,
});
console.log(first.submissionId === retry.submissionId); // true
console.log(retry.accepted); // falsesubmissionId と idempotencyKey の両方を渡す場合、同じ送信を指している必要があります。別々の既存送信を指していると、submitMessages() は例外を投げます。
送信 API で、稼働中の作業の確認、耐久送信のキャンセル、終端レコードのクリーンアップができます。
const current = await this.inspectSubmission(submission.submissionId);
const active = await this.listSubmissions({
status: ["pending", "running"],
});
await this.cancelSubmission(submission.submissionId, "No longer needed");
await this.deleteSubmissions({
status: ["completed", "error", "aborted"],
completedBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});const current = await this.inspectSubmission(submission.submissionId);
const active = await this.listSubmissions({
status: ["pending", "running"],
});
await this.cancelSubmission(submission.submissionId, "No longer needed");
await this.deleteSubmissions({
status: ["completed", "error", "aborted"],
completedBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
});Worker と Durable Object の RPC 境界をまたぐ耐久キャンセルには cancelSubmission(submissionId) を使います。AbortSignal を saveMessages() または continueLastTurn() と一緒に使うのは、ターンを実行する Durable Object の内側で呼び出し元がシグナルを作る場合だけです。
Think は、受け付けた送信をまず送信台帳に保存します。送信されたメッセージを会話 Session に追加するのは、その送信の実行が始まったときです。あとから受け付けた送信は、自分のターンが始まるまでモデルからは見えません。先入れ先出しのターン意味論を保つためです。
メッセージが適用される前に送信をキャンセルした場合(取得済みでもまだ自分のターン待ちのものを含む)、それらのメッセージは会話に永続化されません。
保留中の送信が実行される前にチャットがクリアされるか、ターン状態がリセットされると、その送信は skipped になります。
複数ステップのオーケストレーション、ステップごとの再試行、長い待ち、外部イベント、人手承認、Think を大きな処理の一部として起動するパイプラインには Workflows を使います。Think Workflows を参照してください。