( context: QuickJSContext, toolInvoker: SandboxToolInvoker, pendingDeferreds: Set<QuickJSDeferredPromise>, runPromise: RunPromise, deadline: DeadlineTracker, )
| 303 | type RunPromise = <A, E>(effect: Effect.Effect<A, E>) => Promise<A>; |
| 304 | |
| 305 | const createToolBridge = ( |
| 306 | context: QuickJSContext, |
| 307 | toolInvoker: SandboxToolInvoker, |
| 308 | pendingDeferreds: Set<QuickJSDeferredPromise>, |
| 309 | runPromise: RunPromise, |
| 310 | deadline: DeadlineTracker, |
| 311 | ): QuickJSHandle => |
| 312 | context.newFunction("__executor_invokeTool", (pathHandle, argsHandle) => { |
| 313 | const path = context.getString(pathHandle); |
| 314 | const args = |
| 315 | argsHandle === undefined || context.typeof(argsHandle) === "undefined" |
| 316 | ? undefined |
| 317 | : context.dump(argsHandle); |
| 318 | const deferred = context.newPromise(); |
| 319 | pendingDeferreds.add(deferred); |
| 320 | deferred.settled.finally(() => { |
| 321 | pendingDeferreds.delete(deferred); |
| 322 | }); |
| 323 | |
| 324 | deadline.dispatchStarted(); |
| 325 | void runPromise(toolInvoker.invoke({ path, args })).then( |
| 326 | (value) => { |
| 327 | deadline.dispatchReturned(); |
| 328 | if (!deferred.alive) { |
| 329 | return; |
| 330 | } |
| 331 | |
| 332 | const serialized = serializeJson(value, `Tool result for ${path}`); |
| 333 | if (typeof serialized === "undefined") { |
| 334 | deferred.resolve(); |
| 335 | return; |
| 336 | } |
| 337 | |
| 338 | const valueHandle = context.newString(serialized); |
| 339 | deferred.resolve(valueHandle); |
| 340 | valueHandle.dispose(); |
| 341 | }, |
| 342 | (cause) => { |
| 343 | deadline.dispatchReturned(); |
| 344 | if (!deferred.alive) { |
| 345 | return; |
| 346 | } |
| 347 | |
| 348 | // The reject path is reserved for true infra defects. The |
| 349 | // upstream tool-invoker has already replaced the message with |
| 350 | // an opaque generic plus a correlation id, but defensively log |
| 351 | // the cause here and emit a stable generic if upstream changes. |
| 352 | const message = sandboxDefectMessage(cause); |
| 353 | try { |
| 354 | console.error("[executor:quickjs] tool dispatch defect", { path, cause }); |
| 355 | } catch { |
| 356 | /* ignore logger failures */ |
| 357 | } |
| 358 | const errorHandle = context.newError(message); |
| 359 | deferred.reject(errorHandle); |
| 360 | errorHandle.dispose(); |
| 361 | }, |
| 362 | ); |
no test coverage detected