(input: {
runId?: string | null
checkpointId?: string | null
toolCallId: string
toolName: string
args?: Record<string, unknown>
status?: CopilotAsyncToolStatus
})
| 229 | } |
| 230 | |
| 231 | export async function upsertAsyncToolCall(input: { |
| 232 | runId?: string | null |
| 233 | checkpointId?: string | null |
| 234 | toolCallId: string |
| 235 | toolName: string |
| 236 | args?: Record<string, unknown> |
| 237 | status?: CopilotAsyncToolStatus |
| 238 | }) { |
| 239 | return withDbSpan( |
| 240 | TraceSpan.CopilotAsyncRunsUpsertAsyncToolCall, |
| 241 | 'UPSERT', |
| 242 | 'copilot_async_tool_calls', |
| 243 | { |
| 244 | [TraceAttr.ToolCallId]: input.toolCallId, |
| 245 | [TraceAttr.ToolName]: input.toolName, |
| 246 | [TraceAttr.CopilotAsyncToolStatus]: input.status ?? 'pending', |
| 247 | [TraceAttr.RunId]: input.runId ?? undefined, |
| 248 | }, |
| 249 | async () => { |
| 250 | const existing = await getAsyncToolCall(input.toolCallId) |
| 251 | const incomingStatus = input.status ?? 'pending' |
| 252 | if ( |
| 253 | existing && |
| 254 | (isTerminalAsyncStatus(existing.status) || isDeliveredAsyncStatus(existing.status)) && |
| 255 | !isTerminalAsyncStatus(incomingStatus) && |
| 256 | !isDeliveredAsyncStatus(incomingStatus) |
| 257 | ) { |
| 258 | logger.info('Ignoring async tool upsert that would downgrade terminal state', { |
| 259 | toolCallId: input.toolCallId, |
| 260 | existingStatus: existing.status, |
| 261 | incomingStatus, |
| 262 | }) |
| 263 | return existing |
| 264 | } |
| 265 | const effectiveRunId = input.runId ?? existing?.runId ?? null |
| 266 | if (!effectiveRunId) { |
| 267 | logger.warn('upsertAsyncToolCall missing runId and no existing row', { |
| 268 | toolCallId: input.toolCallId, |
| 269 | toolName: input.toolName, |
| 270 | status: input.status ?? 'pending', |
| 271 | }) |
| 272 | return null |
| 273 | } |
| 274 | |
| 275 | const now = new Date() |
| 276 | const [row] = await db |
| 277 | .insert(copilotAsyncToolCalls) |
| 278 | .values({ |
| 279 | runId: effectiveRunId, |
| 280 | checkpointId: input.checkpointId ?? null, |
| 281 | toolCallId: input.toolCallId, |
| 282 | toolName: input.toolName, |
| 283 | args: input.args ?? {}, |
| 284 | status: incomingStatus, |
| 285 | updatedAt: now, |
| 286 | }) |
| 287 | .onConflictDoUpdate({ |
| 288 | target: copilotAsyncToolCalls.toolCallId, |
no test coverage detected