Inspector, Reasoning, and OMP
gPTY is a graphical PTY foundation with an observability layer. It does not recreate agent TUIs, scrape PTY output for agent semantics, or host the user’s interactive OMP/Claude/Gemini session.
| Surface | Role |
|---|---|
| Terminal | User launches omp (or any CLI) normally. The CLI owns its TUI, auth, tools, and permissions. |
| Inspector | Private, tool-free, iterative Q&A. Owns one in-memory GptyAi session; backends: omp (private omp --mode rpc --no-session --no-tools --no-extensions --no-skills --no-rules), mock, or cli (subprocess NDJSON bridge - a configured adapter command, argv never shell-evaluated, documented hooks only). Does not attach to the terminal OMP process. |
| Reasoning | Passive view of documented reasoning/lifecycle events from one terminal, selected by source_attachment_id. Never starts jobs or accepts concept captures. Turn history is an in-memory accordion for the current OMP session only. |
@gpty/omp-events |
Explicitly installed OMP extension. Dormant unless all four GPTY_EVENT_* vars are present. Forwards bounded session/turn/tool metadata plus thinking_delta text only, coalesced (one event per 16 ms / ≤8 KiB UTF-8, split on code points). |
- Inspector and Reasoning are different sessions. The shipped “Agent Workspace” profile opens Terminal + Inspector + Reasoning; only Reasoning is attached to the terminal.
- Reasoning history is session-scoped RAM (collapsed previous turns, live turn streaming). Closing the pane, changing
source_attachment_id, or binding a newomp_session_iddrops it. Do not write thinking text or OMP session IDs into layout/profile JSON. - The event listener runs on every platform. Workspace control IPC works on Windows (named pipes); the event listener serves
\\.\pipe\gpty-eventsthere andgpty-events.sockon Unix, and per-PTYGPTY_EVENT_*injection happens on both. The shipped@gpty/omp-eventsextension needs no platform branch to reach either one:net.connect(path)opens a Unix socket for a socket path and a named pipe for a pipe path, and the only branch is validation (validateSocketsays a Windows path must be a\\.\pipe\name, answered from the path alone because a pipe cannot bestated).scripts/smoke_pane_api.pyruns the extension inside a real pane and asserts the pane reports Tier 1working, so the chain - env injection, transport, capability check, translation, drain - is observed live on the platform running the smoke (Linux locally,windows-smokein CI). GptyAiis instance-owned:session_open/session_prompt/session_poll/session_cancel/session_close. There is no process-global subscriber bus. Polled envelopes carrysession_id,turn_id,run_id,sequence,channel.- Reasoning caps are user settings (Settings → Reasoning tab):
cfg_reasoning_max_turns(clamped 1–64, default 16) andcfg_reasoning_max_turn_bytes(clamped 4 KiB–1 MiB, default 64 KiB).reasoning_pane.gdreads them at_readyintomax_turns/max_turn_bytes(not consts). When truncating accumulated raw Markdown at the cap, re-close an odd number of ``` fences (_close_open_fences) - an unclosed fence re-renders the tail as code. The cap is visible: the first time a turn reaches it the view gets a source notice (set_source_notice) saying later reasoning is not shown, andtruncated/text_bytesride in the turn record. Appends are O(delta), not O(turn): the byte count is incremental and a delta that arrives after the cap returns before any concatenation or UTF-8 re-encoding (the old path paid two fullto_utf8_buffer()copies per dropped delta - 486 ms for one 64 KiB capped turn, now 31 ms;godot/tests/bench/reasoning_bench.gd). - Reasoning streaming is four rules that must not regress: (a) only the changed turn renders -
_refresh_turn_layoutsyncs width/fold heights and never callsset_markdown; re-rendering every turn on every delta re-parsed the whole accordion and cleared any selection; (b) one deferred layout refresh per frame, not per delta (a burst of 200 deltas used to enqueue 200 walks of every turn); (c) a held selection pauses the coalesced render (MarkdownView._apply_pendingrestarts its timer whileget_selected_text() != "";render_nowfor explicit acts is not deferred); (d) the live turn follows the bottom by intent -_follow_liveis cleared when the user scrolls away from the bottom and re-armed when they return (or a new turn starts), and the scrollbar’schangedsignal re-scrolls after the layout that follows a render. A distance test taken at scroll time is not enough: content grows by whole lines between renders, so the write clamps at the previous bottom and the follow stops.reasoning_bench.gdmeasures the append/render split (64 KiB: 14 ms append, 11 ms render; 256 KiB: 120/41; 256 KiB into a 64 KiB cap: 31/10, against 486 ms for the old capped path).GPTY_REASONING_DEBUG=1prints one line a second - deltas/bytes in, renders/render-ms out, turn/cap state, andGptyTerminal.omp_event_stats()’s accepted/rejected/queued counters - which is how a lossy input stream is told apart from a slow renderer. The status line is a selectableRichTextLabelwith the context menu, and everyMarkdownViewenables selection + the Copy menu. - Do not add Claude/Gemini/Antigravity adapters that read OAuth tokens, call private endpoints, or parse undocumented TUI output. Future adapters may use only that CLI’s documented hooks/extensions, with a fresh terms review.