Skip to content

Reconcile PTY agent sessions into the unified AIChat provider-mode model #1220

Closed

Description

@malibio

Context

The docs were unified in nodespace-docs PR #47 (merge 140e524) — see ADR-034: AIChat Provider Modes, which reframes PTY agent sessions as provider mode 2d of the ai-chat node rather than a standalone subsystem. ADR-032's PTY mechanics remain authoritative; only the product framing changed.

The code still reflects the old standalone model and needs reconciling to match the documented target. This issue tracks that reconciliation. No code was changed in PR #47 (docs only).

Target model (per ADR-034)

ai-chat is one node type with four provider modes: native (2a), ollama (2b), openai (2c), pty (2d).

  • A PTY session is an ai-chat node (provider: pty), created up front via the /ai-chat slash command as a placeholder → user selects mode + agent → session launches.
  • For mode 2d, the terminal (xterm.js) is the node's viewer — the "iframe" — not a separate panel.
  • Capture backfills the existing node with transcript/session-id/metadata; it does not mint a node at session end.
  • A user can create as many ai-chat sessions as they want — N sessions = N nodes, anywhere in the graph.

Current state (the gap)

Surface Today (standalone) Target (unified)
Entry point agent-sessions tab + launch panel only /ai-chat slash command → placeholder node
Terminal pty-terminal.svelte driven by sessionId prop inside a separate panel cluster Rendered as the ai-chat node's viewer for provider: pty
Node creation Minted at session end by capture_service.rs Node exists up front; capture backfills it
Viewer wiring ai-chat-node-viewer.svelte (registered viewer) is disconnected from the PTY terminal Viewer dispatches by provider: message UI (2a/2b/2c) vs embedded terminal (2d)

Files involved (starting points, not exhaustive)

Frontend — standalone cluster to fold in / remove:

  • packages/desktop-app/src/lib/components/agent/agent-sessions-panel.svelte
  • packages/desktop-app/src/lib/components/agent/agent-launch-panel.svelte
  • packages/desktop-app/src/lib/components/agent/sessions-panel.svelte
  • packages/desktop-app/src/lib/components/agent/pty-terminal.svelte (keep the xterm wrapper; re-host it as the 2d viewer)
  • agent-sessions tab wiring: stores/navigation.ts, stores/layout.ts, components/layout/pane-content.svelte, components/layout/navigation-sidebar.svelte, services/tab-persistence-service.ts

Frontend — viewer to extend:

  • packages/desktop-app/src/lib/components/viewers/ai-chat-node-viewer.svelte — dispatch on provider; render embedded terminal for pty
  • packages/desktop-app/src/lib/plugins/core-plugins.ts — ai-chat viewer registration

Backend — capture: mint → backfill:

  • packages/daemon/src/services/capture_service.rs — currently "creates an `ai-chat` node at PTY session end"; change to backfill the node created at launch
  • packages/agent/src/pty/ — PTY mechanics (unchanged per ADR-032)

Acceptance criteria

  • /ai-chat creates a placeholder ai-chat node with no provider/model/agent selected
  • User can select any of the four provider modes (native/ollama/openai/pty) on the node before launch
  • For provider: pty, the embedded terminal renders as the node's viewer (no separate agent-sessions tab/panel)
  • Capture backfills the existing node on session end instead of minting a new one (capture_service.rs)
  • The standalone agent-sessions tab and its launch/sessions panels are removed (per CLAUDE.md: delete old patterns, no dual-mode)
  • Multiple concurrent ai-chat sessions can be created, each its own node
  • Mode 2d capture is limited (transcript/session-id/metadata), not structured messages[] — documented behavior, not a bug
  • No regressions to PTY mechanics (launch/stream/write/resize/terminate per ADR-032)

Out of scope

  • Context pre-assembly (playbook → assembly → launch). Deferred to a separate design session per ADR-034; the playbook engine (packages/core/src/playbook/) is the upstream half but the assembly mechanism is unspecified.

References

  • ADR-034 (AIChat provider modes) — nodespace-docs decisions/034-aichat-provider-modes.md
  • ADR-032 (PTY mechanics) — nodespace-docs decisions/032-pty-agent-session-architecture.md
  • architecture/ai-chat-node.md, architecture/agent-session.md
  • Docs unification: nodespace-docs PR Hybrid Markdown Rendering #47 (140e524)

Activity

  1. malibio commented on May 28, 2026

    @malibio
    CollaboratorAuthor

    Mode 2d (PTY) capture — scope decision

    Follow-up to the docs (nodespace-docs PR #48, refining ADR-034). After reading packages/agent/src/pty/capture.rs and packages/daemon/src/services/capture_service.rs, the PTY layer only exposes raw terminal bytes (ANSI codes, TUI repaints, 1 MiB ring buffer). So mode 2d capture is deliberately scoped:

    • 2d holds a reference/summary + metadata, NOT a searchable conversation. No structured messages[]. Conversation search lives in 2a/2b/2c only.
    • The summary is derived and best-effort — not a slice of the raw buffer.

    Additional acceptance criteria / sub-tasks for the capture rework

    • capture_service.rs: backfill the existing node (created at /ai-chat launch) instead of minting one at session end
    • 2d node stores: reference + metadata (capture:agent_type, capture:started_at/ended_at, capture:exit_code, capture:session_id) — already present; keep
    • ANSI-strip the transcript in capture.rs (transcript()/summary() currently store raw bytes via from_utf8_lossy; ADR-032's "ANSI-stripped" claim is aspirational). Prerequisite for any usable summary.
    • Summary generation (best-effort, derived): summarize the stripped transcript with a conversational provider that is not the PTY agent —
      • prefer the built-in nlp-engine (mode-2a model) when a model is downloaded
      • else a configured OpenAI-protocol endpoint (2b Ollama / 2c BYO-key)
      • else fall back to reference + metadata only (no summarizer available — must not be a hard dependency)
    • (Optional, complementary) capture structured provenance from @nodespace/agent-tools gRPC calls during the session → created_nodes[] / mentions edges, independent of terminal parsing
    • Do not read agent-local session logs (~/.claude/, ~/.codex/) — per-agent, brittle, non-portable (ADR-032)

    Current capture_service.rs field reference (for the rework)

    The existing payload already namespaces 2d-specific fields under capture: and sets status: archived, provider: native (the latter should become pty). Content levels (metadata_only / summary / full) map onto the above; note today's summary() is just the first 500 raw bytes — replace with the derived summary.

    Ref: nodespace-docs ADR-034 (Capture section), PR #48.

  2. malibio commented on May 28, 2026

    @malibio
    CollaboratorAuthor

    Starting #1220. Frontend baseline: 3843 passed, 93 failed (130 files). The 93 failures are pre-existing and environmental — localStorage is undefined under Happy-DOM in layout-persistence-service / tab-persistence-service / expansion-state-persistence suites; verified identical on clean origin/main, unrelated to this issue.

  3. self-assigned this
    on May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions