feat(provider-adapter): implement multi-provider abstraction layer (Phase 1)

Add provider types, registry, capabilities, and message adapter registry.
Rename sdk-messages→claude-messages, agent-runner→claude-runner,
ClaudeSession→AgentSession. Update Rust AgentQueryOptions with provider
and provider_config fields. Capability-driven AgentPane rendering.
This commit is contained in:
Hibryda 2026-03-11 02:08:45 +01:00
parent d8d7ad16f3
commit 1efcb13869
27 changed files with 276 additions and 49 deletions

View file

@ -16,7 +16,8 @@
setAgentSdkSessionId,
getAgentSession,
} from '../../stores/agents.svelte';
import type { AgentMessage } from '../../adapters/sdk-messages';
import type { AgentMessage } from '../../adapters/claude-messages';
import { getProvider, getDefaultProviderId } from '../../providers/registry.svelte';
import AgentPane from '../Agent/AgentPane.svelte';
interface Props {
@ -26,6 +27,9 @@
let { project, onsessionid }: Props = $props();
let providerId = $derived(project.provider ?? getDefaultProviderId());
let providerMeta = $derived(getProvider(providerId));
let sessionId = $state(crypto.randomUUID());
let lastState = $state<ProjectAgentState | null>(null);
let loading = $state(true);
@ -35,7 +39,7 @@
sessionId = crypto.randomUUID();
hasRestoredHistory = false;
lastState = null;
registerSessionProject(sessionId, project.id);
registerSessionProject(sessionId, project.id, providerId);
trackProject(project.id, sessionId);
onsessionid?.(sessionId);
}
@ -70,7 +74,7 @@
} finally {
loading = false;
// Register session -> project mapping for persistence + health tracking
registerSessionProject(sessionId, project.id);
registerSessionProject(sessionId, project.id, providerId);
trackProject(project.id, sessionId);
onsessionid?.(sessionId);
}
@ -112,7 +116,7 @@
}
</script>
<div class="claude-session">
<div class="agent-session">
{#if loading}
<div class="loading-state">Loading session...</div>
{:else}
@ -120,13 +124,15 @@
{sessionId}
cwd={project.cwd}
profile={project.profile || undefined}
provider={providerId}
capabilities={providerMeta?.capabilities}
onExit={handleNewSession}
/>
{/if}
</div>
<style>
.claude-session {
.agent-session {
height: 100%;
overflow: hidden;
display: flex;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { getAgentSession, getTotalCost, type AgentSession } from '../../stores/agents.svelte';
import type { AgentMessage, ToolCallContent, CostContent, CompactionContent } from '../../adapters/sdk-messages';
import type { AgentMessage, ToolCallContent, CostContent, CompactionContent } from '../../adapters/claude-messages';
import { extractFilePaths } from '../../utils/tool-files';
interface Props {

View file

@ -3,7 +3,7 @@
import type { ProjectConfig } from '../../types/groups';
import { PROJECT_ACCENTS } from '../../types/groups';
import ProjectHeader from './ProjectHeader.svelte';
import ClaudeSession from './ClaudeSession.svelte';
import AgentSession from './AgentSession.svelte';
import TerminalTabs from './TerminalTabs.svelte';
import TeamAgentsPanel from './TeamAgentsPanel.svelte';
import ProjectFiles from './ProjectFiles.svelte';
@ -148,7 +148,7 @@
<div class="project-content-area">
<!-- PERSISTED-EAGER: always mounted, toggled via display -->
<div class="content-pane" style:display={activeTab === 'model' ? 'flex' : 'none'}>
<ClaudeSession {project} onsessionid={(id) => mainSessionId = id} />
<AgentSession {project} onsessionid={(id) => mainSessionId = id} />
{#if mainSessionId}
<TeamAgentsPanel {mainSessionId} />
{/if}