Skip to content

feat(flowchat): add a thread goal control to the composer workspace strip - #3252

Merged
kev1n77 merged 2 commits into
GCWing:mainfrom
kev1n77:fmy/bugfix
Sep 29, 2026
Merged

kev1n77 merged 2 commits into
GCWing:mainfrom
kev1n77:fmy/bugfix

Conversation

@kev1n77

@kev1n77 kev1n77 commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add a thread goal control next to the local workspace chip in the composer strip, and fix the goal actions that did not match what the user asked for.

The strip now shows the goal icon, its status and a live elapsed timer, with pause, resume and clear available directly from it. Pause and clear stop the goal-driven turn instead of letting it keep running, pause acts immediately without a confirmation dialog, and clearing a goal no longer leaves the next /goal kickoff parked. Goal duration renders in days, hours, minutes and seconds instead of raw seconds, and editing a paused goal returns it to running because the edit itself is the user asking the goal to continue.

Editing a goal also no longer blocks the dialog. The command used to wait for the goal's next turn to be admitted, which measured 2482.3 ms and 3843.6 ms on the reporting user's machine, and it now hands that steering to the runtime in the background the way resume already does.

Type and Areas

Type: Feature, bug fix, UI/UX.

Areas: Rust core (agentic coordination: thread goal lifecycle and session scheduler), web UI (flow chat composer strip, thread goal control and dialogs), i18n locales (en-US, zh-CN, zh-TW).

Motivation / Impact

A running goal was only visible inside the goal dialog, so the user could not tell what the agent was working toward, how long it had been running, or stop it without opening that dialog. The new control puts the goal icon, its status and a ticking elapsed timer beside the local workspace chip, and exposes pause, resume and clear as direct actions.

Three behavior bugs are fixed in the same area. Pause and clear previously marked the goal but let the goal-driven turn run to completion, so the goal kept working after the user stopped it. Pause opened a confirmation dialog although the user had already decided. After clearing a goal, sending /goal again could leave the goal active with a parked kickoff, which looked like the goal running while the flow chat stayed empty and the timer only moved when the user clicked something.

Goal duration is now reported in days, hours, minutes and seconds in the strip, the goal detail dialog and the usage report, instead of a raw seconds count such as "91s". Editing a paused goal leaves it running, which is the intended reading of the edit dialog: the user is telling the goal what to work on next, so the pause it was edited from no longer describes it.

The edit command no longer waits for the goal's next turn to be admitted. The goal state, its update event and the release of the interruption that parked the kickoff stay on the command path, while the objective steering is delivered in the background through the same helper the resume path uses. The measured edit command went from 2482.3 ms and 3843.6 ms to roughly 50 ms, so the dialog closes immediately and the goal turn appears a moment later in the flow chat.

No persisted shape changes. Thread goal records, statuses and the goal store schema are untouched, so existing goals and older builds keep working.

Verification

Rust:

  • cargo check -p openbitfun-core --no-default-features --features agent-runtime,git — passed.
  • cargo test -p openbitfun-core --no-default-features --features agent-runtime,git --lib goal — 25 passed, 1 failed. The failure is the pre-existing agentic::coordination::scheduler::tests::thread_goal_plain_prompt_steering_activates_without_an_extra_turn, which asserts a \n inside a template that is checked out as CRLF on Windows (src/crates/execution/agent-runtime/src/thread_goal/templates/objective_updated.md contains 16 CRLF pairs). It is a line-ending assertion in the test, not a behavior change from these commits.
  • pnpm run fmt:rs — applied to the changed Rust files.

Web UI:

  • pnpm --dir src/web-ui run test:run src/flow_chat/utils/threadGoalDuration.test.ts src/flow_chat/components/usage/usageReportUtils.test.ts src/flow_chat/components/thread-goal/threadGoalStripTone.test.ts src/flow_chat/components/ChatInputWorkspaceStrip.test.tsx — 4 files, 73 tests passed.
  • pnpm run type-check:web — passed.
  • pnpm run i18n:audit — passed with 0 warnings.
  • pnpm run appearance:contract-audit — passed.
  • node scripts/audit-frontend-colors.mjs --surface web-ui — passed for 2436 files.
  • pnpm run typography:audit — passed with zero violations.

Timing evidence comes from the desktop client log of the reporting user, where the frontend records each invoke duration: update_session_thread_goal_objective took 2482.3 ms and 3843.6 ms, while set_session_thread_goal_status took 86 ms to 428 ms. In the same log the backend shows 2071 ms and 3213 ms inside the goal turn admission, between Dialog turn workspace context and Saved dialog turn, with no other backend event in that window, which is what the edit command was waiting on.

Reviewer Notes

Manual check worth running before merge: open a paused goal, edit the objective, and confirm the dialog closes immediately, the strip switches to running with the timer advancing, and the next goal turn appears in the flow chat within a few seconds.

The backend change is deliberately asymmetric. /goal <objective> still awaits its delivery, because that command's success already implies the kickoff turn exists, while edit and resume hand delivery to the runtime in the background. Making goal creation return instantly as well is a small follow-up on set_thread_goal_objective. Note that a background delivery reports failure through a warn! log only, which is the existing behavior of the resume path.

Rollback is a plain revert of these two commits; nothing is persisted in a new shape and no migration is involved.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Generated with OpenBitFun

…sion

Editing a paused goal restarts it, so the edit path delivered objective-updated steering and awaited it. On an idle session that delivery admits the goal's next turn, which measured 2482-3844 ms and made the edit dialog look frozen.

Hand the steering over in the background, the way resume already does, through one shared delivery helper for both kinds. The goal state, its event, and the release of the interruption that parked the kickoff stay on the command path, so an edited goal still comes back as active.
Give the running goal a control next to the local workspace chip: goal icon, status, and a live elapsed timer, plus pause and clear quick actions. Pause acts immediately instead of opening a confirmation, while clear keeps its own dialog.

Render goal duration in days, hours, minutes and seconds instead of raw seconds, and bring an edited goal back to running so the pause it was edited from no longer describes it.
@kev1n77
kev1n77 merged commit 62db7fc into GCWing:main Sep 29, 2026
13 checks passed
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.

1 participant