Each row in the Run History list now opens a Run Details sheet showing the full, untruncated output/error (the old inline chevron-expand capped output at 20 lines) plus duration, trigger, tokens, and cost. Output/error use an explicit Copy button rather than .textSelection(.enabled), to avoid the same Escape-beeps-instead-of- dismissing bug just fixed in ModelInfoView. While wiring this up, found the JarvisAgentRun model didn't match the real oAI-Web API response shape: output decoded from a nonexistent "output" key instead of "result" (always nil, hence "No output for this run" even on successful runs with real content), finishedAt decoded from "finished_at" instead of "ended_at" (Duration silently never showed), and the status icon only recognized "completed"/ "failed" instead of the API's actual "success"/"error" values (plain gray circle instead of a green checkmark). Fixed all three, verified against a real API response, added 4 decoding tests.
68 lines
2.7 KiB
Swift
68 lines
2.7 KiB
Swift
//
|
|
// JarvisModelsTests.swift
|
|
// oAITests
|
|
//
|
|
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
|
// Copyright (C) 2026 Rune Olsen
|
|
|
|
import Testing
|
|
import Foundation
|
|
@testable import Confab
|
|
|
|
@Suite("JarvisAgentRun decoding")
|
|
struct JarvisModelsTests {
|
|
|
|
// Real shape returned by the oAI-Web /api/agents/{id}/runs endpoint — confirmed by Rune
|
|
// against a live run. Guards against the "result"/"output" and "ended_at"/"finished_at"
|
|
// field-name mismatch that shipped in the initial Run Details modal (output always showed
|
|
// "No output for this run" even when the API had real content).
|
|
private static let sampleJSON = """
|
|
{
|
|
"id": "8628fa26-8ff1-4053-b106-8ba84a0e10e0",
|
|
"agent_id": "531c884b-a401-4985-8717-bfa6bcc1d148",
|
|
"started_at": "2026-08-07T10:00:00.135999+00:00",
|
|
"ended_at": "2026-08-07T10:00:13.815956+00:00",
|
|
"status": "success",
|
|
"input_tokens": 25615,
|
|
"output_tokens": 1233,
|
|
"cost_usd": 0.031780000776052475,
|
|
"result": "Infrastructure Status: HEALTHY",
|
|
"error": null,
|
|
"model": "anthropic:claude-haiku-4-5-20251001"
|
|
}
|
|
"""
|
|
|
|
@Test("Decodes the API's 'result' field into .output")
|
|
func decodesResultIntoOutput() throws {
|
|
let run = try JSONDecoder().decode(JarvisAgentRun.self, from: Data(Self.sampleJSON.utf8))
|
|
#expect(run.output == "Infrastructure Status: HEALTHY")
|
|
}
|
|
|
|
@Test("Decodes the API's 'ended_at' field into .finishedAt")
|
|
func decodesEndedAtIntoFinishedAt() throws {
|
|
let run = try JSONDecoder().decode(JarvisAgentRun.self, from: Data(Self.sampleJSON.utf8))
|
|
#expect(run.finishedAt == "2026-08-07T10:00:13.815956+00:00")
|
|
}
|
|
|
|
@Test("Decodes a full real run without losing any field")
|
|
func decodesAllFields() throws {
|
|
let run = try JSONDecoder().decode(JarvisAgentRun.self, from: Data(Self.sampleJSON.utf8))
|
|
#expect(run.id == "8628fa26-8ff1-4053-b106-8ba84a0e10e0")
|
|
#expect(run.agentId == "531c884b-a401-4985-8717-bfa6bcc1d148")
|
|
#expect(run.status == "success")
|
|
#expect(run.startedAt == "2026-08-07T10:00:00.135999+00:00")
|
|
#expect(run.inputTokens == 25615)
|
|
#expect(run.outputTokens == 1233)
|
|
#expect(run.totalTokens == 26848)
|
|
#expect(run.costUsd == 0.031780000776052475)
|
|
#expect(run.error == nil)
|
|
}
|
|
|
|
@Test("A finished run with both started_at and ended_at produces a non-nil duration")
|
|
func computesDurationFromRealFieldNames() throws {
|
|
let run = try JSONDecoder().decode(JarvisAgentRun.self, from: Data(Self.sampleJSON.utf8))
|
|
#expect(run.formattedDuration != nil)
|
|
#expect(run.formattedDuration == "13s")
|
|
}
|
|
}
|