Deep agent resolution in the sidecar now walks sub-workflow nodes so
nested agents carry subworkflowNodeId and subworkflowName on activity
events. New subworkflow-started / subworkflow-completed activity types
let the frontend track sub-workflow lifecycle.
The Activity panel groups nested agents under collapsible sub-workflow
cards with status badges, accent-colored left borders, and smooth
expand/collapse transitions. Cards auto-expand when a sub-workflow
starts running. Workflows without sub-workflow nodes render identically
to before.
Extracted AgentRow, SubWorkflowGroup, and shared accent constants to
a new components/activity/ feature directory. Added
resolveWorkflowAgentHierarchy and buildGroupedActivityRows for
hierarchical activity grouping with dynamic fallback for unresolved
sub-workflow agents.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add toolArguments to normalizeRunTimelineEvent output so persisted
sessions retain tool argument data across app restarts
- Add toolArguments field to AgentActivityState and propagate it in
applySessionEventActivity for real-time activity labels
- Add tests for normalization round-trip with and without toolArguments
- Add test for activity state including toolArguments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When toolArguments doesn't contain the expected key (e.g. 'path' for
view), fall back to the first usable string value from any argument
key instead of showing misleading placeholders like 'Viewed a file'.
When no arguments exist at all, show just the tool name.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the flat, repetitive 'Agent used X' activity list with a
structured narrative timeline:
- Group consecutive same-tool calls into collapsible rows with context
(e.g. 'Viewed 4 files' with file names listed below)
- Use verb-based labels with arguments: 'Viewed ChatPane.tsx:148-250',
'Searched for tool-call', 'Edited runTimeline.ts'
- Promote report_intent events to phase dividers that segment the
timeline into labeled stages of work
- Show latest intent text in the collapsed header summary
- Use category-specific icons (Eye, Search, Pencil, Terminal, etc.)
instead of the universal wrench
- Render thinking steps as quoted blocks with 'N more' toggle for
consecutive groups
All data was already available in RunTimelineEventRecord.toolArguments;
this change surfaces it prominently instead of hiding it behind
expandable detail panels.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract seven responsibility clusters from the 3,466-line AryxAppService
monolith into focused service classes under src/main/services/:
- WorkflowManager: workflow CRUD, templates, validation, resolution
- McpProbeManager: MCP server probing, OAuth pre-auth, probe queuing
- DiscoveredToolingSyncService: tooling/customization scanning, watchers
- GitContextManager: git refresh orchestration, context updates, mutations
- CheckpointRecoveryManager: checkpoint retry/recovery state handling
- ApprovalCoordinator: approval/user-input/plan-review/OAuth state machine
- SessionTurnExecutor: turn execution, streaming deltas, finalization
AryxAppService remains the public facade consumed by IPC handlers but now
delegates internally via constructor-injected service instances. A new
AppServiceDeps type provides a clean dependency injection seam for testing.
The facade is reduced from 3,466 to 2,572 lines. All existing tests pass
with two test files migrated to constructor DI (appServiceGitRefresh,
appServiceMcpProbing). New focused tests added for WorkflowManager and
the DI seam itself.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thread toolArguments from the sidecar through shared contracts, main-process pipeline, and into the renderer. Add ToolCallDetailPanel with inline summaries (command, path, pattern, etc.) and expandable argument details for every tool-call event in the activity timeline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In sequential workflows, multiple collapsible turn-activity panels shared
the same SessionRunRecord and displayed identical aggregate metrics (tool
calls, approvals, etc.) instead of per-agent counts.
Root cause: ChatPane grouped thinking messages correctly per agent, but
passed the full unfiltered run object to every TurnActivityPanel, so
summarizeActivity() counted all events from the entire run for each panel.
Changes:
- Extract filterEventsByAgent() and summarizeActivity() to
runTimelineFormatting.ts as pure, testable helpers
- Add agentNames (derived from thinking message authors) and isLastRunPanel
to the DisplayItem turn-activity variant in ChatPane
- TurnActivityPanel now filters run.events through filterEventsByAgent()
so each panel only counts events belonging to its agents
- Git summary / discard actions only render on the last panel of a run
- Per-agent timing derived from scoped events instead of run-level start
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
For builder-based orchestration modes (group-chat, handoff), the loop edge
maxIterations, workflow settings.maxIterations, and mode-specific settings
(e.g. groupChat.maxRounds) were independently editable but only the mode
settings controlled runtime behavior. This caused confusion when changing
one did not update the others.
Changes:
- Add syncBuilderModeEdgeIterations() to keep loop edge maxIterations in
sync with the authoritative mode settings for builder-based modes
- Wire sync into normalizeWorkflowDefinition so edges are consistent on
load/normalization
- Update scaffoldGraphForMode to accept optional settings instead of
hardcoded iteration values (4 for handoff, 5 for group-chat)
- Sync settings.maxIterations <-> groupChat.maxRounds bidirectionally
when either changes in the UI
- Make loop edge controls read-only in the graph inspector for
builder-based modes with explanatory text
- Add 8 consistency tests validating built-in workflows, scaffold
behavior, and normalization sync
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Show agent activity label in chat header (Thinking…, Using bash…, etc.)
instead of an anonymous pulsing dot
- Fix ThinkingProcess elapsed timer to tick live every second using
useElapsedTimer hook instead of stale useMemo computation
- Show completed/failed subagents for 3s grace period with fade-out
transition instead of instantly hiding them
- Transition activity labels to Completed state for 1.5s grace period
on session idle instead of abrupt removal
- Eliminate message flash during thinking reclassification by folding
trailing pending assistant messages into the thinking group
optimistically when they follow existing thinking messages
- Stabilize ThinkingProcess isActive flag by checking for pending
messages in the group rather than relying solely on array position
- Skip rendering empty pending messages inside ThinkingProcess steps
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The forward edges from triage to specialists participate in cycles
(triage→specialist + specialist→triage), so they must be marked with
isLoop, condition, and maxIterations to pass validation.
Fixes the Handoff Support Flow template and scaffoldGraphForMode()
for handoff mode. Updates the corresponding test expectation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add first-class backend support for workflow orchestration modes,
including mode settings, graph scaffolding, mode-aware validation,
and real Agent Framework handoff/group-chat execution paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Delete src/shared/domain/pattern.ts and all pattern-specific renderer
components (PatternEditor, NewSessionModal, pattern-graph directory,
patternGraph lib) and their tests
- Migrate all renderer imports from @shared/domain/pattern to
@shared/domain/workflow (ReasoningEffort, reasoningEffortOptions,
WorkflowOrchestrationMode, AgentNodeConfig, WorkflowDefinition)
- Update App.tsx: remove workflowToPattern bridge, createDraftPattern,
NewSessionModal; sessions now created directly with default workflow
- Update ChatPane, ActivityPanel, Sidebar to accept WorkflowDefinition
instead of PatternDefinition and derive agents/mode from workflow
- Update SettingsPanel: remove PatternsSection nav item, pattern editing
state, and pattern-related props; update text references
- Update RunTimeline and modeAccent/modeVisuals records to use
WorkflowOrchestrationMode (drop magentic mode entry)
- Update sessionActivity.ts to use generic agent interface
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the invented code-executor node type entirely. Rename
function-executor to invoke-function to match Agent Framework's
InvokeFunctionTool declarative action. Update InvokeFunctionConfig to
use functionName, arguments, requireApproval, and resultVariable
properties matching the upstream schema.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- add shared workflow template and serialization helpers for YAML, Mermaid, and DOT export
- add pattern-to-workflow upgrade and template application flows in AryxAppService
- persist built-in and custom workflow templates in workspace state and expose new IPC/preload methods
- cover the new backend slice with shared and app-service tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add MVP code-executor and function-executor runtime support, request-port
bridging through Aryx user input, state-scope helpers, lockstep execution
mode handling, and validation/tests for new workflow node kinds.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the restriction that prevented users from deleting built-in
patterns (those with IDs prefixed 'pattern-'). Built-in patterns are
intended as starting points, not permanent fixtures.
Changes:
- Add deletedBuiltinPatternIds field to WorkspaceState to track which
built-in patterns the user has removed
- Update mergePatterns to skip deleted built-ins during workspace load,
preventing them from being re-added
- Remove the isBuiltinPattern guard from AryxAppService.deletePattern;
when a built-in is deleted, its ID is recorded in the tracking list
- Enable the delete button in SettingsPanel and PatternEditor for all
patterns (keep the 'Built-in pattern' label for context)
- Add 3 tests covering built-in deletion, custom deletion, and
selectedPatternId fallback
Users can still restore deleted built-ins via workspace reset.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a workspace-level agent library that allows users to define
agents once and reference them from multiple orchestration patterns.
Domain model:
- Add WorkspaceAgentDefinition type with name, model, instructions, etc.
- Extend PatternAgentDefinition with optional workspaceAgentId and overrides
- Add resolution helpers that merge workspace agent base with per-pattern overrides
- Extend WorkspaceSettings with agents array and normalize on load
IPC & main process:
- Add saveWorkspaceAgent/deleteWorkspaceAgent IPC channels and handlers
- Resolve workspace agent references in buildEffectivePattern before
sending to sidecar (no C# changes needed)
Settings UI:
- Add 'Agents' tab under Orchestration in the Settings panel
- Create WorkspaceAgentEditor component using ToolingEditorShell
- Show usage count (which patterns reference each agent)
Pattern editor integration:
- Add agent picker dropdown: 'New inline agent' or 'From library'
- Show linked badge (chain icon) on referenced agent graph nodes
- Show linked workspace agent banner in the inspector
- Add 'Save to Agent Library' action to promote inline agents
- Add 'Unlink' action to convert referenced agents back to inline
Tests:
- Add unit tests for resolution helpers (resolvePatternAgent,
resolvePatternAgents, findWorkspaceAgentUsages, normalize)
- Update existing tooling test for new agents field
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- parse prompt model and argument-hint metadata and persist model on prompt invocations
- expand markdown-linked file context in scanned prompt and instruction bodies
- discover .claude/rules instructions and support Claude-style paths metadata
- discover customization roots up to the nearest parent repository and watch them for changes
- apply per-turn prompt model overrides before sidecar execution
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Surface workflow-diagnostic session events (warnings and errors from
Agent Framework workflows) in the turn-event log of the Activity Panel.
- Add workflow-diagnostic case to formatTurnEventEntry with label/detail
formatting that includes executor ID, subworkflow ID, exception type,
and diagnostic message when present
- Add AlertTriangle icon for diagnostic events with error/warning color
- Add 5 tests covering executor-failed, workflow-warning, subworkflow-error,
workflow-error, and missing diagnosticKind fallback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the single aggregate thinking tile with per-turn thinking groups.
Instead of collecting all thinking messages into one flat array and
rendering a single ThinkingProcess before the last assistant message,
process session.messages in chronological order to produce interleaved
display items that naturally group consecutive thinking messages by turn.
Each turn now shows its own collapsible thinking tile placed inline
before its assistant response, with correct per-turn isActive state
and turnStartedAt from the matching run.
Also fixes a latent index-mismatch bug in getAssistantMessagePhase where
the visible-messages index was compared against the full session.messages
index, potentially hiding the Final badge when thinking messages existed.
Switched to ID-based comparison.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the isPackaged guard from AutoUpdateService.start() so that
background update checks run in both packaged and dev builds.
forceDevUpdateConfig already handles dev-mode config correctly via
dev-app-update.yml — the start() gate was preventing the 10s initial
check and 4h periodic checks from ever being scheduled in dev.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wire message-reclassified sidecar events through the main process to
the renderer, where reclassified messages are filtered out of the main
transcript and collected into a collapsible ThinkingProcess component.
Main process changes:
- Route message-reclassified via dedicated onMessageReclassified callback
- Add applyMessageReclassified handler that sets messageKind and emits
the session event for the renderer
- Forward assistant-intent and reasoning-delta as turn-scoped events
Renderer changes:
- Split session.messages into visibleMessages and thinkingMessages
- Render ThinkingProcess above the last assistant message
- ThinkingProcess auto-expands during active turns, collapses on finish
- Update messagePhase to skip thinking-kind messages for final detection
Tests:
- 3 new sessionWorkspace tests for reclassification apply/dedup/ignore
- 2 new messagePhase tests for thinking-kind handling
- Updated runTurnPending test fixtures for new callback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add dev-app-update.yml so electron-updater can check GitHub releases
even when running with bun run dev. Remove the isPackaged guard from
checkForUpdates() so manual clicks always contact the update server.
Automatic periodic checks remain disabled in dev mode.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When electron-updater reports no update available, the service now
transitions to 'up-to-date' instead of reverting silently to 'idle'.
The troubleshooting UI shows a green check icon, 'Up to date' label,
and 'You are running the latest version of Aryx.' description.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When multiple MCP servers expose tools with the same name, the approval
pill showed an incorrect count (e.g. 150/300) even when everything was
approved. The numerator used a Set<string> to deduplicate by tool ID,
so shared tools were counted once, while the denominator counted each
group occurrence independently.
Extract countApprovedToolsInGroups() into shared/domain/tooling.ts and
switch to per-group counting that mirrors the totalItemCount formula.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Relax branchSessionRecord validation to accept user or assistant roles
- Show "Branch from here" hover button on all conversation messages
- Contextual tooltip: "starting from this message" vs "continuing from this response"
- Add test for branching from assistant message
- Replace non-user rejection test with non-conversation rejection test
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the backend contract and session-domain support for
'Branch from here':
- new branchSession IPC method and sessions:branch channel
- branchOrigin metadata on SessionRecord
- session branching helper that truncates the transcript at a
chosen user message and clears runtime state
- AryxAppService branching flow with scratchpad directory support
- persistence normalization and regression coverage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add three layers of usage visibility:
- ChatPane footer: premium request count, AIU consumed, and quota
remaining below the existing context-window bar
- Settings / CopilotStatusCard: on-demand account quota section with
progress bars, overage indicators, and reset dates fetched via
the new get-quota sidecar command
- Activity Panel: per-agent token/cost/duration totals on each agent
row and a Session Usage summary section between agents and timeline
Backend (sidecar):
- New get-quota command using SDK account.getQuota RPC
- New assistant-usage turn-scoped event from SDK assistant.usage
- QuotaSnapshotMapper for both typed and untyped SDK quota payloads
- DTOs: GetQuotaCommandDto, QuotaSnapshotDto, AccountQuotaResultEventDto,
AssistantUsageEventDto
Frontend:
- Shared types: AssistantUsageEvent, QuotaSnapshot, GetQuotaCommand
- IPC bridge: getQuota channel, assistant-usage event dispatch
- State: SessionRequestUsageMap accumulator with per-agent breakdown
- 8 new tests for accumulator logic and formatting helpers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CodeHighlightPlugin's selection restoration could create an invalid
Lexical selection targeting a LineBreakNode with type 'element'. Since
LineBreakNode is not an ElementNode, Lexical threw during reconciliation
and the LexicalErrorBoundary replaced the editor with an error state.
The fix ensures findPoint never targets a LineBreakNode directly.
Instead it falls back to an element-level selection on the parent
CodeNode using the child index, which is always a valid target.
Extracted the selection helpers (getCodeNodeAbsoluteOffset,
findCodeNodeSelectionPoint, restoreCodeNodeSelection) into
markdownEditor.ts for testability and added regression tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Display compact status cards in the chat transcript showing each
sub-agent's name, current activity (Thinking, Using grep, etc.),
and elapsed time. Cards appear while sub-agents are running and
clear when the session goes idle.
- Extend SessionEventRecord with description, error, toolCallId,
and model fields for subagent events
- Forward additional subagent fields in handleTurnScopedEvent
- Add subagentTracker reducer to derive active subagent state from
session events, including agent-activity correlation
- Create SubagentActivityCard component with spinner, status icon,
agent name, activity label, and live elapsed timer
- Wire activeSubagents state in App.tsx and pass to ChatPane
- Add 16 unit tests for the subagent tracker
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the agent produces multiple intermediate responses during a turn,
each gets a unique messageId but all stay pending until finalizeTurn().
This caused multiple stacked 'Thinking' bubbles in the chat transcript.
Now, when a new messageId arrives in applyTurnDelta, any previously
pending assistant messages are marked complete and message-complete
events are emitted before the new message-delta. The renderer reducer
mirrors this logic for defensive consistency.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- add a PTY manager with platform shell resolution and streamed data/exit events
- expose terminal lifecycle and terminal height IPC through preload and app service
- persist terminal panel height in workspace settings and document the backend contract
- add backend tests and validate native packaging with bun run package
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mergeDiscoveredToolingState now carries over probedTools from existing
servers when the config fingerprint is unchanged. The equality check in
syncProjectDiscoveredTooling also strips probedTools before comparing,
so runtime-only probe data never triggers a spurious state replacement.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Some MCP servers (e.g., eschat.microsoft.com/mcp) serve their
OAuth Protected Resource Metadata at the origin without the path
suffix. Add a third candidate URL that strips the path, matching
VS Code's discovery behavior.
Tried in order:
1. RFC 9728: {origin}/.well-known/{suffix}{path}
2. Appended: {origin}{path}/.well-known/{suffix}
3. Origin-only: {origin}/.well-known/{suffix}
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>