feat: add native session goals#27163
Conversation
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
908a68b to
786043a
Compare
7bc88b9 to
71989f4
Compare
f9c9820 to
73109c9
Compare
52cbe78 to
3857494
Compare
|
so much of code changes |
|
@codex review |
4cbd99f to
8b458e9
Compare
Reverting in favor of upstream opencode#27163 ("feat: add native
session goals", opened 2026-05-12, still open). Upstream ships:
- Token + wall-clock usage accounting with budget-exhausted state
- Model-facing read/create/mark-complete tools (a real forcing
function — model can't ignore a passive system-prompt block the
way it could here)
- Auto-continue-on-idle + pause-on-abort
- TUI prompt-input / session-header / footer surfaces
- Real SDK codegen output (vs the hand-patched sdk.gen.ts /
types.gen.ts in this PR that next regen would clobber)
- 1243+ lines of test coverage vs ~120 here
PR #31's own "Followups (deferred)" section explicitly listed three
items upstream already provides: SDK regen, footer/status-bar
surface, real budget/time tracking. The implementation here was
display-only prompt injection with no enforcement.
Plan: wait for upstream anomalyco#27163 to merge, then sync via the normal
upstream-merge path. The gpd-cli companion (get-physics-done#228)
is a distinct surface (CLI, not in-runtime) and can land on its
own merits once it consumes the upstream-merged shape.
Cameron's f6a9017 on top (extending the RES-904 reward-hacking
gate to gpt/gemini/codex/kimi/trinity) touches a disjoint file set
and is preserved unchanged.
Reverts the 12 files PR #31 modified/added to their state at the
PR #30 merge (fb230ed):
packages/opencode/migration/20260515120000_add_session_goal/migration.sql (deleted)
packages/opencode/src/cli/cmd/tui/component/dialog-session-goal.tsx (deleted)
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx (restored)
packages/opencode/src/server/instance/session.ts (restored)
packages/opencode/src/session/index.ts (restored)
packages/opencode/src/session/projectors.ts (restored)
packages/opencode/src/session/prompt.ts (restored)
packages/opencode/src/session/session.sql.ts (restored)
packages/opencode/test/cli/tui/dialog-session-goal.test.ts (deleted)
packages/opencode/test/session/goal.test.ts (deleted)
packages/sdk/js/src/v2/gen/sdk.gen.ts (restored)
packages/sdk/js/src/v2/gen/types.gen.ts (restored)
|
There is another problem: False “no progress” auto-pause stopped goal continuation prematurelySummaryWhen a session had an active goal, This was not an LLM/provider failure. The goal loop exited before a new LLM turn was enqueued. Root causeAfter a synthetic goal-continuation user message ( const assistantMadeGoalProgress = (message: MessageV2.WithParts) =>
message.info.role === "assistant" &&
message.parts.some((part) => {
if (part.type === "patch" || part.type === "subtask") return true
if (part.type !== "tool") return false
if (part.tool === "get_goal") return false
return part.state.status === "completed" || part.state.status === "running" || part.state.status === "pending"
})Original buggy condition (simplified): // BEFORE fix — only looked at the latest assistant
if (
isGoalContinuationMessage(latestUser) &&
latestAssistant.finish &&
!assistantMadeGoalProgress(latestAssistant) // ← too narrow
) {
await goals.update({ sessionID, status: "paused" })
return
}Failure scenarioTypical message sequence:
On idle,
So it logged Observed in logs: No Why normal chat still workedA real user message creates a new turn and does not hit this auto-pause branch the same way. The bug specifically affected the goal idle-continuation loop, not arbitrary user prompts. FixTreat a continuation stretch as “no progress” only if none of the last N messages (N=5) contain tool/patch/subtask progress: if (
Option.isSome(latestUser) &&
Option.isSome(latestAssistant) &&
latestAssistant.value.info.role === "assistant" &&
isGoalContinuationMessage(latestUser.value) &&
latestUser.value.info.id < latestAssistant.value.info.id &&
latestAssistant.value.info.finish &&
!recentProgress
) {
yield* goalContinueLog(sessionID, "auto_pause_no_progress", messageContext)
yield* goals.update({ sessionID, status: "paused" }).pipe(
Effect.catchIf(NotFoundError.isInstance, () => Effect.void),
Effect.ignore,
)
return
}Where const recentMessagesMadeGoalProgress = (messages: MessageV2.WithParts[]) =>
messages.some((message) => assistantMadeGoalProgress(message))After the fix, resume logs show |
|
Used it for a bit and everything looks good so far—no other issues found. The program runs great, thanks for the PR! |
9fc0904 to
76a2009
Compare


Issue for this PR
Closes #27167
Type of change
What does this PR do?
Adds native per-session goals to OpenCode. Goals are persisted server-side, exposed through session HTTP APIs and the generated JS SDK, and shared by the TUI and app. The runtime injects defensive hidden goal context, accounts token and wall-clock usage, auto-continues active goals only when idle, pauses on abort, and budget-limits when token budget is exhausted. Model tools are limited to reading, explicit create, and marking complete.
How did you verify your code works?
cd packages/opencode && bun typecheckcd packages/opencode && bun test --timeout 30000 test/session/goal.test.tscd packages/opencode && bun test --timeout 30000 test/session/goal.test.ts test/server/httpapi-session.test.ts test/session/prompt.test.ts --test-name-pattern 'SessionGoal|session goal routes|goal continuation|goal tools'cd packages/opencode && bun test --timeout 30000 test/session/snapshot-tool-race.test.tscd packages/app && bun typecheckcd packages/app && bun test --preload ./happydom.ts src/components/prompt-input/submit.test.ts src/context/global-sync/event-reducer.test.ts src/context/global-sync/session-cache.test.tscd packages/sdk/js && bun typecheckcd packages/desktop && bun typecheckgit diff --checkbun turbo typecheckcodex review --base refs/remotes/upstream/dev; fixed two P2 budget-accounting findings and added regression tests.Screenshots / recordings
Not attached. The UI changes are compact slash/status surfaces; app and TUI behavior is covered by targeted tests.
Checklist