cloudflare / cloudflare/agents
Think: no public wait for a submission to finish
- Dominant language
- TypeScript
- Stars
- 5.6k
- Forks
- 711
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 53
Description
## Summary
Durable turns are `submitMessages` (returns immediately) plus `inspectSubmission` (a status read). There is no public promise or event that resolves when that submission reaches a terminal status. Workflows that admit a Think turn have to poll.
`onSubmissionStatus` is a protected hook, not a waiter. `waitUntilStable` is chat-recovery / client-tool drain, not submission completion.
## Environment
- `@cloudflare/think@0.17.0`
- Cloudflare Workflows calling a Think Durable Object via `submitMessages`
## What the types allow
```ts
submitMessages(
messages: UIMessage[],
options?: SubmitMessagesOptions
): Promise;
inspectSubmission(
submissionId: string
): Promise;
type ThinkSubmissionStatus =
| "pending"
| "running"
| "completed"
| "aborted"
| "skipped"
| "error";
```
`SubmitMessagesResult` is `ThinkSubmissionInspection & { accepted: boolean }` — typically `pending` / `running` at return. There is no `waitForSubmission(submissionId)` (or equivalent) on the public `Think` class.
`runTurn({ mode: "wait" })` blocks, but it is the wrong admission for a Workflow step: a wait-mode turn dies with the isolate, and `step.prompt` is hard-wired to `this.agent`. Parallel Capturer/Builder turns have to be `submitMessages` on other DOs.
## Reproduction
A Workflow step that must not return until a role DO has finished:
```ts
const { submissionId } = await agent.submitMessages([userMessage], {
idempotencyKey: `${workflowName}:${instanceId}:${stepName}`,
});
// No:
// await agent.waitForSubmission(submissionId)
// Only:
let inspection = await agent.inspectSubmission(submissionId);
while (inspection?.status === "pending" || inspection?.status === "running") {
// poll — in a Workflow, throw so the step retries
inspection = await agent.inspectSubmission(submissionId);
}
```
That poll is what `admitTurn` in a Workflow does today: `submitMessages` in one `step.do`, then a second `step.do` that calls `inspectSubmission` and throws while `pending`/`running` so the engine retries.
## Suggested fix
A public waiter, e.g. `waitForSubmission(submissionId): Promise`, that resolves on `completed` / `aborted` / `skipped` / `error` (and rejects or returns the error payload on `error`). An event / `onSubmissionStatus` subscription that a Workflow can await would also remove the poll.
`mode: "wait"` can stay for in-process callers; this is for the submit path a Workflow actually uses.
Contributor guide
Assessment
This issue has not been assessed yet.