Title: Recall previously-sent prompts in the composer with the Up / Down arrows by DragonnZhang · Pull Request #53 · modelstudioai/openwork · GitHub
Open Graph Title: Recall previously-sent prompts in the composer with the Up / Down arrows by DragonnZhang · Pull Request #53 · modelstudioai/openwork
X Title: Recall previously-sent prompts in the composer with the Up / Down arrows by DragonnZhang · Pull Request #53 · modelstudioai/openwork
Description: Closes #52 What & why Terminal shells, the Claude Code CLI, and the Codex desktop composer all let you recall a prompt you already sent by pressing Up in the composer. OpenWork's composer (FreeFormInput) had no prompt history: once a message was sent it was gone from the input, so re-running or tweaking a previous prompt meant retyping it or copying it back out of the transcript. Outside the inline mention / slash / label menus, ArrowUp / ArrowDown in the composer only moved the caret. This adds shell-style prompt history recall: Each sent prompt is appended to a global history list (newest last), persisted in localStorage (craft-prompt-history), trimmed, with immediate duplicate collapse, capped at 100 entries. Up in an empty composer (or while already recalling) walks backwards (newest → oldest), clamping at the oldest. Down while recalling walks forwards; paging past the newest entry restores the draft you started from and exits recall. Any real edit, submitting, or switching sessions exits recall. With a non-empty draft and not recalling, Up/Down keep normal caret-movement — recall never hijacks editing. Frontend-only. No backend / qwen-code change. Recall drives the existing controlled value prop (the same path @mention selection already uses), and persistence reuses the existing lib/local-storage.ts helper. No new i18n keys. Changes components/app-shell/input/prompt-history.ts (new) — pure, DOM-free history model: pushPromptHistory (trim / immediate-repeat collapse / cap), prevPromptIndex / nextPromptIndex / promptAt (index-based Up/Down navigation), and getPromptHistory / recordPrompt (localStorage round-trip). components/app-shell/input/FreeFormInput.tsx — history refs, an applyRecalledPrompt helper (drives setInput + caret), the ArrowUp/ArrowDown branch in handleKeyDown, recall capture in submitMessage, reset on real edit (handleInputChange) and on session switch, and data-testid="composer-input" on the composer for e2e. lib/local-storage.ts — new promptHistory key (craft-prompt-history). components/app-shell/input/__tests__/prompt-history.test.ts (new) — 20 unit tests for the module. e2e/assertions/prompt-history.assert.ts (new) — CDP assertion (below). Verification (DoD) bun run typecheck:all — zero new errors. packages/{core,shared,server-core,server,session-tools-core} pass clean; packages/ui passes clean (checked independently); the only errors are the 11 pre-existing ones in apps/electron (auto-update.ts owner/repo, a settings-default-thinking test tuple, two test files importing vitest) — none in the files this PR touches. bun test — the set of failing tests is byte-for-byte identical to main, verified by diffing the sorted, timing-stripped failure lists from a clean-main run and this branch in the same environment: 56 pre-existing failures on both (BrowserCDP, RPC handler profiles, RoutedClient, startWebuiHttpServer, the i18n sorted checks, resource-bundle, …). This change adds zero new failures, and adds 20 new passing unit tests (prompt-history.test.ts). (The raw N fail total is order-dependent when the whole suite runs unisolated; the deterministic signal is the failing-test set, which is unchanged.) Renderer build (bun run build:renderer, where this change lives) — ✅ builds cleanly. CDP assertion transpiles (bun build e2e/assertions/prompt-history.assert.ts) — ✅. CDP e2e assertion (prompt-history.assert.ts) Drives the real built app over CDP entirely in the draft (no-session) state — no seeded conversation and no backend. The composer reads its history fresh from localStorage, so the assertion seeds three prior prompts there and walks them: The composer renders and starts empty. Seed localStorage['craft-prompt-history'] = ['alpha one','beta two','gamma three']. ArrowUp recalls the newest (gamma three); further Ups recall beta two, alpha one, and clamp at the oldest. ArrowDown walks newer again (beta two, gamma three) and, once past the newest, restores the original empty draft. Reading the composer's actual text after each keypress proves the arrows really change the composer contents, not merely toggle state. ⚠️ Local CDP run was blocked by this sandbox's egress policy, not by the feature. The Electron binary download (GitHub release host) returns 403 from the egress proxy, so the app can't be built/launched here (xvfb is present; only the binary fetch fails) — the same limitation noted on the other open loop-bot PRs. The assertion transpiles and is included so CI / a reviewer can run bun run e2e in an environment with normal network access. Everything that doesn't require launching Electron (typecheck, unit tests, renderer build) passes with zero delta vs main. Part of the autonomous desktop-feature loop (loop-bot). Generated by Claude Code
Open Graph Description: Closes #52 What & why Terminal shells, the Claude Code CLI, and the Codex desktop composer all let you recall a prompt you already sent by pressing Up in the composer. OpenWork's composer (...
X Description: Closes #52 What & why Terminal shells, the Claude Code CLI, and the Codex desktop composer all let you recall a prompt you already sent by pressing Up in the composer. OpenWork's co...
Opengraph URL: https://github.com/modelstudioai/openwork/pull/53
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:84d5253d-183d-1716-9436-00db50038041 |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | 9CA2:3C0E3A:9417BA:C511E3:6A5278F7 |
| html-safe-nonce | e3464ea8c0d2d9d938628d3653d31c153b2a39f4f751fbca0669c783b02cc14e |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5Q0EyOjNDMEUzQTo5NDE3QkE6QzUxMUUzOjZBNTI3OEY3IiwidmlzaXRvcl9pZCI6IjExMzQ3NjYyNTg3MjM2NDk3ODMiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 91feef102286f63e75fd63870a84465248f564efe1449f4568a46390ea37d2f7 |
| hovercard-subject-tag | pull_request:3989153508 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/modelstudioai/openwork/pull/53/files |
| twitter:image | https://avatars.githubusercontent.com/u/52599892?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/52599892?s=400&v=4 |
| og:image:alt | Closes #52 What & why Terminal shells, the Claude Code CLI, and the Codex desktop composer all let you recall a prompt you already sent by pressing Up in the composer. OpenWork's composer (... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/modelstudioai/openwork git https://github.com/modelstudioai/openwork.git |
| octolytics-dimension-user_id | 283556804 |
| octolytics-dimension-user_login | modelstudioai |
| octolytics-dimension-repository_id | 1256697754 |
| octolytics-dimension-repository_nwo | modelstudioai/openwork |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1256697754 |
| octolytics-dimension-repository_network_root_nwo | modelstudioai/openwork |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width