Merge with upstream#2
Open
Outcue wants to merge 763 commits into
Open
Conversation
… documents only invoke their directly nested amplets. This addresses a bug where amplets of transcluded docs get invoked by the outer docs with erroneous results. However, we have to be careful to update documents with active amplets, otherwise they will not run correctly under this revised implementation.
…ment, at least for now. The changes did fix some problems with transclusion, but introduced new ones that are arguably worse.
…pair of slot name and a value, which was eniugh to display them in context, but is emantically wrong. The conceptual confusion manifests once we try to ensure that the slot presenters update correctly in all cases. Now, slots are modeled with an explict model that combines the slot name and the object from which its derived.
…valuators, slot presnetrs and the basic and key/value views fix a number of bugs that manifested as loss of view state during reactive updates: evaluators losing their results (current and historic), open slots being closed upon update etc. Fixes issue #80 and more.
…llow evaluators to isnpect their presenters. Underlying fixes to Hopscotch UI to faciliatet the reatcive fixes in the IDE. Also relies on fixes to mirrors in Psoup repo for the lazy slots.
…. ALos ensure clicking on class name opens it. This got broken by exemplars long ago.
…ith the same expression.
… code to co-exist in a document. To this end, amplets are assigned ids by the system rather than using their definition as a key. In addition, the worksapce manager now allows user-named workspaces to be generated via its API, which makes it easier to open workspaces in a document, keeping these distinct yet also maintaining their state.
…ng of live widgets embedded in HTML via the mapping rather than via amplets. This restores that.
… are still problems howver.
…e up to date when revisited.
…at if it is open, it stays open (and indeed is recursively updated if its internals depend on the model, and retains any state it has recursively as well).
Update version number
…d by default and eliminating explicit Ordered variants. Depends on changes to psoup repo.
… derived from non-class members.
…ntrolClass - Add 16 generic type tests: 8 for Array[T] (covariance, substitution, mismatch detection) and 8 for type-path generics via CollectionsForPrimordialSoup List[T] and Map[K,V]. - Fix genericInvocationNode to safely handle non-TypeIdAST generics (UnaryTypeOpAST from type paths) in the Tuple check. - Fix HopscotchForCroquet and RuntimeForCroquet to pass voiceControlClass: to HopscotchForHTML5, matching the updated factory method signature. 197/199 tests passing (2 pre-existing _Underscore failures). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…scading bugs Generic substitution: generalized GenericType at: to substitute errorTypes (from unresolved type params like E) with actual type arguments for all methods, replacing the previous at:-only special case. Added 8 new tests for size, first, last, at:put:, copyWith:, includes: on Array[String]. Test rigor: all ~50 error-expecting tests now check exact error count (eset size = N) and specific error message via assertErrorSet:containsMessageWith:. Bugs fixed: - Duplicate parameter type resolution in methodNode: (types resolved twice) - subtypeOf: used identity check (t = errorType) instead of t isKindOfErrorType, causing spurious argument errors after accessibility failures - functionTypeOf: re-evaluated receiver, duplicating errors in chained sends - Sends to error-typed receivers produced cascading "not defined" errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new modules provide AI model access from within the IDE: - AIAccess.ns: General-purpose AI infrastructure (Provider abstraction, AnthropicProvider for direct browser API access, Session with multi-turn tool-use conversation loop) - AIChatUI.ns: General-purpose Hopscotch chat UI (AIChatSetupSubject for API key entry with localStorage persistence, ChatSubject/ChatPresenter for the conversation view) - AI_IDE_Support.ns: IDE-specific module that instantiates the above, defines 7 IDE query tools (class/method source, senders, implementors, class search, etc.), and exposes AI functionality to other IDE components The IDE home page gains an "AI Chat" link. Browsing.ns and HopscotchWebIDE.ns are modified to wire up the new modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extends the Newspeak language with optional type parameter declarations on class headers (e.g., class Map <[K, V]> new: capacity <Integer>). This enables the typechecker to correctly resolve multi-parameter generic substitution instead of blindly mapping all unresolved types to the first type argument. Changes span the grammar, both parsers, colorizer, ASTs, typechecker, and collection source annotations. Includes a new TypeParameterType class with positional indexing, scope-walking resolution with proper shadowing semantics, and backward-compatible errorType fallback for classes without declared type parameters. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ween the manifest in the IDE and the manifest at bootstrap. THis was motivated by the work on th etypechecker, which has been conducted using Claude, accessing the CLI, but also nneds to work in the IDE.
- Per-presenter brain buttons on classes, methods, lazy slots, and class headers. Clicking a brain installs the focus, opens the chat as a collapsible region below the header, and amber-highlights the brain so the user can tell which view is in focus. The chat subject is shared across the toolbar and all per-presenter brains, so a single conversation follows the user as they navigate. - brain.png is registered through ImagePaths/Images in all four runtimes (RuntimeForHopscotchForHTML, RuntimeForCroquet, RuntimeForJS, RuntimeForJSWithMirrorBuilders) and in DeploymentManager's image template. The toolbar brain button replaces the home page AI Chat link and reuses the same shared chat. - New AI tools: list_namespace (with dotted-path traversal), get_document, web_fetch, current_focus. get_method_source was renamed to get_member_source and now searches lazy slots as well as methods. senders_of and implementors_of report fully qualified dotted class paths and include lazy-slot matches. - The system prompt is a Newspeak cheat sheet, sent with Anthropic prompt caching (cache_control: ephemeral) so the cost amortizes across turns. Tool handlers are Promise-aware to support web_fetch. - Help text on every brain-enabled presenter (Class, Method, LazySlot, ClassFactory, plus the toolbar) describes the chat and the amber highlight. LazySlotPresenter gains a help button. - Misc chat UX fixes: input editor is cleared and reset to unmodified on send; draft is synced to the subject on every keystroke so it survives presenter refreshes; the chat-toggle is reinstalled fresh on each refresh so new messages render reactively; PaddedFrame around the brain always has a color (transparent vs amber) so the highlight clears correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The AI chat could read the IDE but not drive its view. Add five side-effecting tools so the model can open what it has just looked up: - navigate_to_class, navigate_to_namespace, navigate_to_document - show_tests / run_tests for test configuration classes Browsing exposes a new public navigateTo: aSubject so external callers can drive currentWindow enterSubject: without holding a presenter. AI_IDE_Support adds the tool definitions, a namespaceSubjectForPath: helper, and imports ActivationMirror as a slot (factory parameters are not in scope inside methods). run_tests mirrors respondToRunTests using ActivationMirror invokeSuspended: so a raise routes to a debugging thread. The system prompt gains a side-effecting-tools subsection so the model knows to use them only when the user has expressed intent. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… on CLI and in IDE.
Lets the AI modify code in the running IDE via two tools: propose_changes
stages a changeset and returns a textual diff plus an id; apply_changeset
runs the platform's atomic installer on the staged set. The user reviews
the diff in chat and only approved changesets ever touch the system.
Supported change kinds:
add_or_replace_method, delete_method
add_or_replace_lazy_slot, delete_lazy_slot
set_class_header
add_or_replace_nested_class, delete_nested_class
add_top_level_class
Multiple changes in one propose_changes call install atomically — meant
for mutually-dependent edits. Top-level deletion and class rename are
deliberately out of scope (different mechanism / non-atomic).
Mechanics worth noting:
* Changes are aggregated per top-level class into one
ClassDeclarationBuilder; nested navigation re-uses the cached top
builder. When descending via instanceSide.nestedClasses we patch the
nested IR's enclosingClass to the parent's instance-side
IntermediateMixin so the compiler's scope walk can reach the top
(the mirror system's lazy patch-up only runs on the bottom-up path
via mirror.asBuilder).
* primordialsoup's AtomicInstallWrapper returns mirrors but does NOT
put new top-level classes into Root; we mirror Browsing's own
post-install step (applyToObject reflectee → Root at: name).
Focus refactor — brain buttons no longer track focus by Subject identity,
which broke after any method replacement: atomic install forwards mixin
objects but not individual methods, MethodMirror equality fails,
MirrorGroupSubject>>updateElements creates a fresh MethodSubject, and the
old owner-equality check goes dark. Focus now consists of three
orthogonal pieces of state in AI_IDE_Support:
* a description block, returned by the current_focus tool
* a validator block, run on every current_focus call so a deleted or
replaced-away entity drops focus automatically (works uniformly for
explicit deletes and implicit ones like add_or_replace_nested_class)
* structured identity slots (kind / classPath / side / selector), used
by isFocusedOnX:... matchers for brain-button highlighting
Validators compare via ClassDeclarationMirror>>= (which checks the
underlying mixin), so a replaced class — whose mixin has been forwarded
— still matches; only deletions drop out.
The dead owner-based API (setFocus:, setFocus:owner:, isFocusedOwner:,
currentFocusOwner_slot) is removed; the kind-specific setXFocusOn:
helpers are the only public way to install focus. aiChatButton: now takes
an explicit ifFocused: predicate from each brain site.
Also cleaned up `slot ::= nil` to bare `slot` in AIAccess, AIChatUI, and
AI_IDE_Support — standalone mutable slots are nil-defaulted; the form
without an initializer takes no period.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… responses
Model picker
AnthropicProvider's model slot is now mutable so the chat can switch
models mid-session. The session's apiMessages history is provider-
agnostic (just text / tool_use / tool_result blocks), so switching just
routes the next turn to a different model with the full transcript as
context. AnthropicProvider exposes a curated availableModels list and
displayNameFor: with friendly labels for the picker.
ChatPresenter's heading bar grows a model picker — a label of the
current model plus a dropdown. The picker is disabled (rendered as a
dim label) while a request is in flight, to avoid switching in the
middle of a tool-use loop.
AIChatSetupSubject's default modelName is now claude-sonnet-4-6,
replacing the year-old claude-sonnet-4-20250514. The legacy id is
retained in availableModels for back-compat with existing chats.
Chat help text expanded to describe the picker, available models,
history preservation, the first-turn cache miss after a switch, and
the in-flight guard.
Defensive response handling
completeWithToolLoop now validates that the API response carries a
content array before mutating apiMessages. We have observed
intermittent 200-OK responses missing content (CDN edge case /
refusal-with-no-body / transient server glitch) — previously the
undefined value got stored as an assistant message, which corrupted
history and broke every subsequent send. Now it raises a clear error
("API response missing content. stop_reason: ...") without touching
state, so a retry just works.
displayMessages picks up a matching guard so any pre-existing
corrupted-content message in a long-running chat doesn't crash the UI.
Non-OK API responses now include statusText alongside the numeric
status — so "Anthropic API error: 429" becomes
"Anthropic API error: 429 Too Many Requests".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…error handling
Evaluation surface (AI_IDE_Support)
Five new tools — evaluate / navigate_to_object / inspect_object /
list_objects / forget_object — let the AI run expressions and refer to
results across turns:
- The AI workspace is the default receiver; created lazily as a real
IDE workspace (class AIWorkspace, subclass of Workspace, visible to
the user via the standard workspace list) by going through
WorkspaceManager.AllWorkspacesSubject>>getWorkspace:.
- Non-primitive results are stored in a per-session object registry
under auto-generated ids (r1, r2, ...) or AI-supplied names. The AI
refers to them via in_id on later evaluate calls.
- 'workspace' and 'focus' are pre-registered ids. 'focus' resolves
dynamically to the currently focused evaluator's receiver (see
below) — letting the AI write evaluate("...") and have it default
sensibly to either the workspace or whatever evaluator the user has
indicated.
Chats on evaluator panes (Browsing)
EvaluatorPresenter — the base class shared by workspaces, object
inspectors, in-method evaluator panes, lazy-slot evaluators, and
debugger activations — grows a brain button in its button row plus a
chatSection in its definition. Clicking installs a new #evaluator
focus kind whose identity is the evaluator's underlying mirror
(ObjectMirror or ActivationMirror). When that focus is active, the
AI's evaluate default routes through it via the 'focus' id, results
are appended to the focused evaluator's results list, and
Browsing>>updateCurrentDisplay (new) re-renders the IDE so the user
sees them live.
The validator handles activation lifetime: focus on a debugger frame
invalidates automatically once ActivationMirror>>isUncontinuable
becomes true (frame resumed or otherwise disposed), clearing the
focus on the next current_focus check.
Workspace UI refresh (AI_IDE_Support, Browsing)
Workspace evaluations now also append the ThreadMirror to
aiWorkspaceSubject's evaluator results list and call
updateCurrentDisplay, so AI-driven evaluations show in the AIWorkspace
presenter both live and on later navigation. The same pattern applies
to focused evaluators.
Defensive tool error handling (AIAccess)
executeToolCall:'s exception path now wraps e messageText in a fall-
back chain (messageText → printString → "<unprintable exception>")
so an oddly-shaped exception (e.g. a CannotReturn raised from a stale
stored block) can no longer silently hang the chat.
Memory note added for future me on the underlying bug: ^ inside a
stored block raises CannotReturn after the defining method exits;
tool handlers must use ifTrue:ifFalse: rather than early returns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ixes
Test result and re-run tools (AI_IDE_Support)
run_tests captures the testing subject keyed by config simple name.
Five new tools work against the cached Tester:
get_test_results counts plus per-failure/error one-liners
get_test_failure_details full description / exception detail
run_failing_tests re-run current failures
run_erroring_tests re-run current errors
run_test re-run a single named test
Test cases are identified by "ContextName >> test_selector".
Selective re-runs iterate a copy of the failure/error list (tester
run: mutates the lists) and updateCurrentDisplay so the IDE view
refreshes live. (rounded — not truncated — on the completion ratio;
Float in primordialsoup doesn't define truncated.)
Chat on test outcome view (MinitestUI)
TestingOutcomePresenter — already a ProgrammingPresenter — gains a
brain button in its heading row and a chatSection in its column.
A new #testRun focus kind identifies the run by config class path,
with description "Test results: <ConfigName>". Validator uses
classStillExists:.
Run Again creates a brand-new TestingOutcomeSubject (different object),
so Hopscotch's updateVisualsFromSameKind: chat-restore path doesn't
apply — the new presenter's chatHolder starts empty. Definition now
schedules an installAIChat when a matching #testRun focus is active,
so the chat region persists across re-runs without the user having
to re-click the brain. TestingInProgressPresenter is left alone (it
extends Presenter not ProgrammingPresenter, is transient, and is
navigated away from as soon as tests complete).
Chat input accept-button fix (AIChatUI)
Clicking the green accept button used to silently fail — CodeMirror's
setValue fires a 'change' event, which our changeResponse handler
used to write the editor text back into subject draft, so by the
time sendDraft ran, the draft was empty and the message wasn't sent.
Cmd-Return won that race. The fix bypasses subject draft entirely:
capture text locally, push it through a new ChatSubject>>sendText:
that doesn't read draft. Clear editor + leaveEditState happen BEFORE
updateGUI so the old fragment's edit-state machinery handles them
rather than a fresh post-update fragment whose handlers don't see
the old state (which had been causing the accept/cancel bar to stop
appearing on subsequent edits).
Auto-close other chats on the same page (Browsing, AI_IDE_Support)
Without coordination, clicking a different brain leaves the previous
chat region visible — multiple chat panels at once. AI_IDE_Support
tracks the active (chatHolder, pageSubject) pair; on brain click,
the previous holder is cleared ONLY when the new click is on the
same page. Cross-page navigation preserves each page's chat: A's
chat survives A → click B → click → back to A. Page identity is
Browsing's currentWindow currentPresenter subject, surfaced via
Browsing>>currentPageSubject.
Boolean and: chains one block, not two — Smalltalk-ism caught after
the first build broke per-presenter brains with "False and:and:".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…list/delete media Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…us eof conflict with accept/cancel buttons.
…s the problem that the top line may not be visible if the line is short or overlaps with the accept/cancel buttons. Change show evey editor displays changes, so not great. Eventually, w emay want to change how the display of changes works so we get a signal distinct from the change buttons.
…egration, multi-doc switching, live-view reactivity, generic-doc brain, defensive extractTextFrom Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…key storage, defensive translation, surface API error bodies Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se/Newspeak-exception bridge bug, surface API errors as in-chat turns, add provider chooser to setup Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hopscotch now owns AIChatUI as a lazy module instance constructed from a platform-level aiAccess and an aiChatUIClass re-export, so HopscotchWebIDE and AI_IDE_Support no longer instantiate the AI modules themselves. They pull presenter classes and the chat module through platform hopscotch, keeping the Hopscotch factory signature unchanged. Also a type-annotation and comment pass across AIAccess, AIChatUI, and AI_IDE_Support to document the provider abstraction, the chat-document projection model, and the JS Promise/then: rejection idiom that replaced in-closure Error signal: raises. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The chat UI classes (AIColors, AIChatSetupSubject, AIChatSetupPresenter, ChatSubject, ChatStatusPresenter, ChatInputPresenter, ChatPresenter) now live as sibling top-level classes inside HopscotchForHTML5 rather than as a separate AIChatUI module. This removes the construction cycle that required Hopscotch to retain a private platform reference and a lazy aiChatUI slot, and removes the unnatural Platform.aiChatUIClass accessor. AIAccess slot block is reshaped to do only class imports plus a platform handle; its JS-side handles (global, JSON, Promise) become lazy module-body slots in AIAccess itself. This lets Hopscotch's slot block safely call `p aiAccess` during platform init, since AIAccess construction no longer touches JS aliens that aren't yet usable at snapshot time. AI_IDE_Support drops its chatUI slot and pulls colours through a new aiColors slot — a single small utility class on Hopscotch keeps the import surface tidy. The Hopscotch factory signature is unchanged, so Croquet and other Hopscotch consumers don't need any edits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GeminiProvider previously inherited the Provider default hasToolUse:
^false, so the Session's tool loop was bypassed entirely. It now
translates Gemini function-calling to and from the same tool-block
surface Session already drives for Anthropic.
Provider gains addToolResults:toMessages: as a new required hook for
tool-supporting providers, factored out of completeWithToolLoop's
inline tool_result-message assembly. AnthropicProvider's implementation
is the lifted inline code unchanged. GeminiProvider's wraps the round's
parts as {role: 'user', parts: [...]}.
Gemini-side translation:
- buildToolsPayload: produces [{functionDeclarations: [...]}], with each
declaration using 'parameters' (Gemini) rather than 'input_schema'
(Anthropic) for the JSON schema.
- hasToolUse: / toolUseBlocksFrom: scan candidates[0].content.parts for
functionCall parts. Gate on functionCall.name being non-nil, not on
functionCall itself — on text-only parts the missing functionCall
field surfaces as JS undefined which fails isNil, and a fc-isNil-
ifFalse guard incorrectly admits text parts and yields malformed
shims.
- Gemini issues no tool-call ids of its own, so toolUseBlocksFrom:
synthesises a 'gem-N' id per call and stashes the name in a per-round
pendingCallNames map. The shim blocks expose the same 'id', 'name',
'input' surface Anthropic emits, so Session.executeToolCall: needs no
provider-specific path.
- makeToolResult: builds a functionResponse part, recovering the
function name from pendingCallNames. Gemini has no standard is_error
flag; failure text goes under 'error' instead of 'result'.
- doRequest: now accepts and plumbs the tools payload into the request
body; complete: and attemptComplete: thread it through.
Bulletproof alien field reads (cross-cutting; surfaced during Gemini
bring-up but applies to both providers):
- New Provider helper safeStringAt: receiver field:. Returns the value
only if a real String (verified by v , '' succeeding). Returns nil
for missing fields, JS undefined, JS null, numbers, objects — any-
thing that fails the no-op concat. Cheap, no JSON round-trip.
Necessary because primordialsoup's alien bridge does not uniformly
convert JS undefined to Newspeak nil; a missing field on a JS object
often returns JS undefined which doesn't satisfy isNil, and the
previous isNil-ifFalse guards admitted it into String concats and
crashed with ArgumentError.
- All scalar string-leaf reads in both providers' response-walking code
(extractTextFromResponse:, displayMessagesFromMessages:, hasToolUse:,
toolUseBlocksFrom:) now go through safeStringAt:. safeAt: continues
to handle structural navigation (returns nil for missing receivers /
fields but doesn't normalise undefined leaves).
Robust error surfacing:
- New module-body errorDescription: helper extracts a non-nil String
from any exception. Tries messageText, falls back to class name
printString, then printString, then '<unprintable exception>'. Each
step wrapped so no failure in the chain can sink the whole error
path.
- The four Promise.reject sites (AnthropicProvider doRequest:,
GeminiProvider doRequest:, Session completeWithToolLoop, webFetch:)
now route through errorDescription: instead of bare e messageText,
which was nil-prone and made the chat error turn read 'nil'.
- Session completeWithToolLoop's outer catch now ships the raw provider
response in the rejection ('[stage: X] <error> | response: {...}'),
so future protocol drift or a new provider's first unexpected
message shape lands directly in the chat — no fresh diagnostic
instrumentation needed when the AI vendor tweaks their format or a
new provider follows the recipe.
- Stage tracking in completeWithToolLoop and executeToolCall: pinpoints
which substep of response processing failed. JSON dump of the
problematic tool-call block in executeToolCall:'s structural-error
paths surfaces malformed shims directly.
Browsing.ns: ProgrammingPresenter>>aiChatButton:ifFocused: gained
multi-stage error reporting on click. The previous on:Error do:
formatted 'AI chat error: ', e messageText, which itself crashed when
messageText was nil — silently turning a recoverable UI failure into a
hard IDE freeze. The new handler tracks the substep being executed
(read activeChatHolder, install focus, install AI chat, etc.) and uses
a nested catch that falls back through messageText, class name, and
printString.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hat doc Three related cleanups to the AI-chat entry points. Hide-key toggle (HopscotchForHTML5.ns AIChatSetupPresenter): - The API key editor now lives inside a ToggleComposer. Initial state follows a new keyRevealed slot: revealed (=true) on first-time setup when subject apiKey is empty, concealed (=false) once a key has been stored. The user can expand or collapse manually; the editor's acceptResponse: collapses the toggle on Accept and respondToStart collapses on successful chat start. Both push keyRevealed:: false via updateGUI:, but the close also calls keyToggle collapse directly to mutate the *old* toggle's isExpanded — ToggleComposer's update- VisualsFromSameKind: copies isExpanded from the old fragment, so a fresh toggle with initiallyExpanded:false alone wouldn't actually close after the first render. Provider-switch resync (AI_IDE_Support.ns IDEChatSetupPresenter): - Replaces the inline providerPicker action blocks with a new respondToProviderSwitch:defaultModel: that resyncs presenter state to the newly-chosen provider. Just mutating subject providerName / modelName / reloadApiKey wasn't enough: ToggleComposer preserves old isExpanded across re-renders, and CodeMirrorFragment preserves the old editor's text, so the visible form lagged behind the subject. The new method explicitly toggles keyToggle, updates keyEditor's textSlot, and updates modelEditor's textSlot in the same updateGUI: block, so the diff inherits the right state. Toolbar → chat doc (AI_IDE_Support.ns chatLauncher): - Toolbar AI Chat button now navigates to the active chat doc's full DocumentSubject view (Ampleforth contents with chatControls, doc switcher, model picker, structural amplets, turns as HTML sections) — the canonical home of the chat. Previously it landed on the bare IDEChatPresenter view, which lacks all of those. ensureSharedChat (used by per-presenter brain buttons for the inline ephemeral chat region) is unchanged; the two paths now give appropriately different UX for the same conversation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ChatDocument>>noteLiveViewRendered: stores the current TwoViewEditor on the doc each time its DocumentPresenter renders, but the slot is never cleared when the user navigates away. A chat-subject side effect (sendText:, markComplete, markError:) firing AFTER navigation — e.g. a tool-loop response resolving on a chat we just switched away from — then calls refresh on the now-detached editor. That walks into shell on a parent-less DocumentPresenter and raises 'hierarchy not installed in a shell'. Fix: refreshLiveView probes the cached editor's liveness by asking for shell; if walking the parent chain raises, the slot is stale, so we drop it and return. The next render of this doc installs a fresh editor via noteLiveViewRendered: and subsequent refreshes work against that. This is a narrow patch for the immediate footgun. The broader chat- document reactivity / deactivation story still wants a proper hook (see CHAT_SWITCHING_FOLLOWUPS_2026-05-18.md item 1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.