11import Foundation
22
3+ struct IndexedToolCall {
4+ let index : Int
5+ let call : ToolCall
6+ }
7+
8+ struct IndexedToolResult {
9+ let index : Int
10+ let call : ToolCall
11+ let result : ToolResult
12+ }
13+
314extension Agent {
15+ func requiresApproval( _ call: ToolCall , allowlist: Set < String > ) -> Bool {
16+ configuration. approvalPolicy. requiresApproval ( toolName: call. name, allowlist: allowlist)
17+ }
18+
19+ func resolveApprovals(
20+ _ calls: [ IndexedToolCall ] ,
21+ handler: @escaping ToolApprovalHandler ,
22+ emit: StreamEmitter ? = nil ,
23+ allowlist: inout Set < String >
24+ ) async throws -> ( approved: [ IndexedToolCall ] , denied: [ IndexedToolResult ] ) {
25+ var approved : [ IndexedToolCall ] = [ ]
26+ var denied : [ IndexedToolResult ] = [ ]
27+
28+ for indexed in calls {
29+ guard let tool = firstTool ( named: indexed. call. name, in: tools) else {
30+ approved. append ( indexed)
31+ continue
32+ }
33+
34+ if allowlist. contains ( indexed. call. name) {
35+ approved. append ( indexed)
36+ continue
37+ }
38+
39+ let request = ToolApprovalRequest (
40+ toolCallId: indexed. call. id,
41+ toolName: indexed. call. name,
42+ arguments: indexed. call. arguments,
43+ toolDescription: tool. description
44+ )
45+ emit? . yield ( . toolApprovalRequested( request) )
46+ let decision = try await awaitApprovalDecision ( for: request, using: handler)
47+ emit? . yield ( . toolApprovalResolved( toolCallId: indexed. call. id, decision: decision) )
48+
49+ switch decision {
50+ case . approve:
51+ approved. append ( indexed)
52+ case . approveAlways:
53+ allowlist. insert ( indexed. call. name)
54+ approved. append ( indexed)
55+ case let . approveWithModifiedArguments( newArgs) :
56+ let modified = ToolCall (
57+ id: indexed. call. id,
58+ name: indexed. call. name,
59+ arguments: newArgs,
60+ kind: indexed. call. kind
61+ )
62+ approved. append ( IndexedToolCall ( index: indexed. index, call: modified) )
63+ case let . deny( reason) :
64+ let result = ToolResult . error ( reason ?? ToolFeedback . denied)
65+ denied. append ( IndexedToolResult ( index: indexed. index, call: indexed. call, result: result) )
66+ }
67+ }
68+
69+ return ( approved: approved, denied: denied)
70+ }
71+
472 func resolveTimeout( for call: ToolCall ) -> Duration {
573 guard let tool = firstTool ( named: call. name, in: tools) else {
674 return configuration. toolTimeout
@@ -27,7 +95,7 @@ extension Agent {
2795 } catch let error as AgentError {
2896 return ToolResult . error ( error. feedbackMessage)
2997 } catch {
30- return ToolResult . error ( " Tool failed: \ ( error) " )
98+ return ToolResult . error ( ToolFeedback . failed ( error) )
3199 }
32100 }
33101
@@ -41,7 +109,7 @@ extension Agent {
41109 let eventFactory = options. eventFactory
42110 continuation. yield ( eventFactory. make ( . subAgentStarted( toolCallId: call. id, toolName: call. name) ) )
43111
44- let parentDepth = ( context as? any CurrentDepthProviding ) ? . currentDepth ?? 0
112+ let parentDepth = currentDepth ( of : context )
45113 let eventHandler : @Sendable ( StreamEvent ) -> Void = { [ self ] event in
46114 let processed = applyHistoryEmissionLimitToSubAgentEvent ( event, parentDepth: parentDepth)
47115 continuation. yield ( eventFactory. make (
@@ -63,7 +131,7 @@ extension Agent {
63131 } catch let error as AgentError {
64132 result = ToolResult . error ( error. feedbackMessage)
65133 } catch {
66- result = ToolResult . error ( " Tool failed: \ ( error) " )
134+ result = ToolResult . error ( ToolFeedback . failed ( error) )
67135 }
68136 continuation. yield ( eventFactory. make (
69137 . subAgentCompleted( toolCallId: call. id, toolName: call. name, result: result)
@@ -95,7 +163,12 @@ extension Agent {
95163 } else {
96164 try await executeWithTimeout ( call, context: context, approvalHandler: options. approvalHandler)
97165 }
98- let truncated = truncatedToolResult ( result, toolName: call. name)
166+ let truncated = truncatedToolResult (
167+ result,
168+ toolName: call. name,
169+ tools: tools,
170+ fallbackLimit: configuration. maxToolResultCharacters
171+ )
99172 continuation. yield ( eventFactory. make (
100173 . toolCallCompleted( id: call. id, name: call. name, result: truncated)
101174 ) )
@@ -205,7 +278,12 @@ extension Agent {
205278
206279 var results = [ ( Int, ToolCall, ToolResult) ] ( )
207280 for try await (index, call, result) in group {
208- let truncated = truncatedToolResult ( result, toolName: call. name)
281+ let truncated = truncatedToolResult (
282+ result,
283+ toolName: call. name,
284+ tools: tools,
285+ fallbackLimit: configuration. maxToolResultCharacters
286+ )
209287 continuation. yield ( eventFactory. make (
210288 . toolCallCompleted( id: call. id, name: call. name, result: truncated)
211289 ) )
0 commit comments