Skip to content

Merge with upstream#2

Open
Outcue wants to merge 763 commits into
Outcue:masterfrom
newspeaklanguage:master
Open

Merge with upstream#2
Outcue wants to merge 763 commits into
Outcue:masterfrom
newspeaklanguage:master

Conversation

@Outcue
Copy link
Copy Markdown
Owner

@Outcue Outcue commented Aug 8, 2021

No description provided.

gbracha added 30 commits April 2, 2024 20:06
… 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.
… 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.
…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.
gbracha and others added 30 commits April 16, 2026 10:13
…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>
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>
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants