From 13938f59733dd1b05d7dc736cf2cf5588f2c63fd Mon Sep 17 00:00:00 2001 From: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Date: Thu, 25 Jun 2026 01:01:21 -0700 Subject: [PATCH] feat(thread_goals): Codex-style thread-level goal (core + RPC + tools + harness + UI) (#4087) --- app/scripts/e2e-web-session.sh | 6 + app/src/components/chat/ChatComposer.tsx | 287 ++++---- app/src/components/chat/QueuedFollowups.tsx | 2 +- app/src/lib/i18n/ar.ts | 15 + app/src/lib/i18n/bn.ts | 15 + app/src/lib/i18n/de.ts | 15 + app/src/lib/i18n/en.ts | 16 + app/src/lib/i18n/es.ts | 15 + app/src/lib/i18n/fr.ts | 15 + app/src/lib/i18n/hi.ts | 15 + app/src/lib/i18n/id.ts | 15 + app/src/lib/i18n/it.ts | 15 + app/src/lib/i18n/ko.ts | 15 + app/src/lib/i18n/pl.ts | 15 + app/src/lib/i18n/pt.ts | 15 + app/src/lib/i18n/ru.ts | 15 + app/src/lib/i18n/zh-CN.ts | 15 + app/src/pages/Conversations.tsx | 46 +- .../components/ThreadGoalChip.test.tsx | 97 +++ .../components/ThreadGoalChip.tsx | 369 +++++++++++ .../api/__tests__/threadGoalApi.test.ts | 80 +++ app/src/services/api/threadGoalApi.ts | 114 ++++ app/tailwind.config.js | 8 + src/core/all.rs | 6 + src/core/event_bus/events.rs | 15 + src/openhuman/about_app/catalog_data.rs | 21 + .../agent/harness/session/builder/factory.rs | 6 + .../agent/harness/session/turn/core.rs | 84 ++- src/openhuman/agent/turn_origin.rs | 3 + .../tools/agent_prepare_context.rs | 105 +++ .../agents/context_scout/prompt.md | 9 + .../agents/orchestrator/agent.toml | 12 + src/openhuman/approval/gate.rs | 55 +- src/openhuman/config/schema/heartbeat_cron.rs | 17 + src/openhuman/context/manager.rs | 8 + src/openhuman/mod.rs | 1 + .../subconscious/heartbeat/engine.rs | 13 + src/openhuman/thread_goals/continuation.rs | 270 ++++++++ src/openhuman/thread_goals/mod.rs | 33 + src/openhuman/thread_goals/ops.rs | 165 +++++ src/openhuman/thread_goals/runtime.rs | 424 ++++++++++++ src/openhuman/thread_goals/schemas.rs | 248 +++++++ src/openhuman/thread_goals/store.rs | 617 ++++++++++++++++++ src/openhuman/thread_goals/tools.rs | 275 ++++++++ src/openhuman/thread_goals/types.rs | 151 +++++ src/openhuman/tools/ops.rs | 18 + tests/agent_harness_e2e.rs | 15 +- tests/json_rpc_e2e.rs | 157 +++++ 48 files changed, 3783 insertions(+), 165 deletions(-) create mode 100644 app/src/pages/conversations/components/ThreadGoalChip.test.tsx create mode 100644 app/src/pages/conversations/components/ThreadGoalChip.tsx create mode 100644 app/src/services/api/__tests__/threadGoalApi.test.ts create mode 100644 app/src/services/api/threadGoalApi.ts create mode 100644 src/openhuman/thread_goals/continuation.rs create mode 100644 src/openhuman/thread_goals/mod.rs create mode 100644 src/openhuman/thread_goals/ops.rs create mode 100644 src/openhuman/thread_goals/runtime.rs create mode 100644 src/openhuman/thread_goals/schemas.rs create mode 100644 src/openhuman/thread_goals/store.rs create mode 100644 src/openhuman/thread_goals/tools.rs create mode 100644 src/openhuman/thread_goals/types.rs diff --git a/app/scripts/e2e-web-session.sh b/app/scripts/e2e-web-session.sh index 3e1488c30..51aacae03 100755 --- a/app/scripts/e2e-web-session.sh +++ b/app/scripts/e2e-web-session.sh @@ -102,6 +102,12 @@ coding_provider = "e2e:e2e-mock-model" [update] enabled = false +[context] +# Deterministic e2e specs script the mock-LLM call sequence exactly; the +# default-on first-turn "super context" scout adds an extra agentic call that +# would perturb those sequences. No spec exercises super context, so disable it. +super_context_enabled = false + [[cloud_providers]] id = "p_e2e_mock" slug = "e2e" diff --git a/app/src/components/chat/ChatComposer.tsx b/app/src/components/chat/ChatComposer.tsx index 10f20d827..b3ce89b73 100644 --- a/app/src/components/chat/ChatComposer.tsx +++ b/app/src/components/chat/ChatComposer.tsx @@ -39,6 +39,14 @@ export interface ChatComposerProps { * attach button, hidden file input, and preview strip are not rendered. */ attachmentsEnabled: boolean; + /** + * Optional nodes stacked above the input box but *outside* its focus + * highlight — e.g. the queued-follow-ups strip and the thread-goal editor. + * They render within the overall composer component (so they move with it) + * yet are not wrapped by the blue focus-within ring/border of the input box. + * Entries that render `null` contribute nothing. + */ + headerSlots?: React.ReactNode[]; } /** @@ -66,6 +74,7 @@ export default function ChatComposer({ maxAttachments, allowedMimeTypes, attachmentsEnabled, + headerSlots = [], }: ChatComposerProps) { const { t } = useT(); @@ -93,155 +102,163 @@ export default function ChatComposer({ }, [inputValue, textInputRef]); return ( -
- {/* Hidden file input for attachment (gated — see attachmentsEnabled). */} - {attachmentsEnabled && ( - { - void onAttachFiles(e.target.files); - e.target.value = ''; - }} - /> - )} +
+ {/* Header stack (e.g. queued follow-ups, thread-goal editor): rendered + above the input box and OUTSIDE its blue focus highlight, but still + within the overall composer component so they move as one unit. */} + {headerSlots} - {/* Attachment preview strip */} - {attachmentsEnabled && attachments.length > 0 && ( -
- -
- )} - - {/* Single row: [+] textarea [mic] [send] */} -
- {/* Attach button */} + {/* The input box — only this carries the focus-within highlight. */} +
+ {/* Hidden file input for attachment (gated — see attachmentsEnabled). */} {attachmentsEnabled && ( + { + void onAttachFiles(e.target.files); + e.target.value = ''; + }} + /> + )} + + {/* Attachment preview strip */} + {attachmentsEnabled && attachments.length > 0 && ( +
+ +
+ )} + + {/* Single row: [+] textarea [mic] [send] */} +
+ {/* Attach button */} + {attachmentsEnabled && ( + + )} + + {/* Textarea with ghost completion */} +
+
+ {inputValue} + + {inlineCompletionSuffix} + +
+