Phase 003: remove the coding-agent and ekko-agent runtimes
Every chat session now runs through the Hermes bridge, so the three chat chains become feature-equivalent instead of three partially-maintained dispatch paths. Keeping the coding-agent and in-house agent runtimes alive meant every bridge change had to be mirrored into two more runtimes that had already drifted. Historical rows are read, not migrated: sessions stored with the retired source normalize to cli on load, workflow graphs naming the retired agents keep loading and run on the bridge, and the visible-source check plus SOURCE_LABELS still recognize the old value so those sessions stay listed. The public surface follows the code: the OpenAPI generator and the MCP chat-run tool schema drop the six retired entry fields so external callers are not told about runtimes that no longer exist. harness-check gains a RETIRED_RUNTIME scan so the residual check is a mechanical gate instead of a manual grep, with the two surviving read-side compat sites recorded with reasons. Refs: docs/phases/phase_003.md
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -175,18 +175,11 @@ function mapHistoryMessages(messages: HermesMessage[]): Session['messages'] {
|
||||
})
|
||||
}
|
||||
|
||||
function codingAgentFields(summary: SessionSummary): Pick<Session, 'agent' | 'agentSessionId' | 'agentNativeSessionId' | 'codingAgentId' | 'codingAgentMode'> {
|
||||
const isCodingAgentSession = summary.source === 'coding_agent' || summary.agent === 'claude' || summary.agent === 'codex'
|
||||
function agentFields(summary: SessionSummary): Pick<Session, 'agent' | 'agentSessionId' | 'agentNativeSessionId'> {
|
||||
return {
|
||||
agent: summary.agent || undefined,
|
||||
agentSessionId: summary.agent_session_id || undefined,
|
||||
agentNativeSessionId: summary.agent_native_session_id || undefined,
|
||||
codingAgentId: summary.agent === 'codex' ? 'codex' : summary.agent === 'claude' ? 'claude-code' : undefined,
|
||||
codingAgentMode: isCodingAgentSession
|
||||
? (summary.agent_mode === 'global' || summary.agent_mode === 'scoped'
|
||||
? summary.agent_mode
|
||||
: summary.provider === 'global' ? 'global' : 'scoped')
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +189,7 @@ function sessionFromSummary(summary: SessionSummary, messages: Session['messages
|
||||
profile: summary.profile || undefined,
|
||||
title: summary.title || '',
|
||||
source: summary.source,
|
||||
...codingAgentFields(summary),
|
||||
...agentFields(summary),
|
||||
createdAt: summary.started_at * 1000,
|
||||
updatedAt: (summary.last_active || summary.ended_at || summary.started_at) * 1000,
|
||||
model: summary.model,
|
||||
@@ -405,7 +398,7 @@ function sessionSummaryToSession(summary: SessionSummary): Session {
|
||||
profile: summary.profile || undefined,
|
||||
title: summary.title || '',
|
||||
source: summary.source,
|
||||
...codingAgentFields(summary),
|
||||
...agentFields(summary),
|
||||
createdAt: summary.started_at * 1000,
|
||||
updatedAt: (summary.last_active || summary.started_at) * 1000,
|
||||
model: summary.model,
|
||||
|
||||
@@ -49,7 +49,6 @@ import {
|
||||
} from '@/api/hermes/workflow-socket'
|
||||
import { fetchSkills } from '@/api/hermes/skills'
|
||||
import { fetchSession } from '@/api/hermes/sessions'
|
||||
import { inferCodingAgentApiMode, normalizeCodingAgentApiMode } from '@/api/coding-agents'
|
||||
import { buildWorkflowSkillOptions, workflowAgentToSkillTarget } from '@/utils/hermes/workflow-skills'
|
||||
import type {
|
||||
WorkflowAgentNodeData,
|
||||
@@ -171,8 +170,6 @@ let workflowRunsLoadingSeq = 0
|
||||
|
||||
const agentOptions = computed<WorkflowSelectOption[]>(() => [
|
||||
{ label: 'Hermes', value: 'hermes' },
|
||||
{ label: 'Claude Code', value: 'claude-code' },
|
||||
{ label: 'Codex', value: 'codex' },
|
||||
])
|
||||
|
||||
const modelGroups = computed<AvailableModelGroup[]>(() => appStore.modelGroups)
|
||||
@@ -358,7 +355,6 @@ function makeNode(
|
||||
agent: data.agent || agentOptions.value[0]?.value || 'hermes',
|
||||
provider: data.provider || defaultModelSelection.value.provider,
|
||||
model: data.model || defaultModelSelection.value.model,
|
||||
apiMode: data.apiMode || defaultApiMode(data.provider || defaultModelSelection.value.provider),
|
||||
input: data.input || '',
|
||||
skills: data.skills || [],
|
||||
images: data.images || [],
|
||||
@@ -516,23 +512,14 @@ function closeWorkflowChatPanel() {
|
||||
workflowChatPanelTitle.value = ''
|
||||
}
|
||||
|
||||
function defaultApiMode(provider: string) {
|
||||
const group = modelGroups.value.find(item => item.provider === provider)
|
||||
return normalizeCodingAgentApiMode(
|
||||
group?.api_mode,
|
||||
inferCodingAgentApiMode(group?.provider || provider, group?.base_url),
|
||||
)
|
||||
}
|
||||
|
||||
function normalizeNodeModel(data: WorkflowAgentNodeData): Pick<WorkflowAgentNodeData, 'provider' | 'model' | 'apiMode'> {
|
||||
function normalizeNodeModel(data: WorkflowAgentNodeData): Pick<WorkflowAgentNodeData, 'provider' | 'model'> {
|
||||
const currentGroup = modelGroups.value.find(group => group.provider === data.provider)
|
||||
if (currentGroup?.models.includes(data.model)) {
|
||||
return { provider: data.provider, model: data.model, apiMode: data.apiMode || defaultApiMode(data.provider) }
|
||||
return { provider: data.provider, model: data.model }
|
||||
}
|
||||
return {
|
||||
provider: defaultModelSelection.value.provider,
|
||||
model: defaultModelSelection.value.model,
|
||||
apiMode: defaultApiMode(defaultModelSelection.value.provider),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +565,6 @@ function serializeWorkflowNodes(source: WorkflowNode[]): unknown[] {
|
||||
agent: node.data.agent,
|
||||
provider: node.data.provider,
|
||||
model: node.data.model,
|
||||
apiMode: node.data.apiMode,
|
||||
input: node.data.input,
|
||||
skills: [...node.data.skills],
|
||||
images: [...node.data.images],
|
||||
@@ -624,7 +610,6 @@ function normalizeStoredNode(raw: unknown, index: number): WorkflowNode {
|
||||
agent: data.agent,
|
||||
provider: data.provider,
|
||||
model: data.model,
|
||||
apiMode: data.apiMode,
|
||||
input: data.input,
|
||||
skills: Array.isArray(data.skills) ? data.skills.filter(item => typeof item === 'string') : [],
|
||||
images: Array.isArray(data.images) ? data.images.filter(item => typeof item === 'string') : [],
|
||||
@@ -1338,9 +1323,6 @@ function workflowValidationError(): string | null {
|
||||
if (!node.data.title.trim()) return t('workflow.validation.nodeNameRequired', { node: node.id })
|
||||
if (!node.data.provider.trim()) return t('workflow.validation.providerRequired', { node: label })
|
||||
if (!node.data.model.trim()) return t('workflow.validation.modelRequired', { node: label })
|
||||
if (node.data.agent !== 'hermes' && !node.data.apiMode) {
|
||||
return t('workflow.validation.apiModeRequired', { node: label })
|
||||
}
|
||||
if (!node.data.input.trim()) return t('workflow.validation.inputRequired', { node: label })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user