Files
james.maes 1aeec87682 feat(04-05): DevOverlay package + DevSnapshot/ToolCallRow in AgentOrchestrator (OBS-01)
- NSPanel-backed DevOverlayWindow (.floating + .nonactivating) hidden by default
- SwiftUI DevOverlayView renders OBS-01 surface: state/turn, provider/model,
  token counts, cache creation/read + hit %, latency, last-5 tool calls
- @Observable @MainActor DevOverlayViewModel — single write path via apply()
- DevOverlayBridge pumps BoundedAsyncChannel<DevSnapshot> → ViewModel
- DevSnapshot + ToolCallRow live in AgentOrchestrator target (Rule 3
  deviation from plan's files_modified: DevSnapshotEmitter consumes both
  OrchestratorEvent and DevSnapshot, so parking both in AgentOrchestrator
  avoids the circular AgentOrchestrator→DevOverlay→AgentOrchestrator dep)
- Additive OrchestratorEvent.usage(turnId:usage:) — surfaces TurnUsage to
  DevOverlay without reading replay; no nonce (SEC-06 preserved)
- AgentOrchestrator now emits .usage on LLMEvent.usage alongside replay write
- 14 DevOverlay tests pass; 114 AgentCore tests pass (no regression)
2026-04-24 18:32:56 -05:00

41 lines
1.1 KiB
Swift

import Foundation
/// One row in the DevOverlay's "last 5 tool calls" table (OBS-01).
///
/// `id` == the `toolUseId` from the provider; the emitter dedupes on this
/// so repeated `.toolCardUpdate` events for the same tool_use update the
/// existing row rather than pushing a new one. `preview` is capped at 200
/// characters upstream (`ToolCardUpdate.resultPreview`, Plan 04-04).
public struct ToolCallRow: Sendable, Equatable, Identifiable {
public enum Status: Sendable, Equatable {
case pending
case running
case completed
case failed
case awaitingApproval
}
public let id: String
public let name: String
public let status: Status
public let durationMs: Int
public let preview: String?
public let error: String?
public init(
id: String,
name: String,
status: Status,
durationMs: Int,
preview: String?,
error: String? = nil
) {
self.id = id
self.name = name
self.status = status
self.durationMs = durationMs
self.preview = preview
self.error = error
}
}