Skip to content

feat: allow user message when turn is running - #778

Open
sr07asthana wants to merge 27 commits into
mainfrom
sr-AGE-2264
Open

sr07asthana wants to merge 27 commits into
mainfrom
sr-AGE-2264

Conversation

@sr07asthana

@sr07asthana sr07asthana commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #

Changes

How was this tested?

Checklist

  • I have read the contributing guidelines
  • pnpm build, pnpm test, pnpm typecheck, pnpm lint:ci, and pnpm format:check pass locally
  • Tests added/updated where it makes sense
  • No hand-edits to generated code (packages/trueforge-sdk, python/trueforge_sdk, .github/fern/openapi/openapi.json, docs/openapi.json) — fork PRs omit SDK regen; maintainers regenerate after merge
  • Docs / .env.example updated if configuration or behavior changed

Note

Medium Risk
Changes core turn steering, LLM context repair, sub-agent lifecycle, and durable thread snapshots—behavior shifts when users interrupt pending work, though covered by new contract and orchestration tests.

Overview
Users can start a new turn with a user message while approvals, client-side tool prompts, or in-flight sub-agent threads are still pending, instead of being blocked or forced to wait for resolution.

Interrupt vs resume: AgentThread.send picks interrupt when the batch includes a user message and resume otherwise. Before validation, buildOpenToolCallClosure appends synthetic tool responses for open calls on the last assistant message—cancelled copy on interrupt (including approval, client-side, and sub-agent calls) vs dangling/retry copy on resume (still skipping pending-user-action and thread-creation calls on resume). Pending-approval checks no longer reject user messages; empty sends while awaiting input still fail.

Orchestration & persistence: Non-approval sends drop child threads from the in-memory orchestrator (metrics retained). Session createTurn treats capability_states as the authoritative live thread id set—previous threads omitted are not copied into the next snapshot (in-memory, Postgres, and SQLite). Root AGENT_DONE with error no longer surfaces as turn output in terminal field extraction.

Tests cover steering over pending approval, sub-agent drop vs empty resume, store thread omission, and closure modes.

Reviewed by Cursor Bugbot for commit 6b3d073. Bugbot is set up for automated code reviews on this repo. Configure here.

@changeset-bot

changeset-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6b3d073

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@truefoundry/trueforge-core Patch
@truefoundry/trueforge Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread .changeset/steer-session-anytime.md Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThreadOrchestrator.ts
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	python/trueforge_sdk/.fern/metadata.json
Comment thread .github/fern/openapi/openapi.json Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThread.ts
Comment thread packages/trueforge-core/src/core/runtime/AgentThread.ts Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThread.ts Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThreadOrchestrator.ts Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThreadOrchestrator.ts Outdated
Comment thread packages/trueforge-core/src/core/runtime/AgentThreadOrchestrator.ts Outdated
}

public async *send(messages: AgentThreadSendBatch): AsyncGenerator<AgentThreadAppendContext, void, unknown> {
if (messages.length > 0 && !isUserToolApprovalOrResponseBatch(messages)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have a separate CancelTurn method that does all this ( that we later reuse in cancel API as well)
We shouldn't add such conditional handling directly in orchestrator.
Perhaps we can model it as a "send cancel" event to orchestrator? @chiragjn thoughts here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cancel api is separate in our case right? we decided cancel and closing these calls will be two separate processess right?
The previous turn is already frozen. You start a new turn with a real user message while a sub-agent (or approval) was still open in the snapshot.
Then this orchestrator flow runs, in send() of that new turn

We discussed yesterday that cancel itself should not close all pending subagent/pending actions. It should be done when next user message arrives. cc @chiragjn

@heerambavi1998 heerambavi1998 Sep 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not get this.
A user message creates a new turn, which should cancel the previous turn. So sending a user message should have the exact same behaviour as say clicking cancel turn button.
This was what we discussed.

The problem here is that we already mark the turn as done. I believe this change will make more sense once we pause the turn instead.
Currently the only scenario we need to handle is that the turn is running, and we send a user message - which interrupts the turn.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

freeze/cancel-button stops the old turn, this send() path stops leftover threads/tools on the next turn.

sr07asthana and others added 9 commits September 17, 2026 17:21
Resolve the session test imports while preserving steering validation and main's active executor coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

role: 'tool',
tool_call_id: toolCallId,
content: DUMMY_TOOL_MESSAGE_CONTENT,
content,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cancelled tools never reach event log

Medium Severity

A user message now synthesizes tool responses for pending approvals, client-side tools, and sub-agents, but those closures are written only into LLM context with output: []. createTurn drains send() via collectContextAppends, which ignores output, and stream() never sees the append. Clients that already received HITL required-actions therefore get no TOOL_RESPONSE in the session event log or live stream, so the UI can keep showing those calls as open.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7d9edc6. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is accepted, for now we have decided it will be clients responsibility to handle previous pending tool calls, user actions and threads in case a new user message is sent

Comment thread packages/trueforge-core/src/core/runtime/AgentThreadOrchestrator.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 64133f2. Configure here.

Comment thread .github/fern/openapi/openapi.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants