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