Files
tori/web/src/ws.ts
Fam Zheng 7edbbee471 Tori: AI agent workflow manager - initial implementation
Rust (Axum) + Vue 3 + SQLite. Features:
- Project CRUD REST API with proper error handling
- Per-project agent loop (mpsc + broadcast channels)
- LLM-driven plan generation and replan on user feedback
- SSH command execution with status streaming
- WebSocket real-time updates to frontend
- Four-zone UI: requirement, plan (left), execution (right), comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:36:50 +00:00

70 lines
1.5 KiB
TypeScript

export interface WsPlanUpdate {
type: 'PlanUpdate'
workflow_id: string
steps: { order: number; description: string; command: string }[]
}
export interface WsStepStatusUpdate {
type: 'StepStatusUpdate'
step_id: string
status: string
output: string
}
export interface WsWorkflowStatusUpdate {
type: 'WorkflowStatusUpdate'
workflow_id: string
status: string
}
export interface WsError {
type: 'Error'
message: string
}
export type WsMessage = WsPlanUpdate | WsStepStatusUpdate | WsWorkflowStatusUpdate | WsError
export type WsHandler = (msg: WsMessage) => void
export function connectWs(projectId: string, onMessage: WsHandler): { close: () => void } {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
const url = `${proto}//${location.host}/ws/${projectId}`
let ws: WebSocket | null = null
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
let closed = false
function connect() {
if (closed) return
ws = new WebSocket(url)
ws.onmessage = (e) => {
try {
const msg: WsMessage = JSON.parse(e.data)
onMessage(msg)
} catch {
// ignore malformed messages
}
}
ws.onclose = () => {
if (!closed) {
reconnectTimer = setTimeout(connect, 2000)
}
}
ws.onerror = () => {
ws?.close()
}
}
connect()
return {
close() {
closed = true
if (reconnectTimer) clearTimeout(reconnectTimer)
ws?.close()
},
}
}