( agent: AbstractAgent, calls: ReadonlyArray<CapturedToolCall>, )
| 118 | * so the next `runAgent` sees a valid transcript even on backends that don't. |
| 119 | */ |
| 120 | export function ensureAssistantToolCallMessage( |
| 121 | agent: AbstractAgent, |
| 122 | calls: ReadonlyArray<CapturedToolCall>, |
| 123 | ): void { |
| 124 | const messages = agent.messages; |
| 125 | const last = messages[messages.length - 1]; |
| 126 | const lastIsAssistantWithCalls = |
| 127 | last !== undefined && |
| 128 | last.role === "assistant" && |
| 129 | Array.isArray(last.toolCalls); |
| 130 | |
| 131 | if (lastIsAssistantWithCalls) { |
| 132 | const existing = (last.toolCalls ?? []).map((tc) => tc.id); |
| 133 | const allPresent = calls.every((c) => existing.includes(c.toolCallId)); |
| 134 | if (allPresent) return; |
| 135 | } |
| 136 | |
| 137 | const assistant: Message = { |
| 138 | id: `${calls[0]!.toolCallId}-assistant`, |
| 139 | role: "assistant", |
| 140 | content: "", |
| 141 | toolCalls: calls.map((c) => ({ |
| 142 | id: c.toolCallId, |
| 143 | type: "function" as const, |
| 144 | function: { |
| 145 | name: c.toolCallName, |
| 146 | arguments: JSON.stringify(c.toolCallArgs), |
| 147 | }, |
| 148 | })), |
| 149 | }; |
| 150 | agent.addMessage(assistant); |
| 151 | } |
| 152 | |
| 153 | export function pushToolResult( |
| 154 | agent: AbstractAgent, |
no test coverage detected
searching dependent graphs…