feat: full Copilot SDK feature parity — custom agents, hooks, image input, skills, steering, session persistence

Backend (sidecar):
- Extended ProtocolModels with DTOs for custom agents, hooks, skills,
  infinite sessions, session lifecycle, and 9 new event types
- Added CopilotManagedSessionIds for stable SDK session ID mapping
- Added CopilotSessionManager/ICopilotSessionManager for session lifecycle
- Added CopilotSessionHooks for hook registration
- Added CopilotMessageOptionsMetadata for mid-turn steering
- Extended CopilotAgentBundle to wire custom agents, hooks, skills,
  infinite sessions, and stable session IDs
- Extended CopilotTurnExecutionState to project 13 new SDK event types
- Widened ITurnWorkflowRunner callback to accept SidecarEventDto
- Added list/delete/disconnect session commands to SidecarProtocolHost
- Added AryxCopilotAgentMessageOptionsTests (14 new tests, 142 total)

Frontend (renderer + main + shared):
- Added ChatMessageAttachment type and helpers (attachment.ts)
- Extended sidecar contracts with MessageMode, 3 new command types,
  9 new event types, and agent/session config DTOs
- Extended SessionEventRecord with 6 new event kinds and ~20 fields
- Added PatternAgentCopilotConfig to pattern domain
- Added attachments support to ChatMessageRecord
- Updated sidecar client with session lifecycle methods and
  turn-scoped event routing via onTurnScopedEvent callback
- Updated main process: handleTurnScopedEvent(), deleteSession(),
  steering bypass for mid-turn messages, attachment passthrough
- Added deleteSession IPC handler and preload binding
- Added TurnEventLog state tracker with format/apply/prune helpers
- ChatPane: always-enabled composer, steering indicator, attachment
  picker with preview, image thumbnails in message history,
  context-usage bar, amber steer mode for send button
- ActivityPanel: turn events section with sub-agent, hook, skill,
  and compaction event rendering
- Sidebar: delete session action in context menu
- App.tsx: wired sessionUsage, turnEventLogs, and deleteSession

Documentation:
- AGENTS.md: added glob safety rule for node_modules
- README.md: added steering, image input, and richer observability
- ARCHITECTURE.md: added turn-scoped events, steering, and attachments
- Website: added steering and image input feature cards, updated
  live visibility and session cards

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-28 12:28:20 +01:00
co-authored by Copilot
parent 0c2973c599
commit f1fa52f9c3
40 changed files with 2515 additions and 92 deletions
+42
View File
@@ -0,0 +1,42 @@
export type ChatMessageAttachmentType = 'file' | 'blob';
export interface ChatMessageAttachment {
type: ChatMessageAttachmentType;
path?: string;
data?: string;
mimeType?: string;
displayName?: string;
}
const supportedImageMimeTypes = new Set([
'image/jpeg',
'image/png',
'image/gif',
'image/webp',
]);
export function isImageAttachment(attachment: ChatMessageAttachment): boolean {
if (attachment.mimeType) {
return supportedImageMimeTypes.has(attachment.mimeType);
}
if (attachment.path) {
const ext = attachment.path.split('.').pop()?.toLowerCase();
return ext === 'jpg' || ext === 'jpeg' || ext === 'png' || ext === 'gif' || ext === 'webp';
}
return false;
}
export function getAttachmentDisplayName(attachment: ChatMessageAttachment): string {
if (attachment.displayName) {
return attachment.displayName;
}
if (attachment.path) {
const parts = attachment.path.replace(/\\/g, '/').split('/');
return parts[parts.length - 1] || attachment.path;
}
return attachment.mimeType ?? 'Attachment';
}
+37 -1
View File
@@ -8,7 +8,15 @@ export type SessionEventKind =
| 'message-complete'
| 'agent-activity'
| 'run-updated'
| 'error';
| 'error'
| 'subagent'
| 'skill-invoked'
| 'hook-lifecycle'
| 'session-usage'
| 'session-compaction'
| 'pending-messages-modified';
export type SubagentEventKind = 'started' | 'completed' | 'failed' | 'selected' | 'deselected';
export interface SessionEventRecord {
sessionId: string;
@@ -27,4 +35,32 @@ export interface SessionEventRecord {
toolName?: string;
run?: SessionRunRecord;
error?: string;
// Subagent event fields
subagentEventKind?: SubagentEventKind;
customAgentName?: string;
customAgentDisplayName?: string;
// Skill invoked fields
skillName?: string;
skillPath?: string;
pluginName?: string;
// Hook lifecycle fields
hookInvocationId?: string;
hookType?: string;
hookPhase?: 'start' | 'end';
hookSuccess?: boolean;
// Session usage fields
tokenLimit?: number;
currentTokens?: number;
messagesLength?: number;
// Session compaction fields
compactionPhase?: 'start' | 'complete';
compactionSuccess?: boolean;
preCompactionTokens?: number;
postCompactionTokens?: number;
tokensRemoved?: number;
}
+3
View File
@@ -32,6 +32,8 @@ export const reasoningEffortOptions: ReadonlyArray<{ value: ReasoningEffort; lab
{ value: 'xhigh', label: 'Maximum' },
];
import type { PatternAgentCopilotConfig } from '@shared/contracts/sidecar';
export interface PatternAgentDefinition {
id: string;
name: string;
@@ -39,6 +41,7 @@ export interface PatternAgentDefinition {
instructions: string;
model: string;
reasoningEffort?: ReasoningEffort;
copilot?: PatternAgentCopilotConfig;
}
export interface PatternGraphPosition {
+2
View File
@@ -14,6 +14,7 @@ import type { SessionRunRecord } from '@shared/domain/runTimeline';
import type { PendingUserInputRecord } from '@shared/domain/userInput';
import type { PendingPlanReviewRecord } from '@shared/domain/planReview';
import type { PendingMcpAuthRecord } from '@shared/domain/mcpAuth';
import type { ChatMessageAttachment } from '@shared/domain/attachment';
import type { InteractionMode } from '@shared/contracts/sidecar';
export type ChatRole = 'system' | 'user' | 'assistant';
@@ -32,6 +33,7 @@ export interface ChatMessageRecord {
content: string;
createdAt: string;
pending?: boolean;
attachments?: ChatMessageAttachment[];
}
export interface SessionRecord {