feat(web): define ChatEvent discriminated union, eliminate all any sites (R9)
Created web/src/lib/types.ts with discriminated unions for SSE event payloads: ChatEvent (7 variants: session, tool_use, tool_result, text_delta, text, done, error), ToolCallResult, MessageContent, and typed data shapes for live events (PlanProposedData, PlanStepEventData, QuestionRaisedData, QuestionAnsweredData, EntityTouchedData, HealthChangedData) plus WailsGlobal for the desktop bridge. Replaced all ~15 `any` sites across 7 files: - api.ts: Message.content any -> MessageContent | string; removed local ChatEvent interface (now imported from types.ts as a discriminated union); JSON.parse cast to ChatEvent. - stores/chat.ts: removed local ToolCallResult interface (imported from types.ts, re-exported for backward compat); extractApprovals accesses args with typeof guards instead of implicit any access; toChatMessages handles string|object Message.content cleanly. - stores/activity.ts: update_plan_step seq/status extracted via typeof guards instead of `as any` casts; toolActivityLabel uses a str() helper for safe string extraction from unknown args. - stores/workspace.ts: applyPlanStepEvent takes PlanStepEventData; applyEvent casts data to Record<string, unknown>; switch cases cast to typed interfaces (PlanProposedData, QuestionRaisedData, etc.) instead of `as any`; applyHealthChanged uses HealthChangedData. - Config.svelte: (window as any).wails -> typed WailsGlobal cast; catch (e: any) -> catch (e: unknown) with instanceof Error check. - utils.ts: WithoutChild/WithoutChildren `any` -> `unknown`. - vite.config.ts: authProxy proxy/proxyReq `any` -> ProxyOptions type. Result: eslint no-explicit-any warnings dropped 12 -> 0. Tests (6/6) and build pass. VERSION 0.7.10 -> 0.7.11. Plan R9 marked done.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
import { writable, get } from 'svelte/store'
|
||||
import { streamChat, fetchSessions, fetchMessages, deleteSession as apiDeleteSession } from '$lib/api'
|
||||
import type { ChatEvent, Session, Message } from '$lib/api'
|
||||
import type { ToolCallResult } from '$lib/types'
|
||||
|
||||
export type { ToolCallResult }
|
||||
|
||||
export interface PendingApproval {
|
||||
executionId: string
|
||||
@@ -38,28 +41,21 @@ function extractApprovals(tools: ToolCallResult[]): PendingApproval[] {
|
||||
if (!text.includes('requires approval')) continue
|
||||
const m = text.match(APPROVAL_RE)
|
||||
if (m) {
|
||||
const args = t.args ?? {}
|
||||
const purpose = typeof args.purpose === 'string' ? args.purpose : undefined
|
||||
out.push({
|
||||
executionId: m[1],
|
||||
action: t.args?.purpose?.slice(0, 60) ?? t.args?.action ?? t.name ?? 'unknown',
|
||||
target: t.args?.target ?? 'unknown',
|
||||
action: purpose ? purpose.slice(0, 60) : typeof args.action === 'string' ? args.action : t.name,
|
||||
target: typeof args.target === 'string' ? args.target : 'unknown',
|
||||
destructive: /\bDESTRUCTIVE\b/.test(text),
|
||||
command: t.args?.command,
|
||||
purpose: t.args?.purpose
|
||||
command: typeof args.command === 'string' ? args.command : undefined,
|
||||
purpose
|
||||
})
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
export interface ToolCallResult {
|
||||
type: 'tool_use' | 'tool_result'
|
||||
name: string
|
||||
id?: string
|
||||
args?: any
|
||||
result?: any
|
||||
error?: string
|
||||
}
|
||||
|
||||
function mid(): string {
|
||||
return crypto.randomUUID()
|
||||
}
|
||||
@@ -119,11 +115,12 @@ function mergeToolCalls(raw: ToolCallResult[] | undefined): ToolCallResult[] {
|
||||
|
||||
function toChatMessages(msgs: Message[]): ChatMessage[] {
|
||||
return msgs.map((m) => {
|
||||
const tools = mergeToolCalls(m.content?.tool_calls)
|
||||
const content = typeof m.content === 'string' ? { text: m.content } : m.content
|
||||
const tools = mergeToolCalls(content?.tool_calls)
|
||||
return {
|
||||
id: m.id,
|
||||
role: m.role as 'user' | 'assistant',
|
||||
text: m.content?.text ?? (typeof m.content === 'string' ? m.content : ''),
|
||||
text: content?.text ?? '',
|
||||
tools,
|
||||
pendingApprovals: extractApprovals(tools)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user