Files
hapi/ios/Packages/HapiKit/Sources/HapiProtocol/Models/SessionSummary.swift
T

167 lines
5.5 KiB
Swift

import Foundation
/// Classification of a pending request for list badges.
public enum PendingRequestKind: String, Codable, Sendable {
case permission
case input
}
/// A capped, list-friendly view of one pending tool request.
///
/// Mirrors `PendingRequest` (`shared/src/sessionSummary.ts`).
public struct PendingRequest: Codable, Equatable, Sendable {
public var id: String
public var kind: PendingRequestKind
public var tool: String
/// Epoch ms when the request was raised (falls back server-side to the
/// session's `updatedAt` for requests stored without `createdAt`).
public var since: Int
public init(id: String, kind: PendingRequestKind, tool: String, since: Int) {
self.id = id
self.kind = kind
self.tool = tool
self.since = since
}
}
/// Todo completion counters shown on the session row.
public struct TodoProgress: Codable, Equatable, Sendable {
public var completed: Int
public var total: Int
public init(completed: Int, total: Int) {
self.completed = completed
self.total = total
}
}
/// Metadata subset embedded in a session-list row.
///
/// Mirrors `SessionSummaryMetadata` (`shared/src/sessionSummary.ts`).
public struct SessionSummaryMetadata: Codable, Equatable, Sendable {
/// The `summary` field carries only the text in list rows.
public struct Summary: Codable, Equatable, Sendable {
public var text: String
public init(text: String) {
self.text = text
}
}
public var name: String?
public var path: String
public var machineId: String?
public var summary: Summary?
public var flavor: String?
public var worktree: WorktreeMetadata?
/// Native agent session id resolved per flavor by the hub.
public var agentSessionId: String?
public var lifecycleState: String?
public var hapiMcpUrl: String?
public init(
name: String? = nil,
path: String,
machineId: String? = nil,
summary: Summary? = nil,
flavor: String? = nil,
worktree: WorktreeMetadata? = nil,
agentSessionId: String? = nil,
lifecycleState: String? = nil,
hapiMcpUrl: String? = nil
) {
self.name = name
self.path = path
self.machineId = machineId
self.summary = summary
self.flavor = flavor
self.worktree = worktree
self.agentSessionId = agentSessionId
self.lifecycleState = lifecycleState
self.hapiMcpUrl = hapiMcpUrl
}
}
/// One row of `GET /api/sessions`.
///
/// Mirrors `SessionSummary` (`shared/src/sessionSummary.ts`). The summary is
/// hub-derived: badges must use `pendingRequestsCount` (authoritative total),
/// never `pendingRequests.count` (capped at 5, oldest first).
public struct SessionSummary: Codable, Equatable, Sendable {
/// Server-side cap on `pendingRequests` entries
/// (`PENDING_REQUEST_SUMMARY_CAP`, `shared/src/sessionSummary.ts`).
public static let pendingRequestSummaryCap = 5
public var id: String
public var active: Bool
public var thinking: Bool
public var activeAt: Int
public var updatedAt: Int
public var pinned: Bool?
public var globalPinned: Bool?
public var metadata: SessionSummaryMetadata?
/// Watermark mirrors of the detail record so structured SSE patches can
/// be gated without a detail fetch.
public var metadataVersion: Int
public var agentStateVersion: Int
public var todosUpdatedAt: Int
public var todoProgress: TodoProgress?
public var pendingRequestsCount: Int
public var pendingRequestKinds: [PendingRequestKind]
public var pendingRequests: [PendingRequest]
public var backgroundTaskCount: Int
public var futureScheduledMessageCount: Int
/// Epoch ms of the soonest uninvoked scheduled message, or `nil`.
public var nextScheduledAt: Int?
public var model: String?
public var modelReasoningEffort: String?
public var effort: String?
public init(
id: String,
active: Bool,
thinking: Bool,
activeAt: Int,
updatedAt: Int,
pinned: Bool? = nil,
globalPinned: Bool? = nil,
metadata: SessionSummaryMetadata? = nil,
metadataVersion: Int,
agentStateVersion: Int,
todosUpdatedAt: Int,
todoProgress: TodoProgress? = nil,
pendingRequestsCount: Int,
pendingRequestKinds: [PendingRequestKind] = [],
pendingRequests: [PendingRequest] = [],
backgroundTaskCount: Int = 0,
futureScheduledMessageCount: Int = 0,
nextScheduledAt: Int? = nil,
model: String? = nil,
modelReasoningEffort: String? = nil,
effort: String? = nil
) {
self.id = id
self.active = active
self.thinking = thinking
self.activeAt = activeAt
self.updatedAt = updatedAt
self.pinned = pinned
self.globalPinned = globalPinned
self.metadata = metadata
self.metadataVersion = metadataVersion
self.agentStateVersion = agentStateVersion
self.todosUpdatedAt = todosUpdatedAt
self.todoProgress = todoProgress
self.pendingRequestsCount = pendingRequestsCount
self.pendingRequestKinds = pendingRequestKinds
self.pendingRequests = pendingRequests
self.backgroundTaskCount = backgroundTaskCount
self.futureScheduledMessageCount = futureScheduledMessageCount
self.nextScheduledAt = nextScheduledAt
self.model = model
self.modelReasoningEffort = modelReasoningEffort
self.effort = effort
}
}