forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChatFirstBlockToolExecutor.swift
More file actions
114 lines (111 loc) · 4.52 KB
/
Copy pathChatFirstBlockToolExecutor.swift
File metadata and controls
114 lines (111 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import Foundation
/// Capability-scoped block validation and journal append. It is intentionally
/// separate from the legacy desktop tool switch so server admission is visible
/// as a distinct, all-or-nothing boundary.
@MainActor
enum ChatFirstBlockToolExecutor {
nonisolated static func citationSelection(
from block: [String: Any]
) -> (kind: ChatCitationReference.Kind, sourceID: String)? {
switch block["type"] as? String {
case "taskCard":
return (kind: .task, sourceID: block["task_id"] as? String ?? "")
case "goalLink":
return (kind: .goal, sourceID: block["goal_id"] as? String ?? "")
case "captureLink", "conversationLink":
return (kind: .conversation, sourceID: block["conversation_id"] as? String ?? "")
case "memoryLink":
return (kind: .memory, sourceID: block["memory_id"] as? String ?? "")
default:
return nil
}
}
static func execute(
_ args: [String: Any],
surface: AgentSurfaceReference?,
sessionID: String?,
runID: String?,
attemptID: String?,
capabilityRef: String?,
controlGeneration: Int?,
expectedOwnerID: String?,
authorizationSnapshot: RuntimeOwnerAuthorizationSnapshot?,
api: APIClient
) async -> String {
guard let expectedOwnerID,
let authorizationSnapshot,
let surface,
surface.surfaceKind == "main_chat",
let sessionID,
let runID,
let attemptID,
let capabilityRef,
let controlGeneration,
controlGeneration >= 0,
let backendBlocks = ChatFirstBlockWire.backendBlocks(from: args)
else {
return #"{"ok":false,"error":{"code":"chat_first_invalid_authority"}}"#
}
guard ChatToolExecutor.isExpectedOwnerCurrent(expectedOwnerID, authorizationSnapshot: authorizationSnapshot) else {
return ChatToolExecutor.authorizedOwnerChangedResult()
}
do {
let request = ChatFirstBlockValidationRequest(
controlGeneration: controlGeneration,
ownerFence: expectedOwnerID,
runID: runID,
attemptID: attemptID,
blocks: backendBlocks.map(OmiAnyCodable.init)
)
let receipt: ChatFirstBlockValidationReceipt = try await api.post(
"v1/chat-first/blocks/validate",
body: request,
expectedOwnerId: expectedOwnerID,
authorizationSnapshot: authorizationSnapshot
)
guard ChatToolExecutor.isExpectedOwnerCurrent(expectedOwnerID, authorizationSnapshot: authorizationSnapshot)
else {
return ChatToolExecutor.authorizedOwnerChangedResult()
}
guard let journalBlocks = ChatFirstBlockWire.journalBlocks(from: receipt) else {
log(
"ChatFirstBlockToolExecutor: backend rejected \(backendBlocks.count) block(s) "
+ "[\(backendBlocks.compactMap { $0["type"] as? String }.joined(separator: ","))]")
return #"{"ok":false,"error":{"code":"chat_first_blocks_rejected"}}"#
}
log(
"ChatFirstBlockToolExecutor: appending \(journalBlocks.count) block(s) "
+ "[\(journalBlocks.compactMap { $0["type"] as? String }.joined(separator: ","))]")
let journalBlocksData = try JSONSerialization.data(withJSONObject: journalBlocks)
guard let journalBlocksJSON = String(data: journalBlocksData, encoding: .utf8) else {
return #"{"ok":false,"error":{"code":"chat_first_blocks_unavailable"}}"#
}
_ = try await AgentRuntimeProcess.shared.appendChatFirstBlocks(
clientId: "chat-first-render",
surface: surface,
ownerID: expectedOwnerID,
sessionID: sessionID,
runID: runID,
attemptID: attemptID,
capabilityRef: capabilityRef,
controlGeneration: controlGeneration,
blocksJSON: journalBlocksJSON,
authorizationSnapshot: authorizationSnapshot
)
await ChatCitationProvenanceRegistry.shared.markSelected(
backendBlocks.compactMap { citationSelection(from: $0) }.filter { !$0.sourceID.isEmpty },
runID: runID,
attemptID: attemptID)
// `#(...)` is not interpolation in a raw string — the count was being
// reported to the model as the literal text `#(journalBlocks.count)`.
return #"{"ok":true,"rendered":\#(journalBlocks.count)}"#
} catch {
guard ChatToolExecutor.isExpectedOwnerCurrent(expectedOwnerID, authorizationSnapshot: authorizationSnapshot)
else {
return ChatToolExecutor.authorizedOwnerChangedResult()
}
logError("Chat-first block rendering failed", error: error)
return #"{"ok":false,"error":{"code":"chat_first_blocks_unavailable"}}"#
}
}
}