gemi 0.124.0 → 0.125.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/AgentController.d.ts +185 -3
- package/dist/ai/AgentController.d.ts.map +1 -1
- package/dist/ai/client/index.d.ts +1 -1
- package/dist/ai/client/index.d.ts.map +1 -1
- package/dist/ai/client/index.js +38 -9
- package/dist/ai/client/index.js.map +1 -1
- package/dist/ai/client/reducer.d.ts.map +1 -1
- package/dist/ai/index.d.ts +2 -2
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +31 -48
- package/dist/ai/index.js.map +6 -15
- package/dist/ai/types.d.ts +26 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/useChat.d.ts +35 -2
- package/dist/ai/useChat.d.ts.map +1 -1
- package/dist/app/index.js +1 -1
- package/dist/auth/AuthController.d.ts.map +1 -1
- package/dist/auth/AuthManager.d.ts +11 -0
- package/dist/auth/AuthManager.d.ts.map +1 -1
- package/dist/auth/AuthServiceProvider.d.ts +2 -0
- package/dist/auth/AuthServiceProvider.d.ts.map +1 -1
- package/dist/auth/config.d.ts +71 -2
- package/dist/auth/config.d.ts.map +1 -1
- package/dist/auth/oauth/providers.d.ts +10 -0
- package/dist/auth/oauth/providers.d.ts.map +1 -0
- package/dist/bun/plugin.js +1 -1
- package/dist/bun/preload.js +1 -1
- package/dist/{chunk-a3g7y70h.js → chunk-0x1s02r1.js} +3 -3
- package/dist/{chunk-a3g7y70h.js.map → chunk-0x1s02r1.js.map} +1 -1
- package/dist/{chunk-yzhv93b0.js → chunk-1jcngq6w.js} +3 -3
- package/dist/{chunk-yzhv93b0.js.map → chunk-1jcngq6w.js.map} +1 -1
- package/dist/{chunk-mrswc6qw.js → chunk-1mxb44n9.js} +2 -2
- package/dist/{chunk-mrswc6qw.js.map → chunk-1mxb44n9.js.map} +1 -1
- package/dist/{chunk-9tr92nwy.js → chunk-1n40bdxf.js} +2 -2
- package/dist/{chunk-9tr92nwy.js.map → chunk-1n40bdxf.js.map} +1 -1
- package/dist/chunk-1xmh61fg.js +5 -0
- package/dist/{chunk-70nnh0y7.js.map → chunk-1xmh61fg.js.map} +1 -1
- package/dist/{chunk-bt9qv2jj.js → chunk-3br5zr7a.js} +3 -3
- package/dist/{chunk-bt9qv2jj.js.map → chunk-3br5zr7a.js.map} +1 -1
- package/dist/{chunk-w61sphn5.js → chunk-3kxe9geg.js} +3 -3
- package/dist/{chunk-w61sphn5.js.map → chunk-3kxe9geg.js.map} +1 -1
- package/dist/{chunk-bnt8kx6x.js → chunk-5fh4pvyt.js} +2 -2
- package/dist/{chunk-bnt8kx6x.js.map → chunk-5fh4pvyt.js.map} +1 -1
- package/dist/{chunk-rpyczdta.js → chunk-6gwxvmjv.js} +3 -3
- package/dist/{chunk-rpyczdta.js.map → chunk-6gwxvmjv.js.map} +1 -1
- package/dist/{chunk-65s834td.js → chunk-6q6bhkyf.js} +1 -1
- package/dist/{chunk-fn2qfwgx.js → chunk-6vz75swk.js} +2 -2
- package/dist/{chunk-fn2qfwgx.js.map → chunk-6vz75swk.js.map} +1 -1
- package/dist/chunk-6wgh7nk6.js +15 -0
- package/dist/{chunk-n0r5xyk2.js.map → chunk-6wgh7nk6.js.map} +6 -5
- package/dist/chunk-7vrrgxwm.js +22 -0
- package/dist/chunk-7vrrgxwm.js.map +21 -0
- package/dist/{chunk-kzsjyvvc.js → chunk-7zj6bk9a.js} +2 -2
- package/dist/{chunk-kzsjyvvc.js.map → chunk-7zj6bk9a.js.map} +1 -1
- package/dist/{chunk-3hqwz48c.js → chunk-8tvfmy1a.js} +4 -4
- package/dist/{chunk-3hqwz48c.js.map → chunk-8tvfmy1a.js.map} +1 -1
- package/dist/{chunk-6bgb1nhq.js → chunk-910p6ne6.js} +2 -2
- package/dist/{chunk-6bgb1nhq.js.map → chunk-910p6ne6.js.map} +1 -1
- package/dist/{chunk-96a1459v.js → chunk-ap3g6rbw.js} +2 -2
- package/dist/{chunk-96a1459v.js.map → chunk-ap3g6rbw.js.map} +1 -1
- package/dist/{chunk-3j6s5bmx.js → chunk-ayfjjgv2.js} +1 -1
- package/dist/chunk-b4x1dt3s.js +10 -0
- package/dist/chunk-b4x1dt3s.js.map +43 -0
- package/dist/{chunk-f29pktad.js → chunk-b7a22evs.js} +3 -3
- package/dist/{chunk-f29pktad.js.map → chunk-b7a22evs.js.map} +1 -1
- package/dist/{chunk-qdj8ek8z.js → chunk-bny9s44t.js} +2 -2
- package/dist/{chunk-qdj8ek8z.js.map → chunk-bny9s44t.js.map} +1 -1
- package/dist/{chunk-1rnh9qrp.js → chunk-by5gwr8x.js} +2 -2
- package/dist/{chunk-1rnh9qrp.js.map → chunk-by5gwr8x.js.map} +1 -1
- package/dist/{chunk-nn2jeat2.js → chunk-c0qpv8x7.js} +2 -2
- package/dist/{chunk-17dndh5z.js.map → chunk-c0qpv8x7.js.map} +1 -1
- package/dist/{chunk-f4cmz31h.js → chunk-cpem1j1x.js} +2 -2
- package/dist/{chunk-f4cmz31h.js.map → chunk-cpem1j1x.js.map} +1 -1
- package/dist/{chunk-019wz697.js → chunk-crnfxn9n.js} +2 -2
- package/dist/{chunk-019wz697.js.map → chunk-crnfxn9n.js.map} +1 -1
- package/dist/{chunk-s5jxc63j.js → chunk-cwt8e782.js} +3 -3
- package/dist/{chunk-s5jxc63j.js.map → chunk-cwt8e782.js.map} +1 -1
- package/dist/{chunk-fw7ds23a.js → chunk-dxyxd7b3.js} +2 -2
- package/dist/{chunk-fw7ds23a.js.map → chunk-dxyxd7b3.js.map} +1 -1
- package/dist/{chunk-qhz0x97z.js → chunk-dy58aztm.js} +2 -2
- package/dist/{chunk-qhz0x97z.js.map → chunk-dy58aztm.js.map} +1 -1
- package/dist/{chunk-skf89vrv.js → chunk-entpqjyn.js} +2 -2
- package/dist/{chunk-skf89vrv.js.map → chunk-entpqjyn.js.map} +1 -1
- package/dist/{chunk-7gfdts60.js → chunk-eq5svwca.js} +2 -2
- package/dist/{chunk-7gfdts60.js.map → chunk-eq5svwca.js.map} +1 -1
- package/dist/{chunk-n1a2zj5z.js → chunk-erzfs4t2.js} +2 -2
- package/dist/{chunk-n1a2zj5z.js.map → chunk-erzfs4t2.js.map} +3 -3
- package/dist/{chunk-3y294mb8.js → chunk-ex41d03h.js} +2 -2
- package/dist/{chunk-3y294mb8.js.map → chunk-ex41d03h.js.map} +1 -1
- package/dist/{chunk-v2ggafz1.js → chunk-ey1xrbaz.js} +2 -2
- package/dist/{chunk-v2ggafz1.js.map → chunk-ey1xrbaz.js.map} +1 -1
- package/dist/chunk-eyptwf54.js +57 -0
- package/dist/{chunk-5j50q4g8.js.map → chunk-eyptwf54.js.map} +22 -19
- package/dist/{chunk-zsfwcdqn.js → chunk-g52fcwca.js} +2 -2
- package/dist/{chunk-zsfwcdqn.js.map → chunk-g52fcwca.js.map} +1 -1
- package/dist/{chunk-rttrpjqk.js → chunk-ghcvztxn.js} +2 -2
- package/dist/{chunk-rttrpjqk.js.map → chunk-ghcvztxn.js.map} +1 -1
- package/dist/{chunk-wbg2tza5.js → chunk-gp00enrk.js} +1 -1
- package/dist/{chunk-92sk56n0.js → chunk-h8w9mzjj.js} +6 -6
- package/dist/{chunk-92sk56n0.js.map → chunk-h8w9mzjj.js.map} +7 -7
- package/dist/{chunk-cfdwsvtx.js → chunk-hff9w6rt.js} +2 -2
- package/dist/{chunk-cfdwsvtx.js.map → chunk-hff9w6rt.js.map} +1 -1
- package/dist/{chunk-17dndh5z.js → chunk-hxn0s3zh.js} +2 -2
- package/dist/{chunk-nn2jeat2.js.map → chunk-hxn0s3zh.js.map} +1 -1
- package/dist/{chunk-8m2htvjn.js → chunk-hzen9gh4.js} +2 -2
- package/dist/{chunk-8m2htvjn.js.map → chunk-hzen9gh4.js.map} +1 -1
- package/dist/{chunk-c4jnxmf2.js → chunk-j10a0m7q.js} +1 -1
- package/dist/{chunk-5e22tm7m.js → chunk-j12hpdxk.js} +1 -1
- package/dist/{chunk-ykz38t0t.js → chunk-j5rwv09s.js} +2 -2
- package/dist/{chunk-ykz38t0t.js.map → chunk-j5rwv09s.js.map} +1 -1
- package/dist/{chunk-w4z6x54b.js → chunk-jykkqwcy.js} +3 -3
- package/dist/{chunk-w4z6x54b.js.map → chunk-jykkqwcy.js.map} +1 -1
- package/dist/{chunk-w3812s34.js → chunk-k1ebt28j.js} +2 -2
- package/dist/{chunk-w3812s34.js.map → chunk-k1ebt28j.js.map} +1 -1
- package/dist/{chunk-h3p8qzft.js → chunk-kcsa57km.js} +2 -2
- package/dist/{chunk-h3p8qzft.js.map → chunk-kcsa57km.js.map} +1 -1
- package/dist/{chunk-1qwhty9p.js → chunk-khdkrfxp.js} +2 -2
- package/dist/{chunk-1qwhty9p.js.map → chunk-khdkrfxp.js.map} +1 -1
- package/dist/{chunk-b5afy6k9.js → chunk-knq4ack4.js} +2 -2
- package/dist/{chunk-b5afy6k9.js.map → chunk-knq4ack4.js.map} +1 -1
- package/dist/{chunk-121p4g9j.js → chunk-m7pghdcy.js} +2 -2
- package/dist/{chunk-121p4g9j.js.map → chunk-m7pghdcy.js.map} +1 -1
- package/dist/{chunk-rtawbqec.js → chunk-mmqnq1qh.js} +3 -3
- package/dist/{chunk-rtawbqec.js.map → chunk-mmqnq1qh.js.map} +1 -1
- package/dist/{chunk-34fkx6kb.js → chunk-n3z83qhq.js} +2 -2
- package/dist/{chunk-34fkx6kb.js.map → chunk-n3z83qhq.js.map} +1 -1
- package/dist/{chunk-mvkz22p4.js → chunk-npbf06c1.js} +2 -2
- package/dist/{chunk-mvkz22p4.js.map → chunk-npbf06c1.js.map} +1 -1
- package/dist/{chunk-2affxmkn.js → chunk-p5df4pn7.js} +2 -2
- package/dist/{chunk-2affxmkn.js.map → chunk-p5df4pn7.js.map} +1 -1
- package/dist/{chunk-y434jc1c.js → chunk-p6jbmcrg.js} +2 -2
- package/dist/{chunk-y434jc1c.js.map → chunk-p6jbmcrg.js.map} +1 -1
- package/dist/{chunk-jctb7v53.js → chunk-p7mvp5nf.js} +2 -2
- package/dist/{chunk-jctb7v53.js.map → chunk-p7mvp5nf.js.map} +1 -1
- package/dist/{chunk-jys8y39p.js → chunk-q6ah4yjg.js} +2 -2
- package/dist/{chunk-jys8y39p.js.map → chunk-q6ah4yjg.js.map} +1 -1
- package/dist/{chunk-pmyh33v5.js → chunk-r923001x.js} +2 -2
- package/dist/{chunk-pmyh33v5.js.map → chunk-r923001x.js.map} +1 -1
- package/dist/{chunk-mqtfaqx5.js → chunk-rany5zgk.js} +2 -2
- package/dist/{chunk-mqtfaqx5.js.map → chunk-rany5zgk.js.map} +1 -1
- package/dist/{chunk-30xxc6r7.js → chunk-rmgkc3a2.js} +2 -2
- package/dist/{chunk-30xxc6r7.js.map → chunk-rmgkc3a2.js.map} +1 -1
- package/dist/{chunk-v8v5qfnh.js → chunk-rvspb96n.js} +3 -3
- package/dist/{chunk-v8v5qfnh.js.map → chunk-rvspb96n.js.map} +1 -1
- package/dist/{chunk-zsvav1dk.js → chunk-rwmja4zs.js} +2 -2
- package/dist/{chunk-zsvav1dk.js.map → chunk-rwmja4zs.js.map} +1 -1
- package/dist/{chunk-j7v7dft7.js → chunk-s4semb89.js} +1 -1
- package/dist/{chunk-szn2n976.js → chunk-s4xg69r9.js} +2 -2
- package/dist/{chunk-szn2n976.js.map → chunk-s4xg69r9.js.map} +1 -1
- package/dist/{chunk-4drnyymm.js → chunk-stn0a56e.js} +2 -2
- package/dist/{chunk-4drnyymm.js.map → chunk-stn0a56e.js.map} +1 -1
- package/dist/{chunk-pe46a5a5.js → chunk-sv125fqq.js} +2 -2
- package/dist/{chunk-pe46a5a5.js.map → chunk-sv125fqq.js.map} +1 -1
- package/dist/{chunk-dxfhhw5h.js → chunk-t2t63wa0.js} +2 -2
- package/dist/{chunk-dxfhhw5h.js.map → chunk-t2t63wa0.js.map} +1 -1
- package/dist/{chunk-675kzd7z.js → chunk-t6qpm2j7.js} +2 -2
- package/dist/{chunk-675kzd7z.js.map → chunk-t6qpm2j7.js.map} +1 -1
- package/dist/chunk-tabsxzg9.js +5 -0
- package/dist/chunk-tabsxzg9.js.map +13 -0
- package/dist/{chunk-qycwjzsv.js → chunk-vhvvjaj3.js} +3 -3
- package/dist/{chunk-qycwjzsv.js.map → chunk-vhvvjaj3.js.map} +1 -1
- package/dist/{chunk-sd0c2001.js → chunk-x2j84d06.js} +2 -2
- package/dist/{chunk-sd0c2001.js.map → chunk-x2j84d06.js.map} +1 -1
- package/dist/{chunk-75ewjc4a.js → chunk-xe2pm36q.js} +2 -2
- package/dist/{chunk-75ewjc4a.js.map → chunk-xe2pm36q.js.map} +1 -1
- package/dist/{chunk-z5jydj5r.js → chunk-xfvegbxn.js} +2 -2
- package/dist/{chunk-z5jydj5r.js.map → chunk-xfvegbxn.js.map} +1 -1
- package/dist/{chunk-2n4490pk.js → chunk-y9f2see3.js} +3 -3
- package/dist/{chunk-2n4490pk.js.map → chunk-y9f2see3.js.map} +1 -1
- package/dist/{chunk-nkzmk7v3.js → chunk-yhht1j7f.js} +2 -2
- package/dist/{chunk-nkzmk7v3.js.map → chunk-yhht1j7f.js.map} +1 -1
- package/dist/{chunk-nnarmbjv.js → chunk-z5nfve1k.js} +2 -2
- package/dist/chunk-z5nfve1k.js.map +10 -0
- package/dist/{chunk-fvrmptd0.js → chunk-zq5375wd.js} +3 -3
- package/dist/{chunk-fvrmptd0.js.map → chunk-zq5375wd.js.map} +1 -1
- package/dist/chunks/{ThemeProvider-CbOx8IRl.js → ThemeProvider-CS2a1snV.js} +27 -1
- package/dist/chunks/ThemeProvider-CS2a1snV.js.map +1 -0
- package/dist/client/Mutation.d.ts +7 -6
- package/dist/client/Mutation.d.ts.map +1 -1
- package/dist/client/MutationError.d.ts +53 -1
- package/dist/client/MutationError.d.ts.map +1 -1
- package/dist/client/QueryResource.d.ts +9 -0
- package/dist/client/QueryResource.d.ts.map +1 -1
- package/dist/client/auth/useEmailCode.d.ts +3 -3
- package/dist/client/auth/useForgotPassword.d.ts +1 -1
- package/dist/client/auth/useResetPassword.d.ts +1 -1
- package/dist/client/auth/useSignIn.d.ts +1 -1
- package/dist/client/auth/useSignOut.d.ts +1 -1
- package/dist/client/auth/useSignUp.d.ts +1 -1
- package/dist/client/index.d.ts +4 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +136 -9
- package/dist/client/index.js.map +1 -1
- package/dist/client/useMutation.d.ts +18 -8
- package/dist/client/useMutation.d.ts.map +1 -1
- package/dist/client/useSetQueryData.d.ts +69 -0
- package/dist/client/useSetQueryData.d.ts.map +1 -0
- package/dist/config/index.js +1 -1
- package/dist/console/run.js +2 -2
- package/dist/console/run.js.map +1 -1
- package/dist/container/index.js +2 -2
- package/dist/container/index.js.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/email/index.js +2 -2
- package/dist/email/index.js.map +1 -1
- package/dist/facades/Auth.d.ts +29 -2
- package/dist/facades/Auth.d.ts.map +1 -1
- package/dist/facades/RateLimiter.d.ts +16 -1
- package/dist/facades/RateLimiter.d.ts.map +1 -1
- package/dist/facades/index.js +2 -2
- package/dist/facades/index.js.map +1 -1
- package/dist/foundation/index.js +2 -2
- package/dist/foundation/index.js.map +1 -1
- package/dist/http/HttpRequest.d.ts +14 -0
- package/dist/http/HttpRequest.d.ts.map +1 -1
- package/dist/http/McpRouter.d.ts +121 -2
- package/dist/http/McpRouter.d.ts.map +1 -1
- package/dist/http/RateLimitExceededError.d.ts +24 -0
- package/dist/http/RateLimitExceededError.d.ts.map +1 -0
- package/dist/http/RateLimitMiddleware.d.ts +2 -5
- package/dist/http/RateLimitMiddleware.d.ts.map +1 -1
- package/dist/http/index.d.ts +2 -1
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +2 -2
- package/dist/http/index.js.map +1 -1
- package/dist/http/refusal.d.ts +6 -1
- package/dist/http/refusal.d.ts.map +1 -1
- package/dist/http/requestContext.d.ts +3 -1
- package/dist/http/requestContext.d.ts.map +1 -1
- package/dist/http/requestState.d.ts +57 -0
- package/dist/http/requestState.d.ts.map +1 -0
- package/dist/i18n/dictionaryRuntime.js +2 -2
- package/dist/i18n/dictionaryRuntime.js.map +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +1 -1
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +1 -1
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +1 -1
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/health.d.ts +67 -0
- package/dist/server/health.d.ts.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +5 -4
- package/dist/server/shutdown.d.ts +3 -4
- package/dist/server/shutdown.d.ts.map +1 -1
- package/dist/services/features/gate.d.ts +11 -0
- package/dist/services/features/gate.d.ts.map +1 -0
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +3 -3
- package/dist/services/index.js.map +2 -2
- package/dist/services/logging/LogManager.d.ts +1 -0
- package/dist/services/logging/LogManager.d.ts.map +1 -1
- package/dist/services/logging/config.d.ts +23 -1
- package/dist/services/logging/config.d.ts.map +1 -1
- package/dist/services/logging/consoleSink.d.ts +25 -0
- package/dist/services/logging/consoleSink.d.ts.map +1 -0
- package/dist/services/mcp/McpRegistry.d.ts +106 -14
- package/dist/services/mcp/McpRegistry.d.ts.map +1 -1
- package/dist/services/mcp/http/McpHttpServer.d.ts +41 -2
- package/dist/services/mcp/http/McpHttpServer.d.ts.map +1 -1
- package/dist/services/mcp/toAgentTools.d.ts +21 -3
- package/dist/services/mcp/toAgentTools.d.ts.map +1 -1
- package/dist/services/queue/work.js +2 -2
- package/dist/services/queue/work.js.map +1 -1
- package/dist/services/rate-limiter/RateLimiter.d.ts +12 -0
- package/dist/services/rate-limiter/RateLimiter.d.ts.map +1 -1
- package/dist/services/router/globalMiddleware.d.ts +4 -3
- package/dist/services/router/globalMiddleware.d.ts.map +1 -1
- package/dist/stats/route-table.js +1 -1
- package/dist/support/index.js +2 -2
- package/dist/support/index.js.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/vitest/index.js +1 -1
- package/package.json +1 -1
- package/skills/gemi-react-best-practices/SKILL.md +1 -1
- package/skills/gemi-react-best-practices/rules/query-mutate-over-refetch.md +14 -0
- package/skills/gemi-react-best-practices/rules/routing-middleware-dsl.md +2 -1
- package/dist/chunk-5j50q4g8.js +0 -57
- package/dist/chunk-70nnh0y7.js +0 -5
- package/dist/chunk-kc924zjz.js +0 -5
- package/dist/chunk-kc924zjz.js.map +0 -12
- package/dist/chunk-n0r5xyk2.js +0 -14
- package/dist/chunk-nnarmbjv.js.map +0 -10
- package/dist/chunk-pya4rqm2.js +0 -5
- package/dist/chunk-pya4rqm2.js.map +0 -12
- package/dist/chunk-zmf3vhex.js +0 -10
- package/dist/chunk-zmf3vhex.js.map +0 -43
- package/dist/chunks/ThemeProvider-CbOx8IRl.js.map +0 -1
- /package/dist/{chunk-65s834td.js.map → chunk-6q6bhkyf.js.map} +0 -0
- /package/dist/{chunk-3j6s5bmx.js.map → chunk-ayfjjgv2.js.map} +0 -0
- /package/dist/{chunk-wbg2tza5.js.map → chunk-gp00enrk.js.map} +0 -0
- /package/dist/{chunk-c4jnxmf2.js.map → chunk-j10a0m7q.js.map} +0 -0
- /package/dist/{chunk-5e22tm7m.js.map → chunk-j12hpdxk.js.map} +0 -0
- /package/dist/{chunk-j7v7dft7.js.map → chunk-s4semb89.js.map} +0 -0
package/dist/ai/index.js.map
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../ai/
|
|
3
|
+
"sources": ["../ai/jobs/AgentJobDeadlineSweep.ts", "../ai/jobs/contextBlock.ts", "../ai/jobs/DatabaseAgentJobStore.ts", "../services/mcp/toAgentTools.ts", "../ai/ImageModel.ts", "../ai/providers/endpoints.ts", "../ai/providers/http.ts", "../ai/providers/images.ts", "../ai/ImageProvider.ts", "../ai/providers/fileRejection.ts", "../ai/providers/stream.ts", "../ai/providers/call.ts", "../ai/providers/capabilities.ts", "../ai/providers/request.ts", "../ai/AgentProvider.ts", "../ai/CircuitStore.ts", "../ai/FallbackProvider.ts", "../ai/store/LiveRuns.ts", "../ai/store/FileOwners.ts", "../ai/store/Receipts.ts", "../ai/store/MemoryAgentStore.ts", "../ai/client/reducer.ts", "../ai/store/TurnJournal.ts", "../ai/jobs/overlay.ts", "../ai/AgentController.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { AgentError } from \"../types\";\n\n/**\n * A non-2xx response, carried as an exception so the retry loop and\n * `normalizeError` can both read it.\n *\n * The body is kept parsed-if-possible and raw-if-not: OpenAI and Azure both\n * answer `{ error: { message, type, code } }` on a good day, and an HTML error\n * page from a proxy on a bad one, and the bad day is exactly when the text\n * matters.\n */\nexport class ProviderHttpError extends Error {\n readonly status: number;\n readonly body: unknown;\n readonly requestId?: string;\n\n constructor(status: number, body: unknown, requestId?: string) {\n super(`Provider request failed with status ${status}: ${describeBody(body)}`);\n this.name = \"ProviderHttpError\";\n this.status = status;\n this.body = body;\n this.requestId = requestId;\n }\n}\n\n/**\n * The request ran out of time. Its own class because it must not read as a\n * user abort: `stop()` means the person is done, and a timeout means the\n * network was, and only one of those is worth trying again.\n */\nexport class ProviderTimeoutError extends Error {\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number) {\n super(`Provider request timed out after ${timeoutMs}ms`);\n this.name = \"ProviderTimeoutError\";\n this.timeoutMs = timeoutMs;\n }\n}\n\nfunction describeBody(body: unknown): string {\n const detail = errorBody(body);\n if (detail?.message) return detail.message;\n if (typeof body === \"string\") return body.slice(0, 500);\n return \"no error body\";\n}\n\ntype OpenAIErrorBody = { message?: string; type?: string; code?: string; param?: string };\n\nfunction errorBody(body: unknown): OpenAIErrorBody | null {\n if (!body || typeof body !== \"object\") return null;\n const wrapper = body as { error?: unknown };\n const inner = wrapper.error && typeof wrapper.error === \"object\" ? wrapper.error : body;\n const e = inner as OpenAIErrorBody & { innererror?: { code?: string } };\n if (typeof e.message !== \"string\" && typeof e.code !== \"string\" && typeof e.type !== \"string\") {\n return null;\n }\n // Azure hides the interesting code one level down when its content filter\n // fires, and the outer code is the useless `content_filter`.\n const code = e.innererror?.code ?? e.code;\n return { message: e.message, type: e.type, code, param: e.param };\n}\n\n/**\n * The HTTP status and request id of a provider failure, read off what was\n * thrown — server-side detail for `AgentRunResult.error`, never for a frame.\n *\n * By shape rather than by `instanceof ProviderHttpError`, so a custom provider\n * whose SDK throws its own error class with a `status` gets the same detail.\n * A `status` outside 100–599 is not an HTTP status and is ignored.\n */\nexport function httpErrorDetail(error: unknown): { status?: number; requestId?: string } {\n if (!error || typeof error !== \"object\") return {};\n const { status, requestId } = error as { status?: unknown; requestId?: unknown };\n return {\n ...(typeof status === \"number\" && status >= 100 && status <= 599 ? { status } : {}),\n ...(typeof requestId === \"string\" && requestId ? { requestId } : {}),\n };\n}\n\n/**\n * Provider failures onto `AgentErrorCode`.\n *\n * The contract an app is buying here is that it can branch on `rate_limited`\n * without knowing whose rate limit it was, and on `retryable` without knowing\n * which of the two APIs answered. So `retryable` is set from what is actually\n * true of the failure — a 429 from a spent quota is not retryable no matter\n * what its status code says, and neither is a request that will be too long\n * again next time.\n */\nexport function normalizeProviderError(error: unknown): AgentError {\n if (error instanceof ProviderTimeoutError) {\n return { code: \"provider_error\", message: error.message, retryable: true };\n }\n\n if (isAbort(error)) {\n return { code: \"aborted\", message: \"The request was aborted.\", retryable: false };\n }\n\n if (error instanceof ProviderHttpError) {\n return fromStatus(error.status, errorBody(error.body), error.message);\n }\n\n // `fetch` rejects with a TypeError for DNS failures, refused connections and\n // dropped sockets. Every one of those is worth another attempt.\n if (error instanceof TypeError) {\n return {\n code: \"provider_error\",\n message: `Could not reach the provider: ${error.message}`,\n retryable: true,\n };\n }\n\n if (error instanceof Error) {\n return { code: \"provider_error\", message: error.message, retryable: false };\n }\n\n return { code: \"unknown\", message: String(error), retryable: false };\n}\n\nfunction fromStatus(\n status: number,\n body: OpenAIErrorBody | null,\n fallbackMessage: string,\n): AgentError {\n const message = body?.message ?? fallbackMessage;\n const code = (body?.code ?? \"\").toLowerCase();\n const type = (body?.type ?? \"\").toLowerCase();\n const haystack = `${code} ${type} ${message}`.toLowerCase();\n\n if (status === 429) {\n // A spent quota answers 429 and will answer 429 for the rest of the month.\n // Retrying it is how a run turns one billing problem into `maxRetries`\n // billing problems and a much later error message.\n const outOfCredit = code === \"insufficient_quota\" || haystack.includes(\"quota\");\n return { code: \"rate_limited\", message, retryable: !outOfCredit };\n }\n\n if (status >= 500 || status === 408 || status === 409) {\n return { code: \"provider_error\", message, retryable: true };\n }\n\n if (isContextLength(haystack)) {\n return { code: \"context_length_exceeded\", message, retryable: false };\n }\n\n if (isContentFilter(haystack)) {\n return { code: \"content_filtered\", message, retryable: false };\n }\n\n // A schema the API refused. It is our request that is wrong, so the run\n // should surface it as a tool problem rather than a generic outage.\n if (body?.param?.startsWith(\"tools\") || haystack.includes(\"invalid schema for function\")) {\n return { code: \"invalid_tool_input\", message, retryable: false };\n }\n\n return { code: \"provider_error\", message, retryable: false };\n}\n\nfunction isContextLength(haystack: string): boolean {\n return (\n haystack.includes(\"context_length_exceeded\") ||\n haystack.includes(\"maximum context length\") ||\n haystack.includes(\"context window\") ||\n haystack.includes(\"reduce the length\")\n );\n}\n\nfunction isContentFilter(haystack: string): boolean {\n return (\n haystack.includes(\"content_filter\") ||\n haystack.includes(\"content_policy_violation\") ||\n haystack.includes(\"responsibleaipolicyviolation\") ||\n haystack.includes(\"content management policy\")\n );\n}\n\nfunction isAbort(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const e = error as { name?: string; code?: string };\n return e.name === \"AbortError\" || e.code === \"ABORT_ERR\";\n}\n",
|
|
6
|
-
"import type { ProviderStreamParams } from \"./AgentProvider\";\nimport { supportsStrict, type Schema } from \"./Schema\";\nimport type { AgentError, AgentMessage, Usage } from \"./types\";\n\n/**\n * What one model call needs, whether the agent loop makes it or `generate` does.\n *\n * Moved out of `Agent.ts` rather than copied when `generate` arrived (#594).\n * `generate` is the agent's step without the loop around it — assemble one\n * call, read the stream, parse the answer — so each of these would otherwise\n * exist twice, and the two copies of \"how is a structured answer parsed\" or\n * \"how is usage summed\" are exactly the kind that drift apart unnoticed.\n *\n * Internal. Nothing here is exported from `gemi/ai`.\n */\n\n// --- aborting --------------------------------------------------------------\n\nexport class RunAborted extends Error {\n constructor() {\n super(\"The run was stopped\");\n this.name = \"RunAborted\";\n }\n}\n\nexport function raceAbort<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) {\n return Promise.reject(new RunAborted());\n }\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(new RunAborted());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", onAbort));\n });\n}\n\n// --- usage -----------------------------------------------------------------\n\nexport function emptyUsage(): Usage {\n return { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\n}\n\nexport function addUsage(total: Usage, next: Usage | undefined): Usage {\n if (!next) return total;\n const merged: Usage = {\n inputTokens: total.inputTokens + (next.inputTokens ?? 0),\n outputTokens: total.outputTokens + (next.outputTokens ?? 0),\n totalTokens: total.totalTokens + (next.totalTokens ?? 0),\n };\n if (next.reasoningTokens !== undefined || total.reasoningTokens !== undefined) {\n merged.reasoningTokens = (total.reasoningTokens ?? 0) + (next.reasoningTokens ?? 0);\n }\n if (next.cachedInputTokens !== undefined || total.cachedInputTokens !== undefined) {\n merged.cachedInputTokens = (total.cachedInputTokens ?? 0) + (next.cachedInputTokens ?? 0);\n }\n if (next.imageInputTokens !== undefined || total.imageInputTokens !== undefined) {\n merged.imageInputTokens = (total.imageInputTokens ?? 0) + (next.imageInputTokens ?? 0);\n }\n if (next.imageOutputTokens !== undefined || total.imageOutputTokens !== undefined) {\n merged.imageOutputTokens = (total.imageOutputTokens ?? 0) + (next.imageOutputTokens ?? 0);\n }\n return merged;\n}\n\n// --- structured output -----------------------------------------------------\n\n/**\n * The best parse of a JSON document that is still arriving.\n *\n * Exists so a UI can bind fields before the object closes. It closes whatever\n * brackets are open and drops a trailing key with no value; when even that does\n * not parse it gives up and returns an empty object rather than throwing,\n * because a snapshot is a convenience and a run must not die for one.\n */\nexport function bestEffortParse(text: string): any {\n if (!text.trim()) return {};\n try {\n return JSON.parse(text);\n } catch {\n // fall through to repair\n }\n const closers: string[] = [];\n let inString = false;\n let escaped = false;\n for (const char of text) {\n if (inString) {\n if (escaped) escaped = false;\n else if (char === \"\\\\\") escaped = true;\n else if (char === '\"') inString = false;\n continue;\n }\n if (char === '\"') inString = true;\n else if (char === \"{\") closers.push(\"}\");\n else if (char === \"[\") closers.push(\"]\");\n else if (char === \"}\" || char === \"]\") closers.pop();\n }\n let repaired = text;\n if (inString) repaired += '\"';\n repaired = repaired.replace(/[,:]\\s*$/, \"\");\n const suffix = closers.reverse().join(\"\");\n try {\n return JSON.parse(repaired + suffix);\n } catch {\n // A trailing `\"key\":` leaves a property with no value; drop the key too.\n try {\n return JSON.parse(repaired.replace(/,?\\s*\"[^\"]*\"\\s*$/, \"\") + suffix);\n } catch {\n return {};\n }\n }\n}\n/**\n * The `output` parameter a provider is sent for a schema.\n *\n * `strict` is read off the schema, never chosen: an `s.json()` node anywhere in\n * it has no spelling in strict mode, so a schema containing one is sent\n * non-strict and the provider does not answer 400.\n */\nexport function outputFormat(schema: Schema<any>): NonNullable<ProviderStreamParams[\"output\"]> {\n return { name: \"output\", schema: schema.toJSONSchema(), strict: supportsStrict(schema) };\n}\n\n/**\n * A finished structured answer, checked against its schema.\n *\n * The failure is an `AgentError` with `code: \"invalid_output\"` rather than the\n * schema's own `errors: string[]`, so a caller branches on a code the way it\n * does for `invalid_tool_input`, and the list is joined into the message for a\n * person — or a retry prompt — to read.\n *\n * `bestEffortParse`, not `JSON.parse`, for the reason the agent loop has always\n * used it: the text is the whole answer by now, so the repair has nothing to\n * close, and a document that still does not parse comes back `{}` and fails the\n * schema with a message naming what is missing, instead of a `SyntaxError`\n * position nobody can act on. A cut-off answer never reaches here — see the\n * `length` checks in both callers — because a repaired prefix can pass a loose\n * schema and look finished.\n */\nexport function parseOutput<T>(\n schema: Schema<T>,\n text: string,\n): { ok: true; value: T } | { ok: false; error: AgentError } {\n const parsed = schema.safeParse(bestEffortParse(text));\n if (parsed.ok === true) return { ok: true, value: parsed.value };\n return {\n ok: false,\n error: {\n code: \"invalid_output\",\n message: `The model's structured answer did not match the output schema: ${parsed.errors.join(\", \")}`,\n retryable: true,\n },\n };\n}\n\n// --- building the assistant message ----------------------------------------\n\n/**\n * Resolves a string built by repeated concatenation, in place.\n *\n * `text = text + delta`, run once per streamed token, does not build a string —\n * it builds a rope: a tree of pointers to every fragment, which the engine\n * flattens only when something needs the characters contiguously. A message\n * that nothing reads before it is persisted therefore keeps all of its\n * fragments alive, and the tree costs several times the text.\n *\n * Measured on Bun 1.x, 600 deltas of six characters (a ~450-token answer, 3.5 KB\n * of ASCII): held as a rope, 18.7 KB. Resolved, 3.5 KB — half the UTF-16 size,\n * because a flat ASCII string is stored one byte per character and a rope\n * cannot be. That is 5.3x, and it is paid by every message a store keeps and\n * every run the live registry holds.\n *\n * Indexing is what forces the resolution: `text[0]` cannot be answered without\n * the characters, so the engine collapses the tree and drops the fragments.\n * Nothing is allocated and nothing is copied, which is why this is not\n * `split(\"\").join(\"\")` — that measures the same but allocates one string per\n * character to get there.\n *\n * DO NOT DELETE THIS AS A NO-OP. It reads like one and it is not; the value is\n * the side effect on the receiver. If a future engine does not resolve on\n * index, this silently becomes a real no-op and memory returns to what it is\n * today — a safe failure, which is why it is written as a hint rather than as a\n * round trip through an encoder that would also mangle a lone surrogate.\n */\nexport function resolveRope(text: string): string {\n if (text.length > 0) void text[0];\n return text;\n}\n\nexport function appendText(message: AgentMessage, type: \"text\" | \"reasoning\", delta: string) {\n const last = message.content[message.content.length - 1];\n if (last && last.type === type) {\n (last as { text?: string }).text = ((last as { text?: string }).text ?? \"\") + delta;\n return;\n }\n message.content.push(\n type === \"text\" ? { type: \"text\", text: delta } : { type: \"reasoning\", text: delta },\n );\n}\n\n/**\n * Reasoning is accumulated per ITEM, not per message, and the item's id is kept.\n *\n * This used to go through `appendText`, which merges on the part *type* alone\n * and has nowhere to put an id. Both halves of that were wrong and neither was\n * visible in the transcript:\n *\n * - `request.ts` drops a reasoning item with no id, deliberately — the id is\n * the API's handle on the stored reasoning and a fabricated one would look\n * like continuity that is not there. So an id dropped here meant reasoning\n * was never sent back at all: on a two-step run the model re-derived its\n * own argument from nothing, and the prompt cache (which keys on the\n * literal item) missed every time. Measured against the live Responses API\n * in `live/live.test.ts`: the second call's input carried zero reasoning\n * items.\n * - a step that produces two reasoning items was flattening them into one\n * part, so even with an id there would have been one id for two items'\n * text.\n *\n * A part with no id is still appended rather than dropped: the text is what a\n * UI renders, and a provider that reports no item id (Azure does not always)\n * should still show its thinking. It just cannot be echoed back, which is the\n * bargain `reasoningItem` already documents.\n */\nexport function appendReasoning(message: AgentMessage, id: string | undefined, delta: string) {\n const last = message.content[message.content.length - 1];\n if (last && last.type === \"reasoning\" && last.id === id) {\n last.text = (last.text ?? \"\") + delta;\n return;\n }\n message.content.push(\n id ? { type: \"reasoning\", id, text: delta } : { type: \"reasoning\", text: delta },\n );\n}\n",
|
|
7
|
-
"import { Log } from \"../facades/Log\";\nimport { AgentRunError, type AgentRunFailure, type ReasoningEffort } from \"./Agent\";\nimport type { AgentProvider } from \"./AgentProvider\";\nimport { httpErrorDetail } from \"./providers/errors\";\nimport {\n addUsage,\n appendReasoning,\n appendText,\n emptyUsage,\n outputFormat,\n parseOutput,\n raceAbort,\n resolveRope,\n RunAborted,\n} from \"./runtime\";\nimport type { Infer, Schema } from \"./Schema\";\nimport type { AgentError, AgentMessage, FinishReason, Usage } from \"./types\";\n\n/**\n * One model call with an output schema: no tools, no loop, no stream to a client.\n *\n * const result = await generate({\n * provider,\n * instructions: \"You are the copywriter of …\",\n * prompt: `The business: ${description}`,\n * output: s.object({ headline: s.string(), cta: s.string() }),\n * });\n * if (result.ok) save(result.output);\n *\n * WHAT IT IS FOR. Before this, the only structured generation gemi offered was\n * an `Agent` with an `output` schema, and an app that wanted one typed answer\n * got a tool loop it did not want and — through `ctx.runAgent` — a nested\n * transcript streamed to the browser for a value the browser never renders\n * (#594, #595). This is the agent's step without the agent: it assembles the\n * same provider call and parses the answer the same way (`runtime.ts` holds\n * both halves, shared), and that is all it does.\n *\n * INSIDE A TOOL, CALL `ctx.generate` INSTEAD. It is this function with the turn\n * bound in, not a second implementation: it aborts when the turn is stopped and\n * adds its usage to the turn's, two things a tool passing `ctx.signal` by hand\n * would forget invisibly. See `ToolContext.generate`.\n *\n * IT DOES NOT THROW FOR A BAD ANSWER. It returns `{ ok: false, error }`, and\n * `messages` and `usage` are on both arms. That is the requesting app's retry\n * pattern, and the reason for the shape: a rejected answer is retried by\n * continuing the conversation — `messages` plus \"your output was rejected:\n * <problems>\" — so the transcript holding the reply that failed is exactly\n * what the retry needs, and a throw would have lost it or buried it on an\n * exception. Usage is on both because the tokens were billed either way, and\n * the failed attempt is the one an app repeats. It is also how the rest of the\n * module already reports: `Schema.safeParse` returns a result, and a failing\n * tool is a result the model reads. Pass `throwOnError: true` to have it\n * reject with an `AgentRunError` instead, as `run.result()` can.\n *\n * A FAILURE IS LOGGED through `Log.error` by default, as a failed agent run is\n * (`logErrors: false` turns it off); a stop is not a failure and is not. On\n * `ok: false`, `error` also carries the provider's HTTP `status` and\n * `requestId` when it answered with an error, as `result().error` does.\n *\n * `error.code` says which failure it was:\n *\n * - `invalid_output` — the answer did not match the schema, was cut off at\n * `maxOutputTokens` (then `finishReason` is `\"length\"`), or never came.\n * - `timeout` — `signal` fired with a `TimeoutError`: an\n * `AbortSignal.timeout`, or the tool's `timeoutMs` under `ctx.generate`.\n * - `aborted` — `signal` fired for any other reason: a stop.\n * - anything else — the provider failed, normalized by the provider's own\n * `normalizeError` exactly as a failed agent step is (`rate_limited`,\n * `content_filtered`, `provider_error`, …).\n *\n * The one thing that does throw is a call that could never work: neither\n * `prompt` nor `messages`. That is a bug in the caller, not an outcome.\n *\n * NOT MEMOIZED, AND NOT RECORDED. It writes nothing to a thread and sends no\n * frame, which is the point of it — and it also means a tool body that is\n * re-entered after an escalation (see `ToolContext.runAgent`) calls the model\n * again. `ctx.runAgent` and `ctx.generateImage` can replay because they record\n * on the tool call; this has nothing to record into by design.\n */\nexport function generate<O extends Schema<any>>(\n params: GenerateParams<O> & { throwOnError: true },\n): Promise<GenerateSuccess<Infer<O>>>;\nexport function generate<O extends Schema<any>>(\n params: GenerateParams<O>,\n): Promise<GenerateResult<Infer<O>>>;\nexport function generate(params: GenerateParams): Promise<GenerateResult<unknown>> {\n return generateWithin(params);\n}\n\n/**\n * Where a `generate` call was made from, for its log line: `ctx.generate`\n * passes the agent, run and tool call it belongs to.\n */\nexport type GenerateOrigin = Record<string, unknown>;\n\n/**\n * `generate`, plus what `ctx.generate` needs to bind it to a turn: the origin\n * for the log line, and `settled`, which sees the result before it is logged\n * or thrown. That is where the turn adds the usage (billed whether or not the\n * answer parsed, and whether or not it is about to throw) and throws when the\n * turn itself was stopped.\n */\nexport async function generateWithin(\n params: GenerateParams,\n hooks: { origin?: GenerateOrigin; settled?: (result: GenerateResult<unknown>) => void } = {},\n): Promise<GenerateResult<unknown>> {\n // An id for the call, so the log line and an `AgentRunError` can be matched\n // up. `gen_` rather than `run_`: there is no run, and nothing is stored.\n const id = `gen_${crypto.randomUUID()}`;\n const result = await callModel(params);\n hooks.settled?.(result);\n if (!result.ok) {\n // A stop is an outcome the caller asked for, not a failure — the same rule\n // an agent run follows (an aborted run carries no `error` and is not\n // logged). A timeout is a failure: it reports `timeout`, as a run's\n // deadline does, and is logged.\n if (params.logErrors !== false && result.error.code !== \"aborted\") {\n logFailure(id, result.error, hooks.origin);\n }\n if (params.throwOnError) {\n throw new AgentRunError({\n runId: id,\n messages: result.messages,\n finishReason: result.finishReason,\n usage: result.usage,\n error: result.error,\n });\n }\n }\n return result;\n}\n\n/**\n * Through the app's logger, as a failed agent run is (`AgentRunImpl.logFailure`):\n * `Log.error`, so it lands in `storage/logs` and `onLogCreated`; outside an\n * application, where there is no logger to resolve, `console.error` instead;\n * and in development the console as well.\n */\nfunction logFailure(id: string, failure: AgentRunFailure, origin?: GenerateOrigin): void {\n const message = `[gemi/ai] generate() failed (${failure.code}${\n failure.status !== undefined ? ` ${failure.status}` : \"\"\n }): ${failure.message}`;\n const metadata = { ...origin, generateId: id, error: failure };\n let logged = false;\n try {\n Log.error(message, metadata);\n logged = true;\n } catch {\n // No application to resolve a logger from. Reported below instead.\n }\n if (!logged || process.env.NODE_ENV === \"development\") {\n console.error(message, metadata);\n }\n}\n\nasync function callModel<O extends Schema<any>>(\n params: GenerateParams<O>,\n): Promise<GenerateResult<Infer<O>>> {\n const prior = params.messages ?? [];\n if (prior.length === 0 && !params.prompt) {\n throw new Error(\n \"generate() was given neither a `prompt` nor `messages`, so there is nothing to send the model.\",\n );\n }\n\n const messages: AgentMessage[] = [...prior];\n if (params.prompt) {\n messages.push({\n id: `msg_${crypto.randomUUID()}`,\n role: \"user\",\n content: [{ type: \"text\", text: params.prompt }],\n createdAt: new Date().toISOString(),\n });\n }\n const reply: AgentMessage = {\n id: `msg_${crypto.randomUUID()}`,\n role: \"assistant\",\n content: [],\n createdAt: new Date().toISOString(),\n };\n\n // `raceAbort` wants a signal to race, and a caller with none gets one that\n // never fires rather than a second code path.\n const signal = params.signal ?? new AbortController().signal;\n let usage = emptyUsage();\n let reason: FinishReason = \"stop\";\n let error: AgentError | undefined;\n // The HTTP status and request id of a failed provider response, as an agent\n // run records them on `result().error` (#656). Server-side only.\n let detail: { status?: number; requestId?: string } = {};\n let outputText = \"\";\n\n try {\n const stream = params.provider.stream({\n // A copy: the provider is handed the array and has no business growing\n // the one this function is about to return.\n messages: [...messages],\n systemPrompt: params.instructions?.trim() ? params.instructions : undefined,\n output: outputFormat(params.output),\n reasoning: params.reasoning,\n maxOutputTokens: params.maxOutputTokens,\n temperature: params.temperature,\n signal: params.signal,\n });\n const iterator = stream[Symbol.asyncIterator]();\n try {\n for (;;) {\n // Raced, as the agent's step is: a provider that ignores its signal\n // must not be able to hold a stopped call open.\n const next = await raceAbort(Promise.resolve(iterator.next()), signal);\n if (next.done) break;\n const event = next.value;\n switch (event.type) {\n case \"output-delta\":\n outputText += event.delta;\n break;\n // Kept on the reply for what they are worth to a retry: reasoning\n // carries its item id so a continuation echoes it back and keeps the\n // prompt cache, and prose is what a model that ignored the format\n // said instead.\n case \"text-delta\":\n appendText(reply, \"text\", event.delta);\n break;\n case \"reasoning-delta\":\n appendReasoning(reply, event.id, event.delta);\n break;\n case \"finish\":\n // Usage is taken whatever happened before it; the reason only if\n // nothing already failed. A content filter reports an error and\n // then closes the call with a finish that still bills — the same\n // rule `AgentRunImpl.runStep` follows.\n usage = addUsage(usage, event.usage);\n if (!error) reason = event.reason;\n break;\n case \"error\":\n reason = \"error\";\n error = event.error;\n detail = httpErrorDetail(event);\n break;\n // `tool-call-delta`, `tool-call` and `tool-search` cannot happen:\n // no tools were sent.\n // `file-rejected` needs nothing here: the provider already sent the\n // call again without that file, and `generate()` keeps no thread\n // to mark the part in. The caller's `messages` are its own.\n }\n }\n } finally {\n // Not awaited. On the abort path the generator may be parked inside a\n // `fetch` that ignores its signal, and waiting on it would give back\n // the hang the race above exists to prevent.\n if (signal.aborted) void Promise.resolve(iterator.return?.()).catch(() => {});\n }\n } catch (thrown) {\n if (thrown instanceof RunAborted || signal.aborted) {\n reason = \"aborted\";\n error = abortError(signal);\n } else {\n reason = \"error\";\n error = params.provider.normalizeError(thrown);\n detail = httpErrorDetail(thrown);\n }\n }\n\n // A flag rather than `output !== undefined`: the schema decides what a\n // valid answer is, and nothing says it cannot be a falsy one.\n let answered = false;\n let output: Infer<O> | undefined;\n if (!error) {\n if (reason === \"length\") {\n // Never parsed. A cut-off answer is a prefix of the JSON the model meant\n // to write, `bestEffortParse` closes its brackets, and against a loose\n // schema — `s.json()` — the repaired half passes looking finished. The\n // agent loop withholds its `output` part for the same reason.\n error = {\n code: \"invalid_output\",\n message:\n \"The model ran out of output tokens before finishing its structured answer, so it was cut off. Raise maxOutputTokens, or ask for a shorter answer.\",\n retryable: true,\n };\n } else if (!outputText.trim()) {\n error = {\n code: \"invalid_output\",\n message: \"The model finished without giving a structured answer.\",\n retryable: true,\n };\n } else {\n const parsed = parseOutput(params.output, outputText);\n if (parsed.ok === true) {\n answered = true;\n output = parsed.value as Infer<O>;\n } else {\n error = parsed.error;\n }\n }\n }\n\n if (answered) {\n reply.content.push({ type: \"output\", value: output });\n } else if (outputText) {\n // The answer that failed, as the model wrote it. A retry continues this\n // transcript, and \"your output did not parse\" means little to a model that\n // cannot see what it wrote. Text rather than an `output` part because it is\n // not a value of the schema — an `output` part promises one.\n appendText(reply, \"text\", outputText);\n }\n for (const part of reply.content) {\n if ((part.type === \"text\" || part.type === \"reasoning\") && typeof part.text === \"string\") {\n part.text = resolveRope(part.text);\n }\n }\n reply.finishReason = reason;\n // One call, one message: the reply's usage is the call's, as an agent step's\n // message carries its own (#467).\n reply.usage = usage;\n messages.push(reply);\n\n if (answered) {\n return { ok: true, output: output as Infer<O>, messages, usage, finishReason: reason };\n }\n return { ok: false, error: { ...error!, ...detail }, messages, usage, finishReason: reason };\n}\n\nfunction abortError(signal: AbortSignal): AgentError {\n // `AbortSignal.timeout()` aborts with a `TimeoutError` (and so does a tool's\n // `timeoutMs`, through `ctx.signal`), and saying so is the difference\n // between \"somebody pressed stop\" and \"try again with more time\".\n const timedOut = (signal.reason as { name?: unknown } | undefined)?.name === \"TimeoutError\";\n // The same code an agent run's deadline and a tool's `timeoutMs` report\n // (#455), so one branch on `\"timeout\"` covers all three.\n return timedOut\n ? { code: \"timeout\", message: \"The generation timed out.\", retryable: true }\n : { code: \"aborted\", message: \"The generation was stopped.\", retryable: false };\n}\n\n/** What `generate` and `ctx.generate` are given. `messages` and `prompt` are\n * alternatives, and together the prompt is appended as the next user turn —\n * the same pair `ctx.runAgent` takes, so a retry reads the same in both. */\nexport interface GenerateParams<O extends Schema<any> = Schema<any>> {\n provider: AgentProvider;\n /**\n * The answer's shape, and the type of `output`. Required: a call without one\n * is a chat completion, which is not what this is.\n *\n * `strict` is read off the schema, as it is for an agent — a schema holding\n * an `s.json()` node is sent non-strict, since strict mode cannot express it.\n */\n output: O;\n /** The system prompt. */\n instructions?: string;\n /** Prior turns. Returned again at the front of `messages`, untouched. */\n messages?: AgentMessage[];\n /** Sugar for one more user turn, appended after `messages`. */\n prompt?: string;\n /** Dropped by a provider whose model cannot reason, as for an agent. */\n reasoning?: ReasoningEffort;\n /**\n * The provider's `max_output_tokens`. An answer that reaches it is cut off,\n * and comes back `ok: false` with `finishReason: \"length\"` — never as a\n * repaired half that happens to pass the schema.\n */\n maxOutputTokens?: number;\n /** Sent whenever set; a reasoning model that rejects it answers 400. See\n * `CreateAgentParams.temperature`. */\n temperature?: number;\n /**\n * Stops the call; it then resolves `ok: false` with `code: \"aborted\"`, or\n * `code: \"timeout\"` when it aborted with a `TimeoutError`.\n * `AbortSignal.timeout(ms)` is how to bound one.\n *\n * On `ctx.generate` this is combined with the turn's signal rather than\n * replacing it, so a timeout of the tool's own cannot unhook a `stop()`.\n */\n signal?: AbortSignal;\n /**\n * Reject with an `AgentRunError` instead of resolving `ok: false`, as\n * `run.result({ throwOnError: true })` does for an agent. Its `result` holds\n * the `messages`, `usage` and `error`, and its `runId` is the call's\n * `gen_` id. Any `ok: false` rejects, a stop included, since there is no\n * output to resolve with; the return type is then the `ok: true` arm.\n * Default `false`.\n */\n throwOnError?: boolean;\n /**\n * Write a failed call to the app's log (`Log.error`), as a failed agent run\n * is. Default `true`. A stop (`code: \"aborted\"`) is not a failure and is not\n * logged. Turn it off when the caller reports `result.error` itself — a\n * retry loop that expects `invalid_output` now and then, say.\n */\n logErrors?: boolean;\n}\n\n/** The parts of a `GenerateResult` both arms have. */\ninterface GenerateOutcome {\n /**\n * The whole transcript: `messages` as given, the `prompt` as a user turn,\n * then the model's reply. On success the reply holds the value as an\n * `output` part; on a bad answer, the raw text the model wrote — so a retry\n * passes this straight back with a new `prompt` saying what was wrong.\n */\n messages: AgentMessage[];\n /** What the call cost, including when it failed — the tokens were billed. */\n usage: Usage;\n /** How the model call ended: `\"stop\"` on success, `\"length\"` for a cut-off\n * answer, `\"error\"` or `\"aborted\"` when it did not finish. */\n finishReason: FinishReason;\n}\n\n/**\n * Discriminated on `ok`. `output` and `error` are each declared on both arms —\n * as `undefined` on the one where they cannot be — so that destructuring\n * `{ ok, output, error }` compiles, and checking `ok` narrows both.\n */\nexport type GenerateResult<O> =\n | GenerateSuccess<O>\n | (GenerateOutcome & {\n ok: false;\n /** The `AgentError`, plus the provider's HTTP `status` and `requestId`\n * when the failure was a response from it — as on an agent run's\n * `result().error`. */\n error: AgentRunFailure;\n output?: undefined;\n });\n\n/** The `ok: true` arm of `GenerateResult`, and what `throwOnError` resolves. */\nexport type GenerateSuccess<O> = GenerateOutcome & { ok: true; output: O; error?: undefined };\n",
|
|
8
|
-
"import { ToolError } from \"../redact\";\nimport type {\n PutFileParams,\n ReadFileParams,\n ReadResult,\n} from \"../../services/file-storage/drivers/types\";\nimport type { Usage } from \"../types\";\n\n/**\n * The bytes of an upload, kept by gemi, and the scope that says whose they are.\n *\n * WHY THIS EXISTS. `AgentController.upload` used to hand the file straight to\n * the model provider and keep nothing, which is the trade `AgentProvider.upload`\n * documents — provider file ids in the history, no storage story. That is a fine\n * trade for vision and it fails the moment a *tool* needs the file: the user\n * uploads an image and asks the agent to create a product, `POST /products`\n * wants multipart bytes, and the server is holding a provider file id and\n * nothing else. The model cannot make up the difference — it *saw* the image, it\n * cannot reproduce it — and the only recovery left is downloading from the\n * vendor, which is a round trip for bytes we held minutes ago, is not declared\n * anywhere (`AgentProvider` has `upload` and no counterpart), and is subject to\n * a retention policy that is not ours.\n *\n * WHY THE SCOPE IS NOT OPTIONAL. Once a tool takes an attachment id as an\n * argument, that id arrives *from the model*, and a model's arguments are as\n * untrusted as a request body: whatever the model wrote is a function of what it\n * read, and it reads the user's text, tool output, and any document it was\n * shown. A store that resolves ids globally therefore lets a prompt-injected\n * model name another tenant's upload and have the server fetch it — the model as\n * confused deputy, spending the server's own credentials.\n *\n * So there is no `find(id)` on this interface, only `find(scope, id)`, and the\n * thing a tool is handed is a `ScopedAttachments` whose methods take no scope at\n * all because it already closed over one. The unscoped read is not discouraged,\n * it is unspellable: the tool has no object to call it on. The scope itself is\n * derived from the server's own knowledge of the request — see\n * `AgentController.attachmentScope` — and never from anything the model can\n * write.\n */\n\n/**\n * The subject an attachment belongs to, as one opaque string.\n *\n * ONE STRING, COMPARED WITH `===`, RATHER THAN A STRUCTURE OF user/thread/org\n * fields. gemi does not have an opinion about tenancy — there is no `Org` in\n * this framework — so a structured scope would have had to be a bag of optional\n * fields, and a bag of optional fields has a worst member: `{}`, which under any\n * partial-match rule matches everything. Every such rule admits `{}` — or\n * `{ userId: undefined }`, which is the same thing arrived at by a typo — so one\n * forgetful line in an app turns the scope check into a no-op that still\n * typechecks. An opaque key has no such member: an app that wants org isolation\n * writes `org:${org.id}` and gets it, and an app that decides a request has no\n * subject returns `null` from `attachmentScope()` and gets no attachment ids at\n * all, rather than a bucket everyone shares.\n *\n * It is an object rather than a bare `string` for one reason, and it is a real\n * one: `find(scope, id)` taking two bare strings is a signature whose arguments\n * can be transposed, and the transposition typechecks, runs, and is a scope\n * check comparing an id against an id. The wrapper makes that a compile error.\n *\n * The key is never shown to the model and never sent to the client. It is a\n * server-side comparison value; it is not a path component and is not parsed.\n */\nexport type AttachmentScope = { readonly key: string };\n\n/**\n * Where an upload's bytes were sent. See `AgentController.attachmentDestination`.\n *\n * `\"provider\"` DESCRIBES A RECORD `upload` NEVER WRITES. A file that goes to the\n * provider alone leaves gemi holding nothing to resolve — `read` and `file`\n * would throw for it — so the route answers `fileId` and mints no attachment id\n * at all, and there is no id for anyone to look up its name with. The value is\n * on this type because a store *can* hold such a row (a custom `AttachmentStore`\n * filing provider uploads for its own bookkeeping is a reasonable thing to\n * write, and `ScopedAttachments` handles it correctly), not because the shipped\n * route produces one.\n */\nexport type AttachmentDestination = \"both\" | \"provider\" | \"storage\";\n\n/**\n * One recorded upload.\n *\n * `fileId` and `objectName` are both optional and at least one is always\n * present, because which of them exists is exactly the destination decision:\n * `provider` has a `fileId` and no bytes of ours, `storage` has bytes and no\n * `fileId`, `both` has both.\n */\nexport type Attachment = {\n /**\n * gemi's id for the upload — the one a tool takes as an argument, and the only\n * id in this module that may be shown to a model.\n *\n * Prefixed `gemi_att_` so that the mistake everyone makes once — a gemi\n * attachment id put into `FilePart.fileId`, which is a *provider* id — is\n * caught by a sentence to read rather than by whatever the vendor says about\n * a file it has never heard of, mid-conversation. `toResponsesInput` checks\n * for the prefix; the vendor's own answer to a bogus `file_id` has not been\n * measured, and the guard does not depend on it.\n */\n id: string;\n /**\n * The scope this was filed under, carried on the record so `ScopedAttachments`\n * can check it a second time. See `ScopedAttachments.get` for why the second\n * check is not redundant.\n */\n scopeKey: string;\n /** The provider file id, when the file was sent to the provider. */\n fileId?: string;\n /** The storage object name, when the bytes were kept. Feed it to `read`. */\n objectName?: string;\n /** The client's filename, kept so a tool can forward the file under it. */\n name: string;\n mimeType: string;\n size: number;\n createdAt: string;\n destination: AttachmentDestination;\n};\n\n/**\n * Where attachment *records* live. The bytes are in `AttachmentStorage`; this\n * holds the row that says which bytes, whose, and under what id.\n *\n * The default is `MemoryAttachmentStore`, which dies with the process, exactly\n * like `MemoryAgentStore`. An app that wants an attachment to outlive a deploy\n * implements this over a table — `id` primary key, `scope_key` column — and\n * assigns it to `AgentController.attachments`.\n *\n * IF YOU IMPLEMENT THIS, THE ONE THING YOU MUST NOT DO is answer `find` from the\n * id alone. `SELECT * FROM attachments WHERE id = ?` is the leak this module\n * exists to prevent, and it passes every test an app writes about its own\n * uploads, because those uploads are always in scope. It is wrong only for an id\n * that came from somewhere else, which is to say only when it matters. The\n * clause is `WHERE id = ? AND scope_key = ?`.\n */\nexport interface AttachmentStore {\n /** Records an attachment under `scope`. The caller has already minted the id. */\n put(scope: AttachmentScope, attachment: Attachment): Promise<void>;\n /**\n * The attachment with this id *within this scope*, or `null`.\n *\n * `null` for an id that does not exist and `null` for an id that exists under\n * another scope, and the caller cannot tell which — deliberately. See\n * `AttachmentNotFoundError`.\n */\n find(scope: AttachmentScope, id: string): Promise<Attachment | null>;\n}\n\n/**\n * The bytes half: whatever the app's file storage is.\n *\n * Structurally satisfied by the `Storage` facade, which is what\n * `AgentController` defaults to. Declared as an interface of two methods rather\n * than as `typeof Storage` so a test — or an app with a second bucket for user\n * uploads — can pass something else without standing up a container.\n */\nexport interface AttachmentStorage {\n put(params: PutFileParams | Blob): Promise<string>;\n read(params: ReadFileParams | string): Promise<ReadResult>;\n}\n\n/**\n * What both a missing id and someone else's id answer.\n *\n * THE MESSAGE MUST NOT SAY WHICH. \"Exists but is not yours\" and \"does not exist\"\n * are two answers to a question the caller is not entitled to ask, and a store\n * that distinguishes them is an oracle: a prompt-injected model that can tell\n * the two apart can walk an id space and report back which ids are live, which\n * is a tenant census delivered through the very tool the injection was aimed at.\n * One error, one wording, one code, for both.\n *\n * A `ToolError` rather than a `RequestBreakerError`: this is thrown inside a\n * tool, where the agent loop turns a throw into a tool result the model reads\n * and can recover from, not inside a route where it would decide a status code.\n * A `ToolError` so the model and the client are shown its message (#446).\n */\nexport class AttachmentNotFoundError extends ToolError {\n readonly code = \"attachment_not_found\";\n constructor(public readonly id: string) {\n super(`No attachment ${id}.`);\n this.name = \"AttachmentNotFoundError\";\n }\n}\n\n/** Raised for a scope no caller could have meant. See `assertScope`. */\nexport class InvalidAttachmentScopeError extends ToolError {\n readonly code = \"invalid_attachment_scope\";\n constructor(message: string) {\n super(message);\n this.name = \"InvalidAttachmentScopeError\";\n }\n}\n\n/**\n * Rejects the empty scope.\n *\n * `{ key: \"\" }` is what an app produces by writing `` `org:${org?.id ?? \"\"}` ``\n * for a request that has no org, and it is the one value that must never reach a\n * store: it compares equal to itself, so every subject-less upload in the\n * process lands in one shared bucket that every subject-less caller can read out\n * of. That is the global store this module exists not to be, arrived at by a\n * template literal. Failing here is loud, happens on the first request, and\n * names the method to fix.\n */\nfunction assertScope(scope: AttachmentScope): AttachmentScope {\n if (!scope || typeof scope.key !== \"string\" || scope.key.length === 0) {\n throw new InvalidAttachmentScopeError(\n \"An attachment scope needs a non-empty key. Return `null` from `attachmentScope()` for a request that has no subject — an empty key is a bucket every caller shares.\",\n );\n }\n return scope;\n}\n\n/** The prefix on every gemi attachment id. See `Attachment.id`. */\nexport const ATTACHMENT_ID_PREFIX = \"gemi_att_\";\n\nexport function newAttachmentId(): string {\n return `${ATTACHMENT_ID_PREFIX}${crypto.randomUUID()}`;\n}\n\n/**\n * The handle a tool is given, and the only attachment API a tool should ever\n * see.\n *\n * IT TAKES NO SCOPE, ON ANY METHOD. That is the whole design, and it is not a\n * convenience: an API where the scope is a parameter is an API where the scope\n * is a parameter someone passes the wrong thing to — and the wrong thing here is\n * whatever the model wrote, because inside a tool body the model's arguments are\n * the variables closest to hand. Handing the tool an object that has already\n * closed over the server's answer leaves nothing to pass. `resolve(id, scope)`\n * was the rejected shape: it is the same code with the mistake still available.\n */\nexport class ScopedAttachments {\n constructor(\n private readonly store: AttachmentStore,\n private readonly storage: AttachmentStorage,\n private readonly scope: AttachmentScope,\n ) {\n assertScope(scope);\n }\n\n /**\n * The scope's key. Read by `ctx.jobs.start` (#461), which records it on the\n * job so a background job gets the same attachments its tool had. Only the\n * key leaves: it is the server's answer, not something a tool can set.\n */\n get scopeKey(): string {\n return this.scope.key;\n }\n\n /**\n * The record for `id`, or `AttachmentNotFoundError`.\n *\n * THE SCOPE IS CHECKED TWICE HERE, and the second check is the one that\n * matters. `store.find` is an app's code — a table lookup somebody wrote, with\n * a `WHERE` clause somebody has to have remembered — and the failure mode of\n * forgetting the scope clause is a query that works perfectly for every upload\n * the app's own tests make. Comparing `record.scopeKey` again is three lines\n * that hold even when that clause is missing, so a careless store finds nothing\n * across scopes instead of leaking.\n *\n * It is not defence against a *malicious* store — an app's store is the app's\n * own code and could return anything. It is defence against the ordinary\n * version of this bug, which is the one that ships.\n */\n async get(id: string): Promise<Attachment> {\n const record = await this.store.find(this.scope, id);\n if (!record || record.scopeKey !== this.scope.key) {\n throw new AttachmentNotFoundError(id);\n }\n return record;\n }\n\n /**\n * The bytes, streaming, with the metadata `createStreamResponse` wants.\n *\n * Throws `AttachmentNotFoundError` for an attachment that exists but whose\n * bytes were never kept — a `provider`-destination upload. The same error as\n * an unknown id, for the reason on that class: \"it is at the vendor and not\n * here\" is information about someone else's upload as readily as about your\n * own.\n */\n async read(id: string): Promise<ReadResult> {\n return await this.readRecord(id, await this.get(id));\n }\n\n /**\n * The bytes for a record already resolved, so `file()` does one lookup rather\n * than two. `store.find` is a `SELECT` in any real store, and the second one\n * was not a second check of anything — same scope, same id, same row.\n *\n * It still takes the id the *caller* asked for, rather than reading\n * `record.id`, so the error stays a function of the caller's own input: an app\n * store that answers with the wrong row must not get to choose which id\n * appears in a message the model may read.\n */\n private async readRecord(id: string, record: Attachment): Promise<ReadResult> {\n if (!record.objectName) {\n throw new AttachmentNotFoundError(id);\n }\n return await this.storage.read({ name: record.objectName });\n }\n\n /**\n * The bytes as a `File`, under the name and type they were uploaded with —\n * which is the shape the motivating case actually needs, because\n * `form.append(\"image\", file)` is what a tool forwarding an upload to a\n * multipart endpoint writes.\n *\n * Buffers, and says so. `read()` is there for anything large enough that\n * buffering it is the wrong call.\n *\n * THIS IS ALSO HOW AN ATTACHMENT OUTLIVES THE RUN, and it is `file()` rather\n * than `read()` that composes for it:\n *\n * const file = await ctx.attachments.file(id);\n * await Storage.put({ name: `pages/${pageId}/hero.png`, body: file });\n *\n * `read()` answers a `ReadResult` whose `body` is `ReadableStream | Blob |\n * null`, and `PutFileParams.body` is `Blob | File | Buffer` — a stream body\n * has nowhere to go without being drained first.\n *\n * Two things that bite on the way out, both silent:\n *\n * - **Do not keep a `gemi_att_` id as an app's durable handle to a file.**\n * The default record store is `MemoryAttachmentStore`, so the id→object\n * mapping dies with the process while the bytes stay in storage. Copy the\n * file under a key of the app's own and keep that.\n * - **Put an extension on that key.** `FileSystemDriver` — the default —\n * ignores `contentType` on write and re-derives the type from the stored\n * path on read, so an extensionless object serves as\n * `application/octet-stream` and an `<img>` pointed at it renders nothing,\n * with no error anywhere. `attachmentObjectName` carries one over for this\n * module's own writes; an app's key is the app's to name.\n */\n async file(id: string): Promise<File> {\n const record = await this.get(id);\n const result = await this.readRecord(id, record);\n const body = result.body;\n const blob =\n body instanceof Blob ? body : body ? await new Response(body).blob() : new Blob([]);\n return new File([blob], record.name, { type: record.mimeType });\n }\n\n /**\n * Stores bytes a tool produced, under this caller's scope, and answers the\n * record.\n *\n * Here rather than on the store because the id, the object name and the scope\n * all have to be decided together, and because an attachment a tool created\n * has to land in the scope the tool is reading from — otherwise a tool writes\n * a file the next tool of the same run cannot see.\n *\n * Nothing is sent to the provider: bytes a tool made are bytes for the app,\n * and a tool that wants the model to look at its output says so by returning\n * something the model can read. Issue #490 builds `ctx.attachments.put(blob)`\n * on exactly this.\n */\n async put(\n blob: Blob,\n params: { name?: string; mimeType?: string; fileId?: string } = {},\n ): Promise<Attachment> {\n const id = newAttachmentId();\n const mimeType = params.mimeType ?? blob.type ?? \"\";\n const name = params.name ?? (blob instanceof File ? blob.name : id);\n const objectName = await this.storage.put({\n name: attachmentObjectName(id, name),\n body: blob,\n contentType: mimeType || undefined,\n });\n const record: Attachment = {\n id,\n scopeKey: this.scope.key,\n objectName,\n name,\n mimeType: mimeType || \"application/octet-stream\",\n size: blob.size,\n createdAt: new Date().toISOString(),\n // `both` when the caller has already sent the same bytes to the provider,\n // which is what `ctx.attachments.put(blob, { showModel: true })` does\n // before it gets here.\n //\n // The parameter exists rather than a second `markShown` call because the\n // alternative is a row that is briefly, and then permanently if the second\n // write fails, a lie: `destination` is the field that says where the bytes\n // went, and a file sitting in the vendor's file list under a record that\n // says `storage` is exactly the discrepancy the field was added to close.\n // Nothing here uploads — the provider is the run's, not this module's —\n // so the id is passed in rather than produced.\n destination: params.fileId ? \"both\" : \"storage\",\n ...(params.fileId ? { fileId: params.fileId } : {}),\n };\n await this.store.put(this.scope, record);\n return record;\n }\n}\n\n/**\n * What a tool asks for when it parks bytes.\n *\n * `showModel` is the whole of issue #490 in one flag: without it a tool's\n * output is an id in a string, which the model can quote back and cannot look\n * at, so \"edit this image\" produces a file nobody but the app ever sees. With\n * it the same bytes also go to the provider and come back into the transcript\n * as an input-role message the next step is built on — generate, look, fix.\n *\n * It is a flag rather than the default because the default costs money on every\n * call. The reasoning is `capabilitiesForModel`'s, run the other way round: a\n * file the model did not need and was shown anyway is an upload plus a set of\n * image tokens on every subsequent request of the run, on an invoice, for a\n * tool whose author never asked to be looked at. A file the model needed and\n * was not shown is a tool that returned an id, which is what tools did before\n * this existed and is visible in the transcript the moment anyone reads it. The\n * expensive mistake is the silent one here, so the expensive thing is opt in.\n */\nexport type PutAttachmentParams = {\n /** The filename to keep, so a later `file()` hands the bytes back under it. */\n name?: string;\n /** Overrides `blob.type`, which a `Blob` built from raw bytes does not have. */\n mimeType?: string;\n /**\n * Also send these bytes to the model provider and put them in front of the\n * model as an input-role message, once this tool call settles.\n *\n * Refused, loudly, by a provider whose `capabilities.fileInput` is false: the\n * request builder drops a file part such a provider cannot read, and an\n * upload paid for, stored, and then dropped on the way to the wire is the\n * silent-forever failure — the tool reports success, the model answers about\n * an image it was never shown, and nothing anywhere says why.\n */\n showModel?: boolean;\n};\n\n/**\n * The attachment API a tool is given, as `ctx.attachments`.\n *\n * Everything a `ScopedAttachments` does, plus `showModel`, plus the memo that\n * makes a re-entered tool call idempotent. It is a separate interface from\n * `ScopedAttachments` because those two additions are not properties of the\n * scope, they are properties of *one tool call*: the run has to know which call\n * a `put` belongs to in order to replay it, and the object handed to a tool is\n * therefore built per call — the same shape `ctx.runAgent` has, for the same\n * reason.\n *\n * The read half (`get`, `read`, `file`) is delegated to the `ScopedAttachments`\n * unchanged, including its two scope checks. A tool reading a file it did not\n * create is reading an id the model wrote, and #489's whole argument applies to\n * it word for word.\n */\nexport interface ToolAttachments {\n /**\n * Parks bytes under this caller's scope and answers the record.\n *\n * ON A REPLAY THIS STORES NOTHING. An escalating tool is re-entered from the\n * top on the next turn, so the body that built this blob has run before and\n * built one already; the record from that first attempt is what comes back,\n * and the bytes handed in now are dropped. That is the same bargain\n * `ctx.runAgent` makes and it is not avoidable: the id from the first attempt\n * is already in the transcript the model read, so minting a second one would\n * leave the model holding an id for bytes nobody kept — and uploading the\n * second copy would pay the vendor twice and put the same image into the\n * context twice. Work *before* a `put` still runs again; if producing the\n * bytes is what costs, branch on `ctx.resumed`.\n */\n put(blob: Blob, params?: PutAttachmentParams): Promise<Attachment>;\n /** The record for `id`, or `AttachmentNotFoundError`. Scoped. */\n get(id: string): Promise<Attachment>;\n /** The bytes, streaming. Scoped. */\n read(id: string): Promise<ReadResult>;\n /** The bytes as a `File`, under their original name and type. Scoped. */\n file(id: string): Promise<File>;\n}\n\n/**\n * One successful `ctx.attachments.put` of one tool call, written down so the\n * next turn can replay it instead of doing it again.\n *\n * Lives on `ToolCallPart.attachments`, indexed by the order the puts happened\n * in — exactly where and how `ToolCallPart.nested` records sub-runs, and for\n * exactly the same reason: the message history is the only state that survives\n * a turn boundary, in a thread and in the browser both, so a memo that is not\n * on the message is a memo a stateless app does not have.\n *\n * `shown` is absent for a plain `put`. When present it carries the provider\n * file id AND the identity of the message injected for it, because both have to\n * come back byte for byte: a replay that minted a fresh message id would put a\n * second copy of the same image in the transcript, and a client that had\n * already applied the first would show it twice.\n */\nexport type ToolAttachmentPut = {\n /** What `put` answered, replayed verbatim. */\n attachment: Attachment;\n /**\n * Set when this slot was filled by `ctx.generateImage` / `ctx.editImage`\n * rather than a plain `put`, carrying what the render reported and the\n * attachment record cannot.\n *\n * WHY THE RENDER IS MEMOIZED AT ALL, and why it is memoized *here*. An\n * escalating tool is re-entered from the top on the next turn, so a render\n * that is not written down is paid for again — and unlike a `put`, the thing\n * being repeated costs money at the vendor and about two minutes of wall\n * clock. The memo cannot hold the image: this record lives in the message\n * history, which goes over the wire and into a store on every turn, and a\n * megabyte of base64 per generated image would go with it. So what is\n * recorded is the attachment id, and the bytes live in storage where they\n * were going anyway.\n *\n * That is the whole reason `ctx.generateImage` answers an `Attachment`\n * instead of a `Blob` while `ImageModel.generate` answers the bytes: outside\n * a run there is nothing to replay and nowhere to park, and inside one there\n * has to be both.\n *\n * `size` is the pixel dimensions the model actually produced — read off the\n * response, which does not always echo the request — and is not derivable\n * from `Attachment.size`, which is a byte count.\n */\n generated?: {\n size: string;\n usage: Usage;\n };\n /** Set when `showModel` was asked for. See above. */\n shown?: {\n /** The provider's file id — what the injected `FilePart` carries. */\n fileId: string;\n /** The injected message's id, so a replay reproduces it rather than a twin. */\n messageId: string;\n /** Its `createdAt`, for the same reason. */\n createdAt: string;\n };\n};\n\n/**\n * A slot in that list, which is one `put` — or one `put` that threw.\n *\n * The failure arm exists because the index is what identifies a `put`, and an\n * index is taken the moment the call is made rather than when it succeeds: a\n * body that runs its puts concurrently must number them by the order it *asked*\n * and not by the order the network answered, or the next turn will not\n * reproduce the numbering. So a `put` that throws and is caught — a provider\n * that cannot read files, a vendor that refuses the type, a storage write that\n * fails — leaves a slot behind, and a later successful `put` in the same call\n * would otherwise leave a hole in front of it. A hole is `null` once it has\n * been through JSON, which is what a consumer walking `part.attachments`\n * crashes on; `{ failed: true }` is the same fact said out loud.\n *\n * It is written lazily, only when a later `put` needs the index above it, so a\n * tool whose puts all threw still adds no `attachments` field at all. And it is\n * not a memo: a replayed slot marked `failed` is re-attempted from scratch,\n * because there is nothing recorded to hand back and the failure may have been\n * the network's rather than the tool's.\n */\nexport type ToolAttachmentRecord = ToolAttachmentPut | { failed: true };\n\n/**\n * The object name an attachment's bytes are stored under.\n *\n * The scope is deliberately NOT in the path. A scope key is app-authored text —\n * `org:${slug}`, with whatever a slug turns out to be — and putting arbitrary\n * app text into an object name is how a `..` or a `/` ends up somewhere nobody\n * meant on the one driver that resolves names literally (`FileSystemDriver`\n * concatenates them onto a folder path). The record is what carries the scope;\n * the object name only has to be unique, and a uuid already is.\n *\n * The extension is carried over from the client's filename when it looks like\n * one, because `FileSystemDriver` reads a stored object's content type back off\n * its path and would otherwise answer `application/octet-stream` for everything.\n * `Attachment.mimeType` is the authority either way — this is for anything that\n * reads the bucket without the record.\n */\nexport function attachmentObjectName(id: string, name: string): string {\n const match = /\\.([A-Za-z0-9]{1,8})$/.exec(name);\n return `attachments/${id}${match ? `.${match[1]!.toLowerCase()}` : \"\"}`;\n}\n\n/**\n * The default: attachment records last as long as the process.\n *\n * Modelled as one flat map keyed by id, holding the scope beside the record and\n * comparing it in `find` — rather than as a map of maps, which would make the\n * scoping structural and unforgettable. That looks like the safer shape and is\n * the wrong reference implementation: an app's store is a table with an `id`\n * primary key and a `scope_key` column, and its `find` is a `WHERE` clause that\n * can be written wrong. The store gemi ships should have the same failure\n * available to it as the store an app writes, so that a test written against\n * this one is a test of the check every real store also has to make.\n */\nexport class MemoryAttachmentStore implements AttachmentStore {\n private readonly rows = new Map<string, Attachment>();\n\n async put(scope: AttachmentScope, attachment: Attachment): Promise<void> {\n assertScope(scope);\n this.rows.set(attachment.id, { ...attachment, scopeKey: scope.key });\n }\n\n async find(scope: AttachmentScope, id: string): Promise<Attachment | null> {\n assertScope(scope);\n const row = this.rows.get(id);\n // The scope clause. An id belonging to another scope answers `null`, which\n // is the answer an id that does not exist gets — see\n // `AttachmentNotFoundError` for why the two must be indistinguishable.\n if (!row || row.scopeKey !== scope.key) {\n return null;\n }\n return row;\n }\n\n /** Test and dev affordance: how many rows are held, across every scope. */\n get size(): number {\n return this.rows.size;\n }\n}\n\n/**\n * The process-wide default, so an app that configures nothing still gets\n * attachment ids that work for the length of a conversation.\n *\n * Module-level for the reason `defaultAgentStore` is: the controller is\n * constructed per request, so a store assigned as `new MemoryAttachmentStore()`\n * in a field initializer is an empty store on every request, and every\n * attachment id is a miss one turn after it was minted.\n */\nexport const defaultAttachmentStore = new MemoryAttachmentStore();\n",
|
|
9
|
-
"import type { AgentError, Usage } from \"../types\";\n\n/**\n * Where a background job stands (#461).\n *\n * `running` until something settles it; `ok` and `error` are final. A job\n * moves out of `running` once, by compare-and-set (`AgentJobStore.transition`),\n * so a queue worker, a provider's webhook, a poller and the deadline sweep can\n * all race to settle the same job and exactly one of them wins.\n */\nexport type AgentJobState = \"running\" | \"ok\" | \"error\";\n\n/**\n * One background job, as the job store keeps it.\n *\n * The record is the job's state, and it is NOT the tool result. The tool\n * result in the thread says `running` and points here by `id`; the controller\n * renders the record's current state over it whenever it loads the thread (see\n * `overlayJobs`). The record is kept apart from the messages because a live\n * run writes whole messages to the store, and a job settling during that run\n * would race those writes and lose.\n */\nexport type AgentJobRecord = {\n /** `ajob_…`. Handed to the app (`JobHandle.id`) to settle a tracked job. */\n id: string;\n threadId: string;\n /** The run whose tool started the job. */\n runId: string;\n /** The tool call whose result this job settles. */\n toolCallId: string;\n toolName: string;\n /** The `runOwner` of the run that started it, or `null` for an anonymous run. */\n owner: string | null;\n /** The `AgentJob` class's queue name, or `null` for a job made with `track`. */\n job: string | null;\n /**\n * What the tool said about the job when it started it: what the model and\n * the UI see while it runs. Server-owned, and kept small by the tool.\n */\n summary?: unknown;\n state: AgentJobState;\n /** The settled output, on `ok`. */\n output?: unknown;\n /** Why it failed, on `error`. Already redacted: this is what the model reads. */\n error?: AgentError;\n /** What the job spent on model and image calls. Counted on the turn that started it. */\n usage?: Usage;\n /**\n * Set when the job's tool result never reached the thread: the run died\n * after the job started and before the result was stored. The job still\n * runs and settles; nothing in the thread shows it.\n */\n orphaned?: true;\n /**\n * The attachment scope key of the run that started the job, so the job's\n * `attachments` are the ones the tool would have had. `null` when the run\n * had none.\n */\n attachmentScope: string | null;\n /** Epoch milliseconds, on the store's clock. */\n createdAt: number;\n updatedAt: number;\n /** When the deadline sweep fails the job if it is still running. */\n deadlineAt: number;\n settledAt?: number;\n};\n\n/** What `create` is given: the record minus what the store stamps. */\nexport type NewAgentJobRecord = Omit<\n AgentJobRecord,\n \"state\" | \"createdAt\" | \"updatedAt\" | \"deadlineAt\" | \"settledAt\"\n> & {\n /** How long from now the job may run, in milliseconds. */\n deadlineMs: number;\n};\n\n/** The fields a transition may write. `id`, the thread and the call never change. */\nexport type AgentJobUpdate = Partial<\n Pick<AgentJobRecord, \"state\" | \"output\" | \"error\" | \"usage\" | \"orphaned\" | \"settledAt\">\n>;\n\n/**\n * Where background jobs live.\n *\n * `MemoryAgentJobStore` is the default and is not durable. `DatabaseAgentJobStore`\n * keeps them in a table. An app that already has a jobs table can implement\n * this over it.\n */\nexport interface AgentJobStore {\n /** Writes a new `running` record and returns it as stored. */\n create(job: NewAgentJobRecord): Promise<AgentJobRecord>;\n get(id: string): Promise<AgentJobRecord | null>;\n /**\n * A thread's jobs, newest first. `states` filters, `limit` bounds. Each\n * record is a copy the caller may keep.\n */\n listForThread(\n threadId: string,\n options?: { states?: AgentJobState[]; limit?: number },\n ): Promise<AgentJobRecord[]>;\n /**\n * Compare-and-set: applies `to` only when the job's state is one of `from`,\n * and answers whether it did. Bumps `updatedAt`, and stamps `settledAt` when\n * `to.state` moves the job out of `running`.\n */\n transition(id: string, from: AgentJobState[], to: AgentJobUpdate): Promise<boolean>;\n /** Running jobs whose `deadlineAt` is at or before `now`, oldest deadline first. */\n overdue(now: number, limit: number): Promise<AgentJobRecord[]>;\n /**\n * The store's clock, in epoch milliseconds. The deadline sweep compares\n * `deadlineAt` against this rather than the process's clock. Optional: a\n * store without one is compared against `Date.now()`.\n */\n now?(): Promise<number>;\n /**\n * Runs `fn` in a transaction, so `ctx.jobs.start` writes the record and\n * queues the job together: both or neither. Optional: without it the record\n * is written first, and a dispatch that fails then fails the record.\n */\n transaction?<T>(fn: () => Promise<T>): Promise<T>;\n}\n\n/** How many settled jobs the memory store keeps per thread before dropping the oldest. */\nconst MEMORY_SETTLED_PER_THREAD = 200;\n\n/**\n * Jobs in a map, for as long as the process lives.\n *\n * NOT DURABLE, like `MemoryAgentStore`: a restart loses every record, and a\n * job that was running is then lost too. The tool result that pointed at it\n * reads as a lost job on the next turn. It is the default so that jobs work in\n * development and tests without a table; use `DatabaseAgentJobStore` in\n * production.\n *\n * It only works when the queue runs the jobs in this same process (the memory\n * queue driver, or a database driver claiming here), since a worker in another\n * process has a map of its own.\n */\nexport class MemoryAgentJobStore implements AgentJobStore {\n private jobs = new Map<string, AgentJobRecord>();\n\n async create(job: NewAgentJobRecord): Promise<AgentJobRecord> {\n if (this.jobs.has(job.id)) {\n throw new Error(`A background job with the id ${job.id} already exists.`);\n }\n const now = Date.now();\n const { deadlineMs, ...fields } = job;\n const record: AgentJobRecord = {\n ...structuredClone(fields),\n state: \"running\",\n createdAt: now,\n updatedAt: now,\n deadlineAt: now + deadlineMs,\n };\n this.jobs.set(record.id, record);\n this.trim(record.threadId);\n return structuredClone(record);\n }\n\n async get(id: string): Promise<AgentJobRecord | null> {\n const record = this.jobs.get(id);\n return record ? structuredClone(record) : null;\n }\n\n async listForThread(\n threadId: string,\n options: { states?: AgentJobState[]; limit?: number } = {},\n ): Promise<AgentJobRecord[]> {\n const out: AgentJobRecord[] = [];\n for (const record of this.jobs.values()) {\n if (record.threadId !== threadId) continue;\n if (options.states && !options.states.includes(record.state)) continue;\n out.push(record);\n }\n out.sort(newestFirst);\n return (options.limit === undefined ? out : out.slice(0, options.limit)).map((record) =>\n structuredClone(record),\n );\n }\n\n async transition(id: string, from: AgentJobState[], to: AgentJobUpdate): Promise<boolean> {\n const record = this.jobs.get(id);\n if (!record || !from.includes(record.state)) return false;\n // Cloned in before anything is assigned, so an output that is not plain\n // data fails the transition rather than half-applying it.\n const update = structuredClone(to);\n const now = Date.now();\n Object.assign(record, update, { updatedAt: now });\n if (update.state && update.state !== \"running\" && record.settledAt === undefined) {\n record.settledAt = update.settledAt ?? now;\n }\n return true;\n }\n\n async overdue(now: number, limit: number): Promise<AgentJobRecord[]> {\n const out: AgentJobRecord[] = [];\n for (const record of this.jobs.values()) {\n if (record.state === \"running\" && record.deadlineAt <= now) out.push(record);\n }\n out.sort((a, b) => a.deadlineAt - b.deadlineAt);\n return out.slice(0, Math.max(0, limit)).map((record) => structuredClone(record));\n }\n\n async now(): Promise<number> {\n return Date.now();\n }\n\n /** Bounds a long-lived thread: running jobs are never dropped, settled ones oldest first. */\n private trim(threadId: string): void {\n const settled = [...this.jobs.values()]\n .filter((record) => record.threadId === threadId && record.state !== \"running\")\n .sort(newestFirst);\n for (const record of settled.slice(MEMORY_SETTLED_PER_THREAD)) this.jobs.delete(record.id);\n }\n}\n\n/** Newest first, with the id as a tie-break so the order is stable. */\nexport function newestFirst(a: AgentJobRecord, b: AgentJobRecord): number {\n return b.createdAt - a.createdAt || (a.id < b.id ? 1 : a.id > b.id ? -1 : 0);\n}\n",
|
|
10
|
-
"import { Storage } from \"../../facades/Storage\";\nimport { app } from \"../../foundation/app\";\nimport { Job } from \"../../services/queue/Job\";\nimport { QueueManager } from \"../../services/queue/QueueManager\";\nimport type { GeneratedAttachment, ToolGenerateImageParams, ToolEditImageParams } from \"../Agent\";\nimport { generateWithin, type GenerateParams, type GenerateResult } from \"../generate\";\nimport type { ImageInput, ImageModel } from \"../ImageModel\";\nimport { redactError, ToolError } from \"../redact\";\nimport { addUsage, emptyUsage } from \"../runtime\";\nimport type { Infer, Schema } from \"../Schema\";\nimport {\n type Attachment,\n type AttachmentStorage,\n type AttachmentStore,\n defaultAttachmentStore,\n InvalidAttachmentScopeError,\n ScopedAttachments,\n} from \"../store/Attachments\";\nimport type { AgentError, Usage } from \"../types\";\nimport {\n type AgentJobRecord,\n type AgentJobState,\n type AgentJobStore,\n MemoryAgentJobStore,\n} from \"./AgentJobStore\";\n\n// --- the handle a tool returns -------------------------------------------\n\nconst HANDLE = Symbol.for(\"gemi.ai.JobHandle\");\n\n/**\n * What `ctx.jobs.start` and `ctx.jobs.track` answer, and what a tool returns to\n * say \"this call goes on in the background\" (#461).\n *\n * Returning it is what makes the call's result `running` rather than `ok`: the\n * model reads that the job started and is told not to start it again, the turn\n * goes on and ends as usual, and when the job settles the controller renders\n * its outcome over that result the next time it loads the thread.\n *\n * `Output` is the job's settled output, and it is what the tool's output type\n * becomes, so a client's `ToolShapes` see the job's result as the tool's.\n */\nexport class JobHandle<Output = unknown> {\n /** Phantom: the settled output's type. Never set. */\n declare readonly $output: Output;\n readonly [HANDLE] = true as const;\n\n constructor(\n /** The job's id. Hand it to whatever settles a tracked job. */\n readonly id: string,\n readonly toolCallId: string,\n readonly summary: unknown,\n /** Epoch milliseconds, on the job store's clock. */\n readonly deadlineAt: number,\n ) {}\n}\n\n/** Whether a tool's return value is a `JobHandle`, across copies of the module. */\nexport function isJobHandle(value: unknown): value is JobHandle {\n return typeof value === \"object\" && value !== null && (value as any)[HANDLE] === true;\n}\n\n// --- errors ----------------------------------------------------------------\n\n/**\n * `ctx.jobs.start` or `track` from a run that has nowhere to settle a job\n * into: a stateless turn, a run started without a job store, or a sub-run.\n *\n * A `ToolError`, so the model reads why the tool could not go to the\n * background and can say so, rather than being told the tool broke.\n */\nexport class JobsRequireThreadError extends ToolError {\n readonly code = \"jobs_require_thread\" as const;\n\n constructor(message: string) {\n super(message, { retryable: false });\n this.name = \"JobsRequireThreadError\";\n }\n}\n\n// --- the process-wide registry ----------------------------------------------\n\nlet currentStore: AgentJobStore = new MemoryAgentJobStore();\n\n/** Every state, for a transition that does not change the state. */\nconst ANY_STATE: AgentJobState[] = [\"running\", \"ok\", \"error\"];\n\n/** What a job settles with. */\nexport type AgentJobOutcome =\n | { output: unknown; usage?: Usage }\n | { error: string | Error | (Pick<AgentError, \"message\"> & Partial<AgentError>); usage?: Usage };\n\n/**\n * Background jobs, from anywhere in the app: settle one, fail one, look one up.\n *\n * PROCESS-WIDE, and that is forced. A job is started by a tool inside a run,\n * and settled by a queue worker, a provider's webhook, a poller or the deadline\n * sweep, none of which has a controller to read a store from. So the store is\n * set once, at boot, for every one of them:\n *\n * AgentJobs.use(new DatabaseAgentJobStore(app(DatabaseManager).connection()));\n *\n * Until then it is a `MemoryAgentJobStore`, which works in one process and\n * forgets on restart.\n */\nexport const AgentJobs = {\n /** The store every part of the feature reads and writes. */\n get store(): AgentJobStore {\n return currentStore;\n },\n\n /** Sets the store. Call it once, at boot, in every process that starts or runs jobs. */\n use(store: AgentJobStore): void {\n currentStore = store;\n },\n\n get(id: string): Promise<AgentJobRecord | null> {\n return currentStore.get(id);\n },\n\n /**\n * Settles a running job with its output or its error, and answers whether\n * this call did it.\n *\n * COMPARE-AND-SET FROM `running`. The first settle wins and every later one\n * answers `false` and changes nothing, so a webhook, a poller and the\n * deadline sweep can all race on one job. A job the deadline sweep has\n * already failed stays failed: a late result is refused, so the model never\n * sees a job flip from failed to done.\n *\n * An error given as a `ToolError`, a string or an `AgentError`-like object is\n * shown to the model as it is. Any other `Error` is logged in full and the\n * model is told only that the job failed, as for a tool that throws (#446).\n */\n async settle(id: string, outcome: AgentJobOutcome): Promise<boolean> {\n return settleOn(currentStore, id, outcome);\n },\n\n /** `settle(id, { error })`. */\n async fail(id: string, error: string | Error | AgentError): Promise<boolean> {\n return settleOn(currentStore, id, { error });\n },\n\n /**\n * The deadline sweep: fails every running job whose deadline has passed\n * with code `\"timeout\"`, and answers how many it failed.\n *\n * Compare-and-set like every settle, so it is safe to run on every\n * instance at once, and a result that arrives after it is refused. Run it\n * every minute with `AgentJobDeadlineSweep`; the controller also checks a\n * thread's jobs when it loads the thread, so an app without cron still sees\n * overdue jobs fail, just later. The job's queue worker is not stopped: what\n * it returns afterwards is dropped.\n */\n async sweep(options: { limit?: number } = {}): Promise<number> {\n const store = currentStore;\n const limit = options.limit ?? 100;\n const now = await clockOf(store);\n let failed = 0;\n for (const record of await store.overdue(now, limit)) {\n if (await expire(store, record)) failed++;\n }\n return failed;\n },\n};\n\n/** The store's clock, or this process's for a store without one. */\nexport async function clockOf(store: AgentJobStore): Promise<number> {\n return store.now ? await store.now() : Date.now();\n}\n\n/** Fails a running job for its deadline. Compare-and-set: false when it had settled. */\nexport function expire(store: AgentJobStore, record: AgentJobRecord): Promise<boolean> {\n return store.transition(record.id, [\"running\"], {\n state: \"error\",\n error: {\n code: \"timeout\",\n message: `The background job for \"${record.toolName}\" did not finish before its deadline, so it was given up on. Its result, if it ever arrives, is ignored.`,\n toolCallId: record.toolCallId,\n retryable: true,\n },\n });\n}\n\nasync function settleOn(\n store: AgentJobStore,\n id: string,\n outcome: AgentJobOutcome,\n): Promise<boolean> {\n const record = await store.get(id);\n if (!record || record.state !== \"running\") return false;\n const usage = outcome.usage ? addUsage(record.usage ?? emptyUsage(), outcome.usage) : undefined;\n if (\"error\" in outcome) {\n return store.transition(id, [\"running\"], {\n state: \"error\",\n error: jobError(record, outcome.error),\n ...(usage ? { usage } : {}),\n });\n }\n return store.transition(id, [\"running\"], {\n state: \"ok\",\n output: plainData(outcome.output, record),\n ...(usage ? { usage } : {}),\n });\n}\n\n/** The error the model reads. See `AgentJobs.settle`. */\nfunction jobError(\n record: Pick<AgentJobRecord, \"toolCallId\" | \"toolName\" | \"job\">,\n error: AgentJobOutcome extends infer O ? (O extends { error: infer E } ? E : never) : never,\n): AgentError {\n if (typeof error === \"string\") {\n return { code: \"tool_error\", message: error, toolCallId: record.toolCallId, retryable: true };\n }\n if (error instanceof Error) {\n const raw: AgentError = {\n code: \"tool_error\",\n message: error.message,\n toolCallId: record.toolCallId,\n retryable: error instanceof ToolError ? error.retryable : true,\n };\n if (!(error instanceof ToolError)) {\n console.error(\n `The background job ${record.job ?? \"(tracked)\"} for \"${record.toolName}\" failed.`,\n error,\n );\n }\n return redactError(raw, { source: \"tool\", toolName: record.toolName, cause: error });\n }\n return {\n code: error.code ?? \"tool_error\",\n message: String(error.message),\n toolCallId: record.toolCallId,\n retryable: error.retryable ?? true,\n };\n}\n\n/** A copy of the output that any store can keep, or a throw that says why not. */\nfunction plainData(output: unknown, record: Pick<AgentJobRecord, \"toolName\">): unknown {\n if (output === undefined) return null;\n try {\n return JSON.parse(JSON.stringify(output));\n } catch (error) {\n throw new Error(\n `The output of the background job for \"${record.toolName}\" is not JSON: ${String(error)}`,\n );\n }\n}\n\n// --- the tool side ---------------------------------------------------------\n\n/** Options for `ctx.jobs.start` and `ctx.jobs.track`. */\nexport type StartJobOptions = {\n /**\n * What the model and the UI see while the job runs, in place of a result:\n * which images, which pages. Plain data, and keep it small, since it is in\n * the history on every later turn.\n */\n summary?: unknown;\n /**\n * How long the job may run, in milliseconds. Defaults to the tool's\n * `async.deadlineMs`, else an hour. A job still running then is failed with\n * code `\"timeout\"` by the deadline sweep, and a later result is refused.\n */\n deadlineMs?: number;\n};\n\n/** A tool's `ctx.jobs`. See `ToolContext.jobs`. */\nexport interface ToolJobs {\n /**\n * Records a background job for this tool call and queues `job` to do it.\n * Return the handle from `execute` to make the call's result `running`.\n *\n * At least once, like every queued job: `job.run` may run again after a\n * crash, so make it idempotent. Only on a threaded run (a turn with a\n * `threadId` through `AgentController`), and only from a top-level tool.\n */\n start<A, O>(job: AgentJobClass<A, O>, args: A, options?: StartJobOptions): Promise<JobHandle<O>>;\n /**\n * Records a background job that something else settles: a provider's\n * webhook, a poller. Pass `handle.id` to it, and call\n * `AgentJobs.settle(id, { output })` when the work is done.\n */\n track<O = unknown>(options?: StartJobOptions): Promise<JobHandle<O>>;\n}\n\n/** What a run that may start jobs is given. `AgentController` passes it on a threaded turn. */\nexport type RunJobs = {\n /** The run's owner (`runOwner`), recorded on each job. */\n owner: string | null;\n};\n\n/** The longest a job runs when nothing says otherwise. */\nexport const DEFAULT_JOB_DEADLINE_MS = 60 * 60_000;\n\n/** @internal `ctx.jobs` for one tool call. Built by the run, per call. */\nexport function toolJobs(params: {\n jobs: RunJobs | undefined;\n threadId: string | undefined;\n runId: string;\n toolCallId: string;\n toolName: string;\n depth: number;\n /** The tool's `async` declaration; `undefined` for a tool without one. */\n async: { deadlineMs?: number } | undefined;\n attachments: ScopedAttachments | null;\n}): ToolJobs {\n /** One job per tool call: the handle the first `start`/`track` answered. */\n let started: Promise<JobHandle<any>> | null = null;\n\n const begin = (\n job: (new () => AgentJob<any, any>) | null,\n args: unknown,\n options: StartJobOptions = {},\n ) => {\n if (params.async === undefined) {\n throw new ToolError(\n `\"${params.toolName}\" called ctx.jobs, but the tool does not declare \\`async\\`. Add \\`async: { deadlineMs }\\` to its definition.`,\n { retryable: false },\n );\n }\n if (!params.jobs || !params.threadId) {\n throw new JobsRequireThreadError(\n `\"${params.toolName}\" can only run in the background on a conversation the server keeps (a turn with a threadId), and this one has none.`,\n );\n }\n if (params.depth > 0) {\n throw new JobsRequireThreadError(\n `\"${params.toolName}\" can only run in the background from the top-level agent, not from a sub-agent.`,\n );\n }\n if (started) {\n throw new ToolError(\n `\"${params.toolName}\" started a background job already: a tool call has at most one.`,\n { retryable: false },\n );\n }\n const deadlineMs = options.deadlineMs ?? params.async.deadlineMs ?? DEFAULT_JOB_DEADLINE_MS;\n if (!Number.isFinite(deadlineMs) || deadlineMs <= 0) {\n throw new ToolError(`A job's deadlineMs must be a positive number; got ${deadlineMs}.`);\n }\n const jobs = params.jobs;\n const threadId = params.threadId;\n started = (async () => {\n const store = AgentJobs.store;\n // A tool re-entered after an escalation runs from the top again. The job\n // it started the first time is the one it gets.\n const existing = (await store.listForThread(threadId, { limit: 50 })).find(\n (record) => record.toolCallId === params.toolCallId,\n );\n if (existing) return handleOf(existing);\n\n const write = async () => {\n const record = await store.create({\n id: `ajob_${crypto.randomUUID()}`,\n threadId,\n runId: params.runId,\n toolCallId: params.toolCallId,\n toolName: params.toolName,\n owner: jobs.owner,\n job: job ? job.name : null,\n ...(options.summary !== undefined ? { summary: plainData(options.summary, params) } : {}),\n attachmentScope: params.attachments?.scopeKey ?? null,\n deadlineMs,\n });\n if (job) {\n try {\n await dispatchJob(job, { jobId: record.id, args });\n } catch (error) {\n // In a store transaction the record goes with the rollback.\n if (store.transaction) throw error;\n // Nothing will ever run it, so it is failed now rather than left to\n // reach its deadline, and the tool call reports the failure.\n await store\n .transition(record.id, [\"running\"], {\n state: \"error\",\n error: {\n code: \"tool_error\",\n message: `The background job for \"${params.toolName}\" could not be queued.`,\n toolCallId: params.toolCallId,\n retryable: true,\n },\n })\n .catch(() => {});\n throw error;\n }\n }\n return record;\n };\n // Both or neither when the store can: see `AgentJobStore.transaction`.\n const record = store.transaction ? await store.transaction(write) : await write();\n return handleOf(record);\n })();\n return started;\n };\n\n return {\n start: (job, args, options) => begin(job as new () => AgentJob<any, any>, args, options),\n track: (options) => begin(null, undefined, options),\n };\n}\n\nfunction handleOf(record: AgentJobRecord): JobHandle<any> {\n return new JobHandle(record.id, record.toolCallId, record.summary, record.deadlineAt);\n}\n\n/** What the queue carries for an `AgentJob`: the record's id and the job's own arguments. */\ntype JobEnvelope = { jobId: string; args: unknown };\n\nfunction dispatchJob(job: new () => AgentJob<any, any>, envelope: JobEnvelope): Promise<string> {\n if (job.name === \"unset\" || !job.name) {\n throw new Error(\"Cannot start an AgentJob with no `static name`.\");\n }\n return app(QueueManager).push(job, JSON.stringify([envelope]));\n}\n\n// --- the job side ------------------------------------------------------------\n\n/** An `AgentJob` subclass, as `ctx.jobs.start` takes it. */\nexport type AgentJobClass<A, O> = new () => AgentJob<A, O>;\n\n/** `generateImage`'s params inside a job: as in a tool, without `showModel` (there is no run to show). */\nexport type JobGenerateImageParams = Omit<ToolGenerateImageParams, \"showModel\">;\nexport type JobEditImageParams = Omit<ToolEditImageParams, \"showModel\">;\n\n/** Attachments inside a job: the scope of the run that started it. */\nexport interface JobAttachments {\n put(blob: Blob, params?: { name?: string; mimeType?: string }): Promise<Attachment>;\n get(id: string): Promise<Attachment>;\n read: ScopedAttachments[\"read\"];\n file(id: string): Promise<File>;\n}\n\n/**\n * What `AgentJob.run` is handed beside its arguments: the parts of a tool's\n * `ToolContext` that still mean something with no run around them.\n */\nexport interface AgentJobContext {\n /** The job's id (`ajob_…`). */\n readonly id: string;\n readonly threadId: string;\n readonly toolCallId: string;\n readonly toolName: string;\n /** The `runOwner` of the run that started it. */\n readonly owner: string | null;\n readonly summary: unknown;\n /** Not aborted yet: cancellation comes with a later release (#461, phase 4). */\n readonly signal: AbortSignal;\n /**\n * The attachments of the run that started the job: what the tool's\n * `ctx.attachments` was. Throws when that run had no attachment scope.\n */\n readonly attachments: JobAttachments;\n /** `generate`, with its usage counted on the job. See `ToolContext.generate`. */\n generate<O extends Schema<any>>(params: GenerateParams<O>): Promise<GenerateResult<Infer<O>>>;\n /** Renders an image and stores it under the run's attachments. Usage is counted on the job. */\n generateImage(model: ImageModel, params: JobGenerateImageParams): Promise<GeneratedAttachment>;\n /** Edits images (bytes or attachment ids) and stores the result. Usage is counted on the job. */\n editImage(model: ImageModel, params: JobEditImageParams): Promise<GeneratedAttachment>;\n /** What this attempt has spent so far. */\n readonly usage: Usage;\n}\n\n/**\n * A queued job that settles a tool call (#461).\n *\n * class RenderImagesJob extends AgentJob<{ pageId: number; prompts: string[] }, { made: number }> {\n * static name = \"RenderImagesJob\";\n * async run({ pageId, prompts }, job) {\n * for (const prompt of prompts) await job.generateImage(model, { prompt });\n * return { made: prompts.length };\n * }\n * }\n *\n * A gemi `Job`, so it gets the queue's leases, retries, backoff and dead\n * letters. Register it with the queue like any other job. What `run` returns\n * settles the tool call `ok`; a throw on the last attempt settles it `error`.\n * At least once: make `run` idempotent.\n *\n * Declare `run` as a method, not as an arrow-function field. Override\n * `onDeadletter` only with a call to `super.onDeadletter`, which is what fails\n * the job. `worker = true` is not supported. The queue hands `uniqueId`,\n * `throttle`, `concurrency`, `onFail` and `onDeadletter` the envelope\n * `{ jobId, args }`, not `args`.\n */\nexport abstract class AgentJob<Args = unknown, Output = unknown> extends Job {\n /** Phantom: the arguments' type. Never set. */\n declare readonly $args: Args;\n /** Phantom: the output's type. Never set. */\n declare readonly $output: Output;\n\n /**\n * Where the job's `attachments` records live. Set it to what the\n * controller's `attachments` is, as for the controller itself.\n */\n attachments: AttachmentStore = defaultAttachmentStore;\n /** Where the attachments' bytes live. Defaults to the app's `Storage`. */\n attachmentStorage: AttachmentStorage = Storage;\n\n abstract run(args: Args, job: AgentJobContext): Promise<Output> | Output;\n\n constructor() {\n super();\n // The queue calls `run(...payload)`, and the payload is the envelope. The\n // subclass's `run` is the job's body, so it is wrapped here, on the\n // instance: the queue sees a `run` that loads the record, runs the body\n // and settles the job, and the subclass writes only its work.\n const body = (this as any).run as (args: Args, job: AgentJobContext) => Promise<Output>;\n (this as any).run = (envelope: JobEnvelope) => this.$runEnvelope(envelope, body);\n }\n\n /**\n * Fails the job once the queue has given up on it: its last attempt threw,\n * it called `this.fail(error, { retry: false })`, or its process died on the\n * last attempt.\n */\n onDeadletter(error: Error, ..._args: any[]): void {\n const envelope = _args[0] as JobEnvelope | undefined;\n if (!envelope?.jobId) return;\n void settleOn(AgentJobs.store, envelope.jobId, { error }).catch((err) => {\n console.error(`Could not record the failure of background job ${envelope.jobId}.`, err);\n });\n }\n\n /** @internal The queue-facing `run`: see the constructor. */\n private async $runEnvelope(\n envelope: JobEnvelope,\n body: (args: Args, job: AgentJobContext) => Promise<Output>,\n ): Promise<Output | undefined> {\n const store = AgentJobs.store;\n const record = await store.get(envelope.jobId);\n // Settled already (the deadline passed, or another attempt finished it):\n // nothing it produced would be kept, so the work is not done again.\n if (!record || record.state !== \"running\") return undefined;\n\n const context = new JobContext(record, this);\n let output: Output;\n try {\n output = await body.call(this, envelope.args as Args, context);\n } catch (error) {\n await keepUsage(store, record.id, context.usage);\n throw error;\n }\n if (this.$outcome) {\n // `this.release()` or `this.fail()`: the queue decides what happens next.\n await keepUsage(store, record.id, context.usage);\n return output;\n }\n await settleOn(store, record.id, { output, usage: context.usage });\n return output;\n }\n}\n\n/** Adds an attempt's spend to a job still running, so a retry does not lose it. */\nasync function keepUsage(store: AgentJobStore, id: string, usage: Usage): Promise<void> {\n if (usage.totalTokens === 0 && usage.inputTokens === 0 && usage.outputTokens === 0) return;\n const record = await store.get(id);\n if (!record) return;\n await store\n .transition(id, ANY_STATE, { usage: addUsage(record.usage ?? emptyUsage(), usage) })\n .catch(() => {});\n}\n\nclass JobContext implements AgentJobContext {\n readonly id: string;\n readonly threadId: string;\n readonly toolCallId: string;\n readonly toolName: string;\n readonly owner: string | null;\n readonly summary: unknown;\n readonly signal = new AbortController().signal;\n usage: Usage = emptyUsage();\n readonly attachments: JobAttachments;\n\n constructor(record: AgentJobRecord, job: AgentJob<any, any>) {\n this.id = record.id;\n this.threadId = record.threadId;\n this.toolCallId = record.toolCallId;\n this.toolName = record.toolName;\n this.owner = record.owner;\n this.summary = record.summary;\n const scoped = record.attachmentScope\n ? new ScopedAttachments(job.attachments, job.attachmentStorage, {\n key: record.attachmentScope,\n })\n : null;\n const scope = (): ScopedAttachments => {\n if (!scoped) {\n throw new InvalidAttachmentScopeError(\n \"The run that started this job had no attachment scope, so the job cannot store or read files. See `attachmentScope()` on the controller.\",\n );\n }\n return scoped;\n };\n this.attachments = {\n put: (blob, params = {}) => scope().put(blob, params),\n get: (id) => scope().get(id),\n read: (id) => scope().read(id),\n file: (id) => scope().file(id),\n };\n }\n\n generate(params: GenerateParams<any>): Promise<any> {\n return generateWithin(params, {\n origin: { threadId: this.threadId, toolCallId: this.toolCallId, jobId: this.id },\n settled: (result) => {\n this.usage = addUsage(this.usage, result.usage);\n },\n });\n }\n\n async generateImage(\n model: ImageModel,\n params: JobGenerateImageParams,\n ): Promise<GeneratedAttachment> {\n const { name, ...settings } = params as JobGenerateImageParams & { name?: string };\n const image = await model.generate({ ...settings, signal: this.signal });\n return this.park(model, image, name);\n }\n\n async editImage(model: ImageModel, params: JobEditImageParams): Promise<GeneratedAttachment> {\n const { name, images, mask, ...settings } = params as JobEditImageParams & { name?: string };\n const asInput = async (input: ImageInput | string): Promise<ImageInput> =>\n typeof input === \"string\" ? await this.attachments.file(input) : input;\n const image = await model.edit({\n ...settings,\n images: (await Promise.all(images.map(asInput))) as [ImageInput, ...ImageInput[]],\n ...(mask ? { mask: await asInput(mask) } : {}),\n signal: this.signal,\n });\n return this.park(model, image, name);\n }\n\n private async park(\n model: ImageModel,\n image: { image: Blob; mimeType: string; size: string; usage: Usage },\n name: string | undefined,\n ): Promise<GeneratedAttachment> {\n // Counted before the store write, which may fail: the render was billed.\n this.usage = addUsage(this.usage, image.usage);\n const extension = image.mimeType === \"image/jpeg\" ? \"jpg\" : \"png\";\n const attachment = await this.attachments.put(image.image, {\n name: name ?? `${model.name}.${extension}`,\n mimeType: image.mimeType,\n });\n return { attachment, size: image.size, mimeType: image.mimeType, usage: image.usage };\n }\n}\n",
|
|
11
|
-
"/**\n * Bounding what a long thread sends to the model (#473).\n *\n * A threaded conversation grows without end, and before this nothing in gemi\n * bounded what a turn sent: the whole `loadThread` went to the provider until\n * it answered `context_length_exceeded`. These are the pieces an app needs to\n * bound it where the model call is, rather than in its store:\n *\n * - `turnStarts` / `splitTurns`: where the user's turns begin. A cut made at\n * one never separates a tool call from its result, since a result is stored\n * in the message that made the call, and never strands a tool-injected file\n * message (user role, but not a turn) from the call that showed it.\n * - `windowMessages`: a built-in policy over those turns (at most N turns, at\n * most N bytes or approximate tokens), with cut points that move in steps so\n * the provider's prompt cache keeps hitting.\n *\n * `Agent.create({ contextWindow })` applies the policy on every model call, and\n * `prepareStep` is the hook for anything else. Neither changes what is stored:\n * they shape the request, and the run's history, `onMessage` and the store\n * see every message as before.\n */\n\nimport type { ContextCompactOptions } from \"./contextCompaction\";\nimport type { AgentMessage, ToolCallPart, ToolSearchRecord } from \"./types\";\n\n/**\n * The ids of the messages a tool injected to show a file, read from the\n * `ToolCallPart.attachments` records in `messages`.\n *\n * The record is the test, not `attachmentId` on the part: a user's own upload\n * carries an `attachmentId` too. Such a message has the user's role but is not\n * the user's turn, which is why `turnStarts` steps over it.\n */\nexport function injectedMessageIds(messages: readonly AgentMessage[]): Set<string> {\n const injected = new Set<string>();\n for (const message of messages) {\n for (const part of message.content ?? []) {\n if (part.type !== \"tool-call\") continue;\n for (const record of part.attachments ?? []) {\n if (record && \"shown\" in record && record.shown) injected.add(record.shown.messageId);\n }\n }\n }\n return injected;\n}\n\n/**\n * The index of the first message of every turn in `messages`.\n *\n * A turn starts at a user message that no tool injected, and runs until the\n * next one: the assistant's steps, their tool calls with their results (which\n * are stored on the same message as the call), and any file a tool showed.\n * Index 0 always starts a turn, so messages before the first user message (a\n * greeting, a run cut short before its turn was stored) belong to the first\n * turn rather than to none. Empty for an empty list.\n */\nexport function turnStarts(messages: readonly AgentMessage[]): number[] {\n if (messages.length === 0) return [];\n const injected = injectedMessageIds(messages);\n const starts = [0];\n for (let index = 1; index < messages.length; index++) {\n const message = messages[index]!;\n if (message.role === \"user\" && !injected.has(message.id)) starts.push(index);\n }\n return starts;\n}\n\n/** `messages` grouped into turns. See `turnStarts`. */\nexport function splitTurns(messages: readonly AgentMessage[]): AgentMessage[][] {\n const starts = turnStarts(messages);\n return starts.map((start, index) => messages.slice(start, starts[index + 1] ?? messages.length));\n}\n\n/**\n * Roughly how much a message costs to send: the length of its JSON. A file\n * part counts as its reference, not its bytes, which is what the request\n * carries. Good enough to budget with, and the same number for the same\n * message every time, which is what keeps a cut point stable.\n */\nexport function messageSize(message: AgentMessage): number {\n try {\n return JSON.stringify(message).length;\n } catch {\n return 0;\n }\n}\n\n/** Characters per token when a budget is given in `maxTokens`. */\nconst CHARS_PER_TOKEN = 4;\n\n/** `ContextWindowOptions.step`'s default. */\nexport const DEFAULT_CONTEXT_WINDOW_STEP = 10;\n\n/** `ContextWindowOptions.note`'s default. */\nexport const DEFAULT_CONTEXT_WINDOW_NOTE = \"[Earlier turns of this conversation are not shown.]\";\n\nexport type ContextWindowOptions = {\n /** The most turns sent. The latest turn is always sent, whatever the limits. */\n maxTurns?: number;\n /**\n * The most characters of message JSON sent (see `messageSize`). The system\n * prompt and the tools' schemas are not counted.\n */\n maxBytes?: number;\n /**\n * The same budget in approximate tokens (four characters each). When both\n * are given, the smaller one applies.\n */\n maxTokens?: number;\n /**\n * How many turns the start of the window moves at a time. Default 10.\n *\n * A window that slid one turn per turn would send a different first message\n * on every turn, and the provider's prompt cache (a prefix cache) would miss\n * on every turn. With a step, the first kept turn is the 0th, the 10th, the\n * 20th, … of the thread, so consecutive turns send the same prefix until the\n * window has to move again. The cost is that the window holds up to `step`\n * fewer turns than the limits would allow. `1` slides one turn at a time.\n */\n step?: number;\n /**\n * Put at the start of the first kept turn when turns were left out, so the\n * model knows the conversation goes back further. Default\n * `DEFAULT_CONTEXT_WINDOW_NOTE`; `false` for none. A function gets how much\n * was left out and answers the text, or `false`.\n */\n note?: string | false | ((omitted: { turns: number; messages: number }) => string | false);\n /**\n * Summarise the turns left out instead of dropping them (#782). Off unless\n * set; `true` uses the defaults. Applies to a run with a `threadId` (a\n * stored thread), at the top level; anything else, stateless threads\n * included, gets the plain window. `windowMessages` itself ignores it. See\n * `ContextCompactOptions`.\n *\n * Turns are summarised when the window leaves them out and, with\n * `compact.triggerTokens`, once the turns sent would be over that many\n * tokens. The summary is made with one or more provider calls when the\n * window's start moves (every `step` turns), usually in the background\n * after the turn before; kept per thread in a `SummaryStore`; and sent as a\n * user message in front of the kept turns, in place of `note`. Its usage is\n * billed once, to a run that waits on it or uses it. If it fails, the run\n * sends the plain window with `note`.\n */\n compact?: boolean | ContextCompactOptions;\n};\n\nexport type ContextWindowResult = {\n /** What to send. New objects only where something changed (the note, a\n * carried search); every other message is the one passed in. */\n messages: AgentMessage[];\n /** The index in the input of the first kept turn's first message. */\n start: number;\n /** How many turns and messages were left out. Both 0 when nothing was. */\n omittedTurns: number;\n omittedMessages: number;\n};\n\n/**\n * The latest turns of `messages` that fit `options`.\n *\n * - Cuts only at a turn start (`turnStarts`), so a tool call keeps its result\n * and a tool-injected file stays below the call that showed it.\n * - Always keeps the latest turn, even when it alone is over the budget: an\n * empty request is worse than an oversized one, and the provider is the\n * judge of whether it fits.\n * - Moves the cut `step` turns at a time, counted from the thread's first\n * turn, so the prefix sent stays the same from turn to turn (see `step`).\n * When no step-aligned cut fits (one huge turn), it falls back to the\n * earliest turn that does.\n * - Keeps `system` messages from before the cut, at the front: they are\n * instructions, not conversation.\n * - Carries tool searches over the cut (#777). A namespaced or deferred tool\n * is only loaded for the model by a search in its history, so a kept call to\n * one whose search was left out gets that search put back on it (on a copy).\n *\n * Pure: the input is never changed, and the same input gives the same output.\n */\nexport function windowMessages(\n messages: readonly AgentMessage[],\n options: ContextWindowOptions = {},\n): ContextWindowResult {\n const all = [...messages];\n const starts = turnStarts(all);\n const budget = byteBudget(options);\n const maxTurns = positive(options.maxTurns) ?? Infinity;\n const step = Math.max(1, Math.floor(positive(options.step) ?? DEFAULT_CONTEXT_WINDOW_STEP));\n\n if (starts.length <= 1 || (maxTurns >= starts.length && budget === Infinity)) {\n return { messages: all, start: 0, omittedTurns: 0, omittedMessages: 0 };\n }\n\n // Characters from each message to the end: what a cut there would send.\n // System messages kept from before the cut are not counted.\n const sizeFrom: number[] = Array.from({ length: all.length + 1 }, () => 0);\n if (budget !== Infinity) {\n for (let index = all.length - 1; index >= 0; index--) {\n sizeFrom[index] = sizeFrom[index + 1]! + messageSize(all[index]!);\n }\n }\n const fits = (turn: number) =>\n starts.length - turn <= maxTurns && sizeFrom[starts[turn]!]! <= budget;\n\n let first = -1;\n for (let turn = 0; turn < starts.length; turn += step) {\n if (fits(turn)) {\n first = turn;\n break;\n }\n }\n if (first < 0) {\n for (let turn = 0; turn < starts.length; turn++) {\n if (fits(turn)) {\n first = turn;\n break;\n }\n }\n }\n if (first < 0) first = starts.length - 1;\n if (first === 0) return { messages: all, start: 0, omittedTurns: 0, omittedMessages: 0 };\n\n const start = starts[first]!;\n const dropped = all.slice(0, start);\n const pinned = dropped.filter((message) => message.role === \"system\");\n const kept = carrySearches(dropped, all.slice(start));\n\n const omitted = { turns: first, messages: dropped.length - pinned.length };\n const note =\n typeof options.note === \"function\"\n ? options.note(omitted)\n : options.note === undefined\n ? DEFAULT_CONTEXT_WINDOW_NOTE\n : options.note;\n if (note) {\n const head = kept[0]!;\n kept[0] = { ...head, content: [{ type: \"text\", text: note }, ...head.content] };\n }\n\n return {\n messages: [...pinned, ...kept],\n start,\n omittedTurns: omitted.turns,\n omittedMessages: omitted.messages,\n };\n}\n\nfunction positive(value: number | undefined): number | undefined {\n return typeof value === \"number\" && value > 0 ? value : undefined;\n}\n\nfunction byteBudget(options: ContextWindowOptions): number {\n const bytes = positive(options.maxBytes) ?? Infinity;\n const tokens = positive(options.maxTokens);\n return Math.min(bytes, tokens === undefined ? Infinity : tokens * CHARS_PER_TOKEN);\n}\n\n/**\n * What a search has to have loaded for a call to make sense: the call's\n * namespace, or, for a deferred tool outside any namespace, its name.\n */\nfunction covers(search: ToolSearchRecord, call: ToolCallPart): boolean {\n const namespaces = Array.isArray(search?.namespaces) ? search.namespaces : [];\n const loaded = Array.isArray(search?.loaded) ? search.loaded : [];\n return call.namespace ? namespaces.includes(call.namespace) : loaded.includes(String(call.name));\n}\n\nfunction searchesOf(part: ToolCallPart): ToolSearchRecord[] {\n return Array.isArray(part.toolSearches) ? part.toolSearches : [];\n}\n\n/**\n * `kept`, with the searches from `dropped` that a kept call still depends on\n * put back on the first call that needs one.\n *\n * A call needs a dropped search when no search before it in `kept` (its own\n * included) covers it and one in `dropped` does. All such searches go on the\n * first call that needs any, in their original order, so every later call is\n * covered by them too. Deterministic in the cut, which keeps the prefix the\n * same from turn to turn while the cut stays put.\n */\nfunction carrySearches(dropped: AgentMessage[], kept: AgentMessage[]): AgentMessage[] {\n const droppedSearches: ToolSearchRecord[] = [];\n for (const message of dropped) {\n for (const part of message.content ?? []) {\n if (part.type === \"tool-call\") droppedSearches.push(...searchesOf(part));\n }\n }\n if (droppedSearches.length === 0) return kept;\n\n const seen: ToolSearchRecord[] = [];\n const needed = new Set<ToolSearchRecord>();\n let host: { message: number; part: number } | undefined;\n kept.forEach((message, m) => {\n (message.content ?? []).forEach((part, p) => {\n if (part.type !== \"tool-call\" || part.partial) return;\n seen.push(...searchesOf(part));\n if (seen.some((search) => covers(search, part))) return;\n const missing = droppedSearches.filter((search) => covers(search, part));\n if (missing.length === 0) return;\n for (const search of missing) needed.add(search);\n host ??= { message: m, part: p };\n });\n });\n if (!host) return kept;\n\n const carried = droppedSearches.filter((search) => needed.has(search));\n const out = [...kept];\n const message = out[host.message]!;\n out[host.message] = {\n ...message,\n content: message.content.map((part, p) =>\n p === host!.part && part.type === \"tool-call\"\n ? { ...part, toolSearches: [...carried, ...searchesOf(part)] }\n : part,\n ),\n };\n return out;\n}\n",
|
|
12
|
-
"/**\n * Compaction for the context window (#782).\n *\n * `contextWindow` (#473) bounds a long thread's request by leaving its older\n * turns out. With `compact` set, the turns left out are summarised instead,\n * and the request becomes `[system messages, summary, ...kept turns]`.\n *\n * - **Incremental.** The part left out of a long thread can itself be bigger\n * than a context, so a summary is never built from the whole of it at once.\n * The summary for a cut is the summary for an earlier cut of the same thread\n * plus the turns between the two, folded in chunks of at most `chunkTokens`.\n * - **Persistent.** Summaries live in a `SummaryStore`, per thread and keyed\n * by the cut (the id of the first kept message). `AgentController` uses its\n * own `AgentStore` when that implements the summary methods, which\n * `MemoryAgentStore` does; otherwise a process-wide memory store.\n * - **Two triggers.** The window's own limits (`maxTurns`, `maxTokens`,\n * `maxBytes`) and `triggerTokens`, a token budget for the turns sent: a\n * thread whose turns are few but long (big tool results) is compacted\n * before `maxTurns` would cut it. `triggerTokens` only moves the cut when a\n * summary can take the turns' place; without one the plain window is sent.\n * - **Computed once per cut.** The cut moves `step` turns at a time, so a\n * summary is made when the window moves and reused, from the store, by every\n * later turn until it moves again. The request's prefix stays the same from\n * turn to turn in between, so the provider's prompt cache keeps hitting.\n * - **In the background.** When a run on a thread ends, the summary the next\n * turn will need is started right away (`precompactWindow`), so the next\n * turn usually finds it stored. If it isn't ready, the next turn waits for\n * the same call, or makes it before its first model call.\n * - **Never twice at once.** In one process, every run and background start\n * on a thread share one summary job per cut. Across processes, a store may\n * implement `lockSummary`; a run that finds the cut locked waits for the\n * summary to appear, and sends the plain window if it doesn't in time.\n * - **Detached from the run.** A summary job is not cancelled by the run that\n * started it: stopping that run stops its wait, not the job, which finishes,\n * is saved, and reaches every run waiting on it.\n * - **Billed once.** Each summary call's usage is added to the usage of a run\n * waiting on the job (the one that started it, while it runs). A call no run\n * was waiting on (a background start, or a job whose run was stopped) is\n * billed to the next run in this process that uses the summary.\n * - **Never fatal.** A failed summary call sends the plain window with its\n * note, as `contextWindow` without `compact` would, and the run goes on.\n *\n * The summary is checked against what it summarised: each record carries a\n * fingerprint of the messages before its cut, so a thread whose earlier\n * messages changed (a regenerate, an edit, an amended tool result) gets a new\n * summary rather than a stale one.\n */\n\nimport type { AgentProvider } from \"./AgentProvider\";\nimport { turnStarts, windowMessages } from \"./contextWindow\";\nimport type { ContextWindowOptions } from \"./contextWindow\";\nimport { generate } from \"./generate\";\nimport { addUsage, emptyUsage } from \"./runtime\";\nimport { s } from \"./Schema\";\nimport type { AgentMessage, AgentContentPart, Usage } from \"./types\";\n\n/** `ContextCompactOptions.maxSummaryTokens`'s default. */\nexport const DEFAULT_MAX_SUMMARY_TOKENS = 1_000;\n/** `ContextCompactOptions.chunkTokens`'s default. */\nexport const DEFAULT_COMPACT_CHUNK_TOKENS = 24_000;\n/** `ContextCompactOptions.lockWaitMs`'s default. */\nexport const DEFAULT_COMPACT_LOCK_WAIT_MS = 20_000;\n/**\n * `ContextCompactOptions.triggerTokens`'s default, for a window with no\n * `maxTokens`/`maxBytes` of its own.\n */\nexport const DEFAULT_COMPACT_TRIGGER_TOKENS = 100_000;\n/**\n * How long one summary call may take. A job is detached from the runs\n * waiting on it, so nothing else would stop a provider that never answers.\n */\nconst SUMMARY_CALL_TIMEOUT_MS = 120_000;\n\n/** `ContextCompactOptions.instructions`'s default. */\nexport const DEFAULT_COMPACT_INSTRUCTIONS = [\n \"You keep a running summary of a conversation between a user and an AI assistant.\",\n \"The assistant will continue the conversation with only your summary and the latest turns, so the summary has to carry everything from the earlier turns it may still need.\",\n \"You are given the summary so far (possibly empty) and the turns that came after it. Answer the updated summary, which replaces the old one.\",\n \"Keep: the user's goals, preferences and constraints; decisions made and why; facts, names, ids, numbers, dates, file names and URLs that may matter later; what tools were used and their important results; open questions and unfinished work.\",\n \"Drop greetings, repetition and anything later turns superseded. Do not invent anything, and do not answer the user.\",\n \"Write terse prose or bullet points, in the language of the conversation.\",\n].join(\" \");\n\n/** The text the summary is sent under. */\nexport const COMPACT_SUMMARY_HEADER =\n \"[Summary of the earlier turns of this conversation, which are not shown:]\";\n\n/**\n * `contextWindow.compact`: summarise the turns the window leaves out instead\n * of dropping them. See `contextCompaction.ts`.\n */\nexport type ContextCompactOptions = {\n /** The model that writes the summaries. Default: the run's provider. */\n provider?: AgentProvider;\n /**\n * Compact once the turns sent would be over this many approximate tokens\n * (four characters each, as `maxTokens` counts them), even when `maxTurns`\n * would keep them all: older turns are summarised until the rest, with the\n * summary, fit. So a few long turns (big tool results) are compacted early.\n *\n * Unlike the window's `maxTokens`, it never drops a turn without a summary:\n * when no summary can be had, the plain window is sent as if it weren't set.\n *\n * Default `DEFAULT_COMPACT_TRIGGER_TOKENS` (100000) when the window has no\n * `maxTokens`/`maxBytes`; when it has one, that budget is the trigger and\n * this is unset. `false` turns it off.\n */\n triggerTokens?: number | false;\n /**\n * Start the summary the next turn will need as soon as a run on the thread\n * ends, rather than when that turn asks for it. Default `true`. The next\n * turn makes it inline (before its first model call) when it isn't ready.\n */\n background?: boolean;\n /** The summariser's system prompt. Default `DEFAULT_COMPACT_INSTRUCTIONS`. */\n instructions?: string;\n /**\n * How long a summary may be, in approximate tokens. Default 1000. The model\n * is asked for at most this, a longer answer is cut to it, and it is\n * reserved from the window's `maxTokens`/`maxBytes`, so the summary and the\n * kept turns together stay within the budget.\n */\n maxSummaryTokens?: number;\n /**\n * The most transcript one summary call is sent, in approximate tokens.\n * Default 24000. More turns than this to fold in (the first summary of a\n * long thread) take several calls, each building on the last.\n */\n chunkTokens?: number;\n /** Passed to the summary call. Default `\"low\"`; dropped by a model that\n * cannot reason. */\n reasoning?: \"minimal\" | \"low\" | \"medium\" | \"high\";\n /**\n * Where the summaries live. Default: the controller's `AgentStore` when it\n * implements `loadSummaries` and `saveSummary` (as `MemoryAgentStore` does),\n * else `defaultSummaryStore`, which lasts as long as the process.\n */\n store?: SummaryStore;\n /**\n * How long a run waits for a summary another process is writing (see\n * `SummaryStore.lockSummary`) before it sends the plain window instead.\n * Default 20000.\n */\n lockWaitMs?: number;\n};\n\n/** One summary of a thread's turns before a cut. */\nexport type ThreadSummary = {\n /** The id of the first message after the summarised part: the cut. */\n cutMessageId: string;\n /** The summary, without `COMPACT_SUMMARY_HEADER`. */\n text: string;\n /** How many turns and messages before the cut it covers. */\n turns: number;\n messages: number;\n /**\n * A hash of the messages it covers, as stored. A record whose fingerprint\n * no longer matches the thread is ignored.\n */\n fingerprint: string;\n createdAt: string;\n /** What the calls that wrote it cost. */\n usage?: Usage;\n};\n\n/**\n * Where `compact` keeps its summaries. `AgentStore` has the same optional\n * methods, so a store that holds threads can hold their summaries too, and\n * drop them with the thread.\n */\nexport interface SummaryStore {\n /**\n * The thread's summaries, in any order. Keeping a few per thread is enough:\n * the latest is what the next cut builds on, and an older one only helps\n * when the window moves back (a regenerate, a larger budget).\n */\n loadSummaries(threadId: string): Promise<ThreadSummary[]>;\n /** Upsert by `cutMessageId`. */\n saveSummary(threadId: string, summary: ThreadSummary): Promise<void>;\n /**\n * Optional, for a store shared by several processes: take the lock for one\n * cut of a thread for at most `ttlMs`, answering its release, or `null` when\n * another process holds it. (Redis: `SET key NX PX ttlMs`.) Without it, two\n * processes may both summarise the same cut once; one process never does.\n */\n lockSummary?(\n threadId: string,\n cutMessageId: string,\n ttlMs: number,\n ): Promise<(() => Promise<void>) | null>;\n}\n\n/** How many summaries `MemorySummaryStore` keeps per thread. */\nconst SUMMARIES_PER_THREAD = 8;\n\n/**\n * Summaries kept per thread in memory, most recent first. Lost on restart and\n * not shared between processes, like `MemoryAgentStore`. Threads are\n * forgotten after `ttlMs` without a read or a write.\n */\nexport class MemorySummaryStore implements SummaryStore {\n private threads = new Map<\n string,\n { summaries: ThreadSummary[]; touchedAt: number }\n >();\n private lastSweep = 0;\n\n constructor(readonly ttlMs = 24 * 60 * 60 * 1000) {}\n\n async loadSummaries(threadId: string): Promise<ThreadSummary[]> {\n this.sweep();\n const entry = this.threads.get(threadId);\n if (!entry) return [];\n entry.touchedAt = Date.now();\n return entry.summaries.slice();\n }\n\n async saveSummary(threadId: string, summary: ThreadSummary): Promise<void> {\n this.sweep();\n const entry = this.threads.get(threadId) ?? {\n summaries: [],\n touchedAt: Date.now(),\n };\n entry.summaries = keepSummary(entry.summaries, summary);\n entry.touchedAt = Date.now();\n this.threads.set(threadId, entry);\n }\n\n /** Forget a thread's summaries. */\n delete(threadId: string): void {\n this.threads.delete(threadId);\n }\n\n private sweep(now = Date.now()): void {\n if (now - this.lastSweep < 60_000) return;\n this.lastSweep = now;\n for (const [threadId, entry] of this.threads) {\n if (now - entry.touchedAt > this.ttlMs) this.threads.delete(threadId);\n }\n }\n}\n\n/**\n * `summaries` with `summary` put first, any older record for the same cut\n * replaced, and at most `SUMMARIES_PER_THREAD` kept. For stores that hold a\n * thread's summaries as a list.\n */\nexport function keepSummary(\n summaries: readonly ThreadSummary[],\n summary: ThreadSummary,\n) {\n return [\n summary,\n ...summaries.filter((held) => held.cutMessageId !== summary.cutMessageId),\n ].slice(0, SUMMARIES_PER_THREAD);\n}\n\n/** The process-wide summary store a run uses when nothing else is given. */\nexport const defaultSummaryStore = new MemorySummaryStore();\n\n/** Whether `store` holds summaries (an `AgentStore` may or may not). */\nexport function isSummaryStore(store: unknown): store is SummaryStore {\n const candidate = store as Partial<SummaryStore> | null | undefined;\n return (\n typeof candidate?.loadSummaries === \"function\" &&\n typeof candidate?.saveSummary === \"function\"\n );\n}\n\n// --- the request -----------------------------------------------------------\n\n/** What a summary job needs, whoever started it. Nothing here is a run's. */\nexport type CompactJobParams = {\n /** What the request would send before windowing (`historyForProvider`). */\n history: AgentMessage[];\n /** The same messages as stored, index for index, for the fingerprint. */\n stored: readonly AgentMessage[];\n window: ContextWindowOptions;\n compact: ContextCompactOptions;\n threadId: string;\n /** The run's provider, used when `compact.provider` is not set. */\n provider: AgentProvider;\n store: SummaryStore;\n};\n\nexport type CompactParams = CompactJobParams & {\n /** The run's signal: stops this run's wait, never the summary job. */\n signal: AbortSignal;\n /**\n * Told the usage of the summary calls this run is billed for, failed ones\n * included. See \"Billed once\" above.\n */\n onUsage: (usage: Usage) => void;\n /**\n * The run's own memo, by cut: the messages before the cut don't change\n * between a run's steps, so later steps skip the fingerprint and the store,\n * and a summary that failed is not tried again on every step.\n */\n memo?: Map<string, ThreadSummary | null>;\n};\n\n/** The two windows over one history: the one compaction cuts at, and the\n * plain one sent when there is no summary. */\nfunction plan(\n history: readonly AgentMessage[],\n window: ContextWindowOptions,\n compact: ContextCompactOptions,\n) {\n const maxSummaryTokens =\n positiveInt(compact.maxSummaryTokens) ?? DEFAULT_MAX_SUMMARY_TOKENS;\n // The summary is sent too, so it comes out of the budget. Never down to 0,\n // which `windowMessages` would read as \"no limit\".\n const reserve = (tokens: number) => Math.max(1, tokens - maxSummaryTokens);\n const plain: ContextWindowOptions = {\n ...window,\n ...(positiveInt(window.maxTokens)\n ? { maxTokens: reserve(window.maxTokens!) }\n : {}),\n ...(positiveInt(window.maxBytes)\n ? {\n maxBytes: Math.max(\n 1,\n window.maxBytes! - maxSummaryTokens * CHARS_PER_TOKEN,\n ),\n }\n : {}),\n };\n const trigger = triggerTokens(window, compact);\n const compacting: ContextWindowOptions = {\n ...plain,\n note: false,\n ...(trigger\n ? { maxTokens: Math.min(plain.maxTokens ?? Infinity, reserve(trigger)) }\n : {}),\n };\n return { plain, cut: windowMessages(history, compacting), maxSummaryTokens };\n}\n\n/** `ContextCompactOptions.triggerTokens` as it applies to `window`. */\nfunction triggerTokens(\n window: ContextWindowOptions,\n compact: ContextCompactOptions,\n): number | undefined {\n if (compact.triggerTokens === false) return undefined;\n const set = positiveInt(compact.triggerTokens || undefined);\n if (set) return set;\n if (positiveInt(window.maxTokens) || positiveInt(window.maxBytes))\n return undefined;\n return DEFAULT_COMPACT_TRIGGER_TOKENS;\n}\n\n/**\n * The messages a compacted window sends: the window with the summary of what\n * it left out in front, or the plain window (with its note) when there is\n * nothing to summarise or the summary could not be made.\n */\nexport async function compactWindow(\n params: CompactParams,\n): Promise<AgentMessage[]> {\n const { history, window, compact } = params;\n const { plain, cut, maxSummaryTokens } = plan(history, window, compact);\n if (cut.omittedTurns === 0) return cut.messages;\n\n const memoKey = `${history[cut.start]!.id}:${cut.start}`;\n let summary: ThreadSummary | null | undefined = params.memo?.get(memoKey);\n if (summary === undefined) {\n try {\n summary = await summaryFor(params, cut.start, maxSummaryTokens);\n } catch (error) {\n if (params.signal.aborted) throw error;\n summary = null;\n }\n // Not when the run was stopped: that is no verdict on the summary.\n if (!params.signal.aborted) params.memo?.set(memoKey, summary);\n }\n if (!summary) return windowMessages(history, plain).messages;\n\n const keptCount = history.length - cut.start;\n const pinned = cut.messages.slice(0, cut.messages.length - keptCount);\n const kept = cut.messages.slice(cut.messages.length - keptCount);\n const head = history[cut.start]!;\n return [\n ...pinned,\n {\n // Derived from the cut, so the same cut sends the same message: the\n // prompt cache keys on the bytes.\n id: `summary_${head.id}`,\n role: \"user\",\n content: [\n { type: \"text\", text: `${COMPACT_SUMMARY_HEADER}\\n${summary.text}` },\n ],\n createdAt: head.createdAt,\n },\n ...kept,\n ];\n}\n\n/** The id of the stand-in for the next turn's user message. */\nconst NEXT_TURN_ID = \"\\u0000next-turn\";\n\n/**\n * Starts, in the background, the summary the thread's next turn will need,\n * when it isn't stored yet: the cut is worked out with an empty user message\n * standing in for that turn. A next turn whose message moves the cut further\n * (a long one, against a token budget) makes its own summary, as without this.\n *\n * Never rejects and nobody has to wait on it; the promise is for tests and\n * shutdown, as `settleSummaries` is.\n */\nexport function precompactWindow(params: CompactJobParams): Promise<void> {\n const started = precompact(params).finally(() => starting.delete(started));\n starting.add(started);\n return started;\n}\n\n/** `precompactWindow`s still deciding whether to start a job. */\nconst starting = new Set<Promise<void>>();\n\nasync function precompact(params: CompactJobParams): Promise<void> {\n try {\n const next: AgentMessage = {\n id: NEXT_TURN_ID,\n role: \"user\",\n content: [{ type: \"text\", text: \"\" }],\n createdAt: new Date().toISOString(),\n };\n const history = [...params.history, next];\n const stored = [...params.stored, next];\n const { cut, maxSummaryTokens } = plan(\n history,\n params.window,\n params.compact,\n );\n if (cut.omittedTurns === 0 || history[cut.start]!.id === NEXT_TURN_ID)\n return;\n const target = cutTarget({ ...params, history, stored }, cut.start);\n if ((await load(params.store, params.threadId)).some(target.matches))\n return;\n await job(\n target,\n { ...params, history, stored },\n cut.start,\n maxSummaryTokens,\n ).promise;\n } catch {\n // Best effort: the next turn makes it inline.\n }\n}\n\n/** Resolves once every summary job in flight in this process has ended. */\nexport async function settleSummaries(): Promise<void> {\n while (jobs.size > 0 || starting.size > 0) {\n await Promise.allSettled([\n ...starting,\n ...[...jobs.values()].map((running) => running.promise),\n ]);\n }\n}\n\n/** One summary being made, shared by every run that needs it. */\ntype Job = {\n promise: Promise<ThreadSummary | null>;\n /** The runs waiting on it, in the order they came. The first is billed. */\n payers: Array<(usage: Usage) => void>;\n /** Usage of calls made while no run was waiting. */\n owed: Usage | undefined;\n};\n\n/** Summary jobs in flight in this process, by thread, cut and fingerprint. */\nconst jobs = new Map<string, Job>();\n\n/**\n * Usage of finished jobs no run was billed for, by job key, for the next run\n * that uses the summary. Bounded: a thread nobody comes back to leaves its\n * entry until it is pushed out.\n */\nconst owed = new Map<string, Usage>();\nconst MAX_OWED = 1_000;\n\nfunction owe(key: string, usage: Usage): void {\n owed.set(key, addUsage(owed.get(key) ?? emptyUsage(), usage));\n while (owed.size > MAX_OWED) owed.delete(owed.keys().next().value!);\n}\n\nfunction claimOwed(key: string, onUsage: (usage: Usage) => void): void {\n const usage = owed.get(key);\n if (!usage) return;\n owed.delete(key);\n onUsage(usage);\n}\n\n/** What identifies the summary for the cut at `start`. */\nfunction cutTarget(params: CompactJobParams, start: number) {\n const cutMessageId = params.history[start]!.id;\n const fingerprints = prefixFingerprints(params.stored, start);\n const fingerprint = fingerprints[start]!;\n return {\n key: `${params.threadId}\\u0000${cutMessageId}\\u0000${fingerprint}`,\n fingerprints,\n matches: (summary: ThreadSummary | undefined) =>\n summary?.cutMessageId === cutMessageId &&\n summary.fingerprint === fingerprint,\n };\n}\n\nasync function summaryFor(\n params: CompactParams,\n start: number,\n maxSummaryTokens: number,\n): Promise<ThreadSummary | null> {\n const target = cutTarget(params, start);\n const found = (await load(params.store, params.threadId)).find(\n target.matches,\n );\n if (found) {\n claimOwed(target.key, params.onUsage);\n return found;\n }\n\n const running = job(target, params, start, maxSummaryTokens);\n // Billed from here on, and for whatever ran while nobody waited.\n if (running.owed) {\n params.onUsage(running.owed);\n running.owed = undefined;\n }\n running.payers.push(params.onUsage);\n try {\n return await untilAborted(running.promise, params.signal);\n } finally {\n running.payers.splice(running.payers.indexOf(params.onUsage), 1);\n claimOwed(target.key, params.onUsage);\n }\n}\n\n/** The job for `target`, started if none is running. */\nfunction job(\n target: ReturnType<typeof cutTarget>,\n params: CompactJobParams,\n start: number,\n maxSummaryTokens: number,\n): Job {\n const running = jobs.get(target.key);\n if (running) return running;\n\n const created: Job = { promise: undefined!, payers: [], owed: undefined };\n const bill = (usage: Usage) => {\n const payer = created.payers[0];\n if (payer) payer(usage);\n else created.owed = addUsage(created.owed ?? emptyUsage(), usage);\n };\n created.promise = (async () => {\n const { store, threadId } = params;\n const lockWaitMs =\n positiveInt(params.compact.lockWaitMs) ?? DEFAULT_COMPACT_LOCK_WAIT_MS;\n let release: (() => Promise<void>) | null = null;\n if (store.lockSummary) {\n try {\n release = await store.lockSummary(\n threadId,\n params.history[start]!.id,\n lockWaitMs + 60_000,\n );\n } catch {\n release = null;\n }\n if (!release) return waitFor(params, target.matches, lockWaitMs);\n }\n try {\n // Again under the lock: whoever held it may have just written it.\n const summaries = await load(store, threadId);\n const again = summaries.find(target.matches);\n if (again) return again;\n return await build(\n params,\n summaries,\n target.fingerprints,\n start,\n maxSummaryTokens,\n bill,\n );\n } finally {\n if (release) await release().catch(() => {});\n }\n })()\n .catch(() => null)\n .finally(() => {\n jobs.delete(target.key);\n if (created.owed) owe(target.key, created.owed);\n created.owed = undefined;\n });\n jobs.set(target.key, created);\n return created;\n}\n\n/** `promise`, or a rejection as soon as `signal` fires. The promise goes on. */\nfunction untilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(signal.reason);\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n },\n );\n });\n}\n\nasync function load(\n store: SummaryStore,\n threadId: string,\n): Promise<ThreadSummary[]> {\n try {\n const summaries = await store.loadSummaries(threadId);\n return Array.isArray(summaries) ? summaries.filter(isRecord) : [];\n } catch {\n return [];\n }\n}\n\nfunction isRecord(value: unknown): value is ThreadSummary {\n const record = value as ThreadSummary | null;\n return (\n !!record &&\n typeof record.cutMessageId === \"string\" &&\n typeof record.text === \"string\" &&\n typeof record.fingerprint === \"string\"\n );\n}\n\n/** Another process holds the cut's lock: wait for its summary to land. */\nasync function waitFor(\n params: CompactJobParams,\n matches: (summary: ThreadSummary | undefined) => boolean,\n waitMs: number,\n): Promise<ThreadSummary | null> {\n const until = Date.now() + waitMs;\n while (Date.now() < until) {\n await new Promise((resolve) => setTimeout(resolve, 250));\n const found = (await load(params.store, params.threadId)).find(matches);\n if (found) return found;\n }\n return null;\n}\n\n/**\n * Folds the turns before `start` into a summary, from the latest still-valid\n * summary at an earlier cut (or from nothing), and saves it.\n */\nasync function build(\n params: CompactJobParams,\n summaries: ThreadSummary[],\n fingerprints: string[],\n start: number,\n maxSummaryTokens: number,\n bill: (usage: Usage) => void,\n): Promise<ThreadSummary | null> {\n const { history, compact } = params;\n const starts = turnStarts(history);\n const startTurn = starts.indexOf(start);\n\n // The base: the latest summary whose cut is a turn start before this one\n // and whose fingerprint still matches the thread up to it.\n const indexOf = new Map(starts.map((index) => [history[index]!.id, index]));\n let base: ThreadSummary | undefined;\n let from = 0;\n for (const summary of summaries) {\n const at = indexOf.get(summary.cutMessageId);\n if (at === undefined || at >= start || at <= from) continue;\n if (summary.fingerprint !== fingerprints[at]) continue;\n base = summary;\n from = at;\n }\n\n const chunkChars =\n (positiveInt(compact.chunkTokens) ?? DEFAULT_COMPACT_CHUNK_TOKENS) *\n CHARS_PER_TOKEN;\n const chunks = chunkTurns(history, starts, from, start, chunkChars);\n const maxChars = maxSummaryTokens * CHARS_PER_TOKEN;\n const instructions = `${compact.instructions ?? DEFAULT_COMPACT_INSTRUCTIONS} Keep the summary under about ${Math.round(maxSummaryTokens * 0.75)} words.`;\n\n let text = base?.text ?? \"\";\n let usage = emptyUsage();\n for (const chunk of chunks) {\n const result = await generate({\n provider: compact.provider ?? params.provider,\n instructions,\n prompt: `Summary so far:\\n${text || \"(none yet: these are the first turns of the conversation)\"}\\n\\nThe turns that came after it:\\n${chunk}`,\n output: s.object({ summary: s.string() }),\n reasoning: compact.reasoning ?? \"low\",\n signal: AbortSignal.timeout(SUMMARY_CALL_TIMEOUT_MS),\n });\n usage = addUsage(usage, result.usage);\n bill(result.usage);\n if (!result.ok) return null;\n text = truncate(result.output.summary.trim(), maxChars);\n }\n if (!text) return null;\n\n const summary: ThreadSummary = {\n cutMessageId: history[start]!.id,\n text,\n turns: startTurn < 0 ? 0 : startTurn,\n messages: start,\n fingerprint: fingerprints[start]!,\n createdAt: new Date().toISOString(),\n usage,\n };\n try {\n await params.store.saveSummary(params.threadId, summary);\n } catch {\n // Sent this time anyway; the next turn writes it again.\n }\n return summary;\n}\n\n// --- the transcript ----------------------------------------------------------\n\nconst CHARS_PER_TOKEN = 4;\n\n/**\n * The turns from `from` to `to` (message indexes, both turn starts) rendered\n * as text, in chunks of whole turns of at most `chunkChars` each. A turn on\n * its own over the limit is its own chunk, its parts cut short.\n */\nexport function chunkTurns(\n history: readonly AgentMessage[],\n starts: readonly number[],\n from: number,\n to: number,\n chunkChars: number,\n): string[] {\n const injected = new Set<string>();\n const startSet = new Set(starts);\n for (let i = 0; i < history.length; i++) {\n if (history[i]!.role === \"user\" && !startSet.has(i) && i !== 0)\n injected.add(history[i]!.id);\n }\n const partLimit = Math.max(500, Math.min(20_000, Math.floor(chunkChars / 2)));\n\n const chunks: string[] = [];\n let current = \"\";\n const bounds = starts.filter((index) => index >= from && index < to);\n bounds.forEach((turnStart, t) => {\n const turnEnd = bounds[t + 1] ?? to;\n const lines: string[] = [];\n for (let i = turnStart; i < turnEnd; i++) {\n const line = renderMessage(\n history[i]!,\n injected.has(history[i]!.id),\n partLimit,\n );\n if (line) lines.push(line);\n }\n const turn = lines.join(\"\\n\");\n if (!turn) return;\n if (current && current.length + turn.length + 2 > chunkChars) {\n chunks.push(current);\n current = \"\";\n }\n current = current ? `${current}\\n\\n${turn}` : turn;\n });\n if (current) chunks.push(current);\n return chunks;\n}\n\nfunction renderMessage(\n message: AgentMessage,\n injected: boolean,\n limit: number,\n): string {\n // System messages before the cut are still sent, at the front.\n if (message.role === \"system\") return \"\";\n const who = injected\n ? \"Tool (file shown)\"\n : message.role === \"user\"\n ? \"User\"\n : \"Assistant\";\n const parts = (message.content ?? [])\n .map((part) => renderPart(part, limit))\n .filter(Boolean);\n return parts.length > 0 ? `${who}: ${parts.join(\"\\n\")}` : \"\";\n}\n\nfunction renderPart(part: AgentContentPart, limit: number): string {\n switch (part.type) {\n case \"text\":\n return truncate(part.text ?? \"\", limit);\n case \"file\":\n return `[file: ${part.name ?? part.mimeType ?? part.fileId ?? \"attachment\"}]`;\n case \"tool-call\": {\n const name = part.namespace\n ? `${part.namespace}.${String(part.name)}`\n : String(part.name);\n return `[called ${name}(${truncate(json(part.input), Math.min(limit, 1_000))})]`;\n }\n case \"tool-result\": {\n const body =\n part.status === \"ok\"\n ? json(part.output)\n : part.status === \"error\"\n ? `error: ${part.error?.message ?? \"\"}`\n : part.status === \"running\"\n ? `a background job (${part.job?.id ?? \"unknown\"}) that was still running`\n : `${part.status}${part.reason ? `: ${part.reason}` : \"\"}`;\n return `[${String(part.name)} returned: ${truncate(body, Math.min(limit, 2_000))}]`;\n }\n case \"output\":\n return `[structured answer: ${truncate(json(part.value), Math.min(limit, 2_000))}]`;\n default:\n return \"\";\n }\n}\n\nfunction json(value: unknown): string {\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return String(value);\n }\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max)}…[cut]`;\n}\n\nfunction positiveInt(value: number | undefined): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : undefined;\n}\n\n// --- fingerprints --------------------------------------------------------------\n\n/**\n * `out[i]` is a fingerprint of `messages[0..i)`, for every `i` up to `end`.\n * A chain over each message's JSON, so one pass gives every prefix.\n */\nexport function prefixFingerprints(\n messages: readonly AgentMessage[],\n end: number,\n): string[] {\n const out = [\"0\"];\n let chain = \"\";\n for (let i = 0; i < end; i++) {\n let body: string;\n try {\n body = JSON.stringify(messages[i]) ?? \"\";\n } catch {\n body = String(messages[i]?.id);\n }\n chain = hash(`${chain}|${hash(body)}`);\n out.push(chain);\n }\n return out;\n}\n\n/** cyrb53: a fast 53-bit string hash. Not cryptographic, and needn't be: it\n * tells a changed history from an unchanged one, on the server's own data. */\nfunction hash(text: string): string {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n for (let i = 0; i < text.length; i++) {\n const ch = text.charCodeAt(i);\n h1 = Math.imul(h1 ^ ch, 2654435761);\n h2 = Math.imul(h2 ^ ch, 1597334677);\n }\n h1 =\n Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^\n Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 =\n Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^\n Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);\n}\n",
|
|
13
|
-
"import { Log } from \"../facades/Log\";\nimport { RequestContext } from \"../http/requestContext\";\nimport type { AgentProvider, ProviderToolNamespace, ProviderToolSpec } from \"./AgentProvider\";\nimport type { GeneratedImage, GenerateImageParams, ImageInput, ImageModel } from \"./ImageModel\";\nimport {\n generateWithin,\n type GenerateParams,\n type GenerateResult,\n type GenerateSuccess,\n} from \"./generate\";\nimport {\n addUsage,\n appendReasoning,\n appendText,\n bestEffortParse,\n emptyUsage,\n outputFormat,\n parseOutput,\n raceAbort,\n resolveRope,\n RunAborted,\n} from \"./runtime\";\nimport { supportsStrict } from \"./Schema\";\nimport { applyRedaction, rememberUnredacted, ToolError } from \"./redact\";\nimport type { ErrorRedactor } from \"./redact\";\nimport type { Infer, JSONSchema, Schema } from \"./Schema\";\nimport { isJobHandle, type JobHandle, type RunJobs, type ToolJobs, toolJobs } from \"./jobs/AgentJob\";\nimport type { AgentJobsOptions } from \"./jobs/contextBlock\";\nimport {\n executionReceiptId,\n spendNestedRun,\n spendPendingCall,\n readSignature,\n signNestedRun,\n signPendingCall,\n verifyNestedRun,\n verifyPendingCall,\n} from \"./signing\";\nimport type {\n Attachment,\n PutAttachmentParams,\n ScopedAttachments,\n ToolAttachmentPut,\n ToolAttachmentRecord,\n ToolAttachments,\n} from \"./store/Attachments\";\nimport { ATTACHMENT_ID_PREFIX, InvalidAttachmentScopeError } from \"./store/Attachments\";\nimport { httpErrorDetail } from \"./providers/errors\";\nimport { defaultNonceStore, type NonceStore } from \"./store/Nonces\";\nimport type { ReceiptClaim, ReceiptStore } from \"./store/Receipts\";\nimport { sseKeepalive } from \"./store/sse\";\nimport {\n injectedMessageIds,\n windowMessages,\n type ContextWindowOptions,\n} from \"./contextWindow\";\nimport {\n compactWindow,\n defaultSummaryStore,\n precompactWindow,\n type CompactJobParams,\n type SummaryStore,\n type ThreadSummary,\n} from \"./contextCompaction\";\nimport type {\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n AgentStreamFrame,\n ClientToolResult,\n ClientTurn,\n FilePart,\n FinishReason,\n NestedRun,\n PendingToolCall,\n ToolCallPart,\n ToolSearchRecord,\n ToolResultPart,\n ToolShapes,\n Usage,\n} from \"./types\";\n\n// --- tools ---------------------------------------------------------------\n\n/**\n * What the app hands a run for its tools to use: who it is for, the ids it is\n * about, and functions the tools call back into — a notifier, a scoped\n * repository, a progress sink.\n *\n * Empty here, and filled in by the app, once, with declaration merging:\n *\n * ```ts\n * declare module \"gemi/ai\" {\n * interface AgentContext {\n * userId: string;\n * notify?: (message: string) => Promise<void>;\n * }\n * }\n * ```\n *\n * WHY IT REPLACED `req`. A run used to be handed the HTTP request that started\n * it, and tools read the user off it. That tied every run to a request, and a\n * run started anywhere else — a queued job, a cron, a script — had nothing to\n * pass: `new HttpRequest()` outside a request throws before a model is called.\n * A run needs to know who it is acting for, not how the ask arrived, so the\n * caller now says that directly. `AgentController` builds it from its request\n * in `context()`; a job builds it from its payload.\n *\n * ONE SHAPE FOR THE APP, NOT ONE PER AGENT. Tools are module-scope singletons\n * that any agent may mount, so there is no agent whose type a tool could be\n * checked against. A field only some runs have is optional, and the tool that\n * needs it checks.\n *\n * TRUSTED. Unlike `ctx.body`, nothing here came from the client unless the\n * caller put it there: it is what the server decided the run is for.\n */\n// oxlint-disable-next-line no-empty-interface\nexport interface AgentContext {}\n\n/**\n * Required from a caller when the app's `AgentContext` has a required field,\n * optional when it has none — so an app that never declares one is not made to\n * pass `{}`, and an app that does cannot start a run that forgets it.\n */\ntype ContextParam = {} extends AgentContext\n ? { context?: AgentContext }\n : { context: AgentContext };\n\n/**\n * Everything a tool needs from the run it is part of.\n *\n * Tools are created once at module scope and shared by every run, so they\n * cannot close over a user or an abort signal — and anything mutable stored on\n * the tool itself would leak across runs. That is why the run's state arrives\n * as an argument instead: the tool stays a singleton and the context is per\n * call.\n */\nexport interface ToolContext {\n /**\n * What the caller of `Agent.stream` handed the run. See `AgentContext`.\n *\n * The same object for every tool of the run and every sub-run started with\n * `ctx.runAgent` — a sub-agent acts for the same caller, so it is given the\n * same one. `{}` for a run started without one.\n */\n context: AgentContext;\n /**\n * The app's own fields from the turn's request body — what `useChat`'s\n * `body` option sent, minus the keys the turn envelope owns.\n *\n * Carried on the run because `AgentController` has already consumed the\n * body, and a run outlives the request anyway, so by the time a tool\n * executes there is nothing left to read. The values are copied onto the run\n * when it starts.\n *\n * `{}` for a run started with none. Untyped on purpose — a tool is a\n * module-scope singleton that any controller may mount, so there is no one\n * `Body` for it to be. The controller that declares one gets it typed in\n * `instructions()`; a tool validates, the way it would any other input it\n * did not define.\n *\n * CLIENT-CONTROLLED. Same trust as a request body: fine to read, not a\n * finding about who the user is. An id from here says which record the\n * client wants, never that it may have it.\n */\n body: Record<string, unknown>;\n runId: string;\n threadId?: string;\n toolCallId: string;\n /**\n * Aborted when the user calls `stop()`, when the run reaches its\n * `maxRunDurationMs`, and when this call reaches the tool's own `timeoutMs`\n * (with a `TimeoutError` `DOMException` as its `reason`, the same as\n * `AbortSignal.timeout`). Not when the connection drops — a run outlives the\n * request that started it so a refresh can reattach, which means a\n * disconnect is no longer a signal to stop working.\n *\n * Pass it to whatever the tool waits on (`fetch(url, { signal })`). A tool\n * that ignores it does not hold the run open, since the run stops waiting\n * for it either way, but whatever it started keeps running in the\n * background.\n */\n signal: AbortSignal;\n /** Which step of the tool loop this is, starting at 1. */\n step: number;\n /**\n * How deep this tool is inside nested runs: 0 at the top, 1 inside a tool of\n * an agent started by `runAgent`, and so on. Compared against `maxDepth` on\n * `Agent.create` so a cycle — agent A with a tool that runs agent A — fails\n * with a sentence to read instead of exhausting the stack.\n */\n readonly depth: number;\n /**\n * True when this tool is being re-entered after a sub-agent it started asked\n * the user something and the user answered.\n *\n * READ THE `runAgent` NOTE BEFORE USING IT. This is the flag that lets a tool\n * tell a first attempt from a replay, and it exists because there is nothing\n * to tell it otherwise: the tool body ran once already.\n */\n readonly resumed: boolean;\n /**\n * Files, both directions.\n *\n * WHAT THIS FIXES. Before it, files travelled one way: a user's upload became\n * a provider file id the model could look at, and a tool that *produced*\n * something — an edited image, a rendered chart — had a string to return and\n * nowhere to put the bytes. `put(blob)` parks them and answers a record whose\n * `id` is the handle everything else uses; `put(blob, { showModel: true })`\n * also sends them to the provider and puts them in front of the model as an\n * input-role message once this tool call settles, which is what makes\n * generate → look → fix a loop rather than a one-way report.\n *\n * SCOPED, AND THAT IS THE WHOLE SECURITY STORY. The object is built from the\n * `ScopedAttachments` the controller resolved for *this request* (see\n * `AgentController.attachmentScope`), and none of its methods takes a scope,\n * so there is nothing for a tool to pass the model's arguments into. An id\n * that came from another user resolves to `AttachmentNotFoundError`, with the\n * same wording an unknown id gets.\n *\n * PER TOOL CALL, LIKE `runAgent`, AND FOR THE SAME REASON. `put` is memoized\n * by call index within the tool call, so a tool that escalates and is\n * re-entered does not store, upload or inject a second time. Read the note on\n * `ToolAttachments.put` before writing a body whose `put` calls sit in a\n * branch.\n *\n * ALWAYS PRESENT, NEVER NULL. A request with no attachment scope — an\n * unauthenticated, thread-less chat — gets an object whose every method\n * throws with a sentence naming `attachmentScope()`. A nullable `ctx`\n * member would be a guard every tool has to remember and most would not,\n * and the failure of forgetting is a `TypeError` in a tool body rather than\n * an explanation.\n */\n attachments: ToolAttachments;\n /**\n * What the user sent with the turn this tool call answers. See `ToolTurn`.\n */\n readonly turn: ToolTurn;\n /**\n * Runs another agent from inside this tool, wired into the parent run.\n *\n * A tool can already drive a sub-agent by hand — make one, iterate it, yield\n * its events as progress. What this does that hand-rolling cannot is join the\n * two runs: the sub-run inherits `ctx.signal` so the parent's `stop()` reaches\n * it; every sub-run event is re-emitted on the parent stream as\n * `nested-event`, numbered in the parent's `seq`, so `/attach` replay stays\n * correct through the nesting; the sub-run's usage rolls into the parent's;\n * its transcript is recorded on the parent's `ToolCallPart.nested`; and the\n * depth and agent-name chain travel with it, so a cycle fails fast.\n *\n * ESCALATION. If the sub-run ends `awaiting-input` — it has an approval tool,\n * or it asked a question — `onPending: \"escalate\"` (the default) throws a\n * `PendingEscalation` carrying the inner pending calls, which the parent run\n * collects exactly like pending calls of its own: the parent ends\n * `awaiting-input` with the sub-agent's questions in its list, and the client\n * answers them with the same `approve()` / `answer()` it uses for any other.\n * `onPending: \"deny\"` refuses them instead and lets the sub-run finish.\n *\n * THE COST, WHICH IS REAL AND WHICH YOU MUST DESIGN AROUND. A JS async\n * generator cannot be suspended across a turn boundary: `awaiting-input` is\n * terminal for the stream, the next turn re-enters the loop at the top and\n * rebuilds its state from the message history, and a paused generator is not\n * in that history and cannot be put there. So an escalating tool is\n * RE-ENTERED FROM THE TOP on the next turn, with `ctx.resumed === true`, and\n * `runAgent` is memoized by call index within the tool call: the Nth\n * `runAgent` of a tool call that already completed on an earlier turn returns\n * its persisted result immediately, calling no provider and running no\n * sub-tool, and only the sub-run that escalated actually continues.\n *\n * The index is the only key there is, so a body whose `runAgent` calls sit in\n * a branch or a loop can produce a different sequence on the replay and make\n * index N mean two different things. That is checked, not trusted: a mismatch\n * fails the tool call with a sentence naming both sub-runs, because pairing a\n * user's answer with a sub-run they never saw would be invisible.\n *\n * Which means: CODE BEFORE AN ESCALATING `runAgent` RUNS AGAIN ON RESUME.\n * Side effects there are repeated. Put your side effects after the\n * `runAgent`, or make them idempotent, or branch on `ctx.resumed`. This is\n * inherent to replay and it is the same bargain the outer tool loop already\n * makes; it is written here in plain words rather than solved with a\n * checkpoint API, because that is a much larger feature than this one.\n */\n runAgent<A extends AnyAgent>(agent: A, params?: RunAgentParams): Promise<NestedRunResult>;\n\n /**\n * One model call with an output schema, from inside this tool: `generate`,\n * bound to the turn. For a typed answer that needs no tools — where a\n * sub-agent would bring a tool loop nobody wants and stream a transcript to\n * the browser for a value it never renders.\n *\n * const result = await ctx.generate({ provider, instructions, prompt, output });\n * if (!result.ok) return { error: result.error.message };\n *\n * WHAT THE BINDING ADDS, and why it is not left to the caller: the call\n * aborts with the turn (`ctx.signal`), and its usage counts toward the turn,\n * the way a nested run's does. Passing the signal by hand is easy to forget\n * and the failure is invisible — a `stop()` that does not stop, and a bill\n * the run under-reports. A `signal` of the tool's own (a timeout) is\n * combined with the turn's, never swapped for it.\n *\n * SERVER ONLY. No frame reaches the client and nothing is written to the\n * transcript; the tool returns whatever it makes of the answer.\n *\n * A BAD ANSWER IS A RESULT, NOT A THROW — `{ ok: false, error, messages,\n * usage }`, so a retry continues `messages` — unless `throwOnError` is set.\n * It is logged unless `logErrors: false`, with the agent, run and tool call\n * it came from. See `generate`. A tool's own `timeoutMs` reaches it through\n * `ctx.signal` and comes back as `code: \"timeout\"`. The exception is the\n * turn itself being stopped, or reaching its deadline: then this throws, as\n * `runAgent` does, so the body does not carry on with half an answer while\n * the run around it is already closing — its result would be discarded\n * anyway.\n *\n * NOT MEMOIZED. A tool re-entered after an escalation calls the model again,\n * unlike `runAgent` and `generateImage`, which replay from what they recorded\n * on the tool call. This records nothing, by design.\n */\n generate<O extends Schema<any>>(\n params: GenerateParams<O> & { throwOnError: true },\n ): Promise<GenerateSuccess<Infer<O>>>;\n generate<O extends Schema<any>>(params: GenerateParams<O>): Promise<GenerateResult<Infer<O>>>;\n\n /**\n * Renders an image and parks it, in one step, wired into this tool call.\n *\n * THE SPELLING DIFFERS FROM `ImageModel.generate` ON PURPOSE, and the reason\n * is the same one behind `ctx.runAgent`: an escalating tool is re-entered\n * from the top on the next turn, so a render reached by a bare\n * `model.generate()` inside a tool body is paid for again on every replay —\n * two minutes and an invoice line, for an image whose id the model has\n * already read. This memoizes the render against the tool call, exactly as\n * `ctx.attachments.put` memoizes a store.\n *\n * IT ANSWERS AN `Attachment`, NOT BYTES, and that is forced rather than\n * chosen: the memo lives in the message history, so it cannot hold an image.\n * The bytes are in the app's Storage, which is where a generated image was\n * going anyway; `ctx.attachments.file(id)` hands them back, and copying them\n * under a key of the app's own is what makes the image outlive the run.\n *\n * `showModel: true` puts the result in front of the model as an input-role\n * message once this call settles, so an agent can look at what it made and\n * try again.\n */\n generateImage(model: ImageModel, params: ToolGenerateImageParams): Promise<GeneratedAttachment>;\n\n /**\n * Edits images and parks the result. Everything above applies.\n *\n * `images` takes attachment ids as well as bytes, and the ids are the point:\n * the image to change is usually the one the model just named (\"make that one\n * warmer\"), so it arrives with exactly the trust of a request body. Ids are\n * resolved through this call's `ctx.attachments`, which applies #489's scope\n * checks; there is no spelling here that reaches an id outside them.\n */\n editImage(model: ImageModel, params: ToolEditImageParams): Promise<GeneratedAttachment>;\n\n /**\n * Hands this call's work to a background job (#461).\n *\n * async execute({ images }, ctx) {\n * return ctx.jobs.start(RenderImagesJob, { images }, { summary: { count: images.length } });\n * }\n *\n * Return the handle and the call's result is `running`: the model is told\n * the job started, the turn goes on and ends, and when the job settles its\n * output becomes the call's result. The tool has to declare `async`, and\n * the run has to be a threaded turn through `AgentController`. Anywhere\n * else `start` and `track` throw a `JobsRequireThreadError`, which the\n * model reads as the tool's error. See `ToolJobs`.\n */\n jobs: ToolJobs;\n}\n\n/** What an image parked by a tool answers. See `ToolContext.generateImage`. */\nexport type GeneratedAttachment = {\n attachment: Attachment;\n /** The pixel dimensions the model produced, read off the response. */\n size: string;\n mimeType: string;\n usage: Usage;\n};\n\ntype ToolImageSettings = Omit<GenerateImageParams, \"prompt\" | \"signal\">;\n\nexport type ToolGenerateImageParams = ToolImageSettings & {\n prompt: string;\n /** The filename to store it under. Defaults to `<model name>.<extension>`. */\n name?: string;\n /** Also show the model its own output, once this tool call settles. */\n showModel?: boolean;\n};\n\nexport type ToolEditImageParams = ToolGenerateImageParams & {\n /** Attachment ids, or raw bytes. At least one. */\n images: [ImageInput | string, ...(ImageInput | string)[]];\n mask?: ImageInput | string;\n};\n\n/**\n * The files of the turn a tool call belongs to, as data the model cannot write.\n *\n * WHAT THIS FIXES. Every method on `ctx.attachments` takes an id, and before\n * this the only ids a tool could get were the ones the model put in its\n * arguments. So a tool meant to use \"the image the user attached\" had to trust\n * the model to name it, and a prompt-injected document could name a different\n * upload of the same user's — yesterday's contract instead of today's photo —\n * which the scope check passes, because it is the user's file. Reading the ids\n * from here instead leaves the model nothing to steer.\n *\n * WHICH TURN: THE USER MESSAGE BEFORE THIS CALL, NOT THE LATEST ONE. Found by\n * walking back from the assistant message that made the call, never by taking\n * the last user message in the history when the tool runs, and the difference\n * is re-entry. An escalating tool runs again from the top on a later turn (see\n * `runAgent`), and \"latest\" is recomputed each time: a turn that answers the\n * sub-agent can carry text or files of its own, and when the re-entered tool\n * asks again, that turn's user message is appended *after* the still-open call\n * — so on the next re-entry \"latest\" is the answer turn, and a tool that read\n * \"the image\" would pick a different file, or none, on its second attempt. The\n * replay checks do not reliably catch that: `putMismatch` compares the media\n * type and showModel, never the bytes, and a sub-run seeded with the file as\n * a message part fingerprints as `<file>` whichever file it was. The message\n * that preceded the call is in the history on every attempt and does not\n * move, so every attempt sees the same list.\n *\n * ONE TURN, NOT THE THREAD. The whole thread is what \"the image I sent earlier\"\n * needs, and it is the wider thing to bind to: a tool that picks \"the first\n * image\" out of forty turns picks whichever one the history happens to put\n * first, and the user who uploaded a new one sees the old one used. A tool that\n * wants earlier turns can take an id from the model and let the scope check it;\n * one that binds should bind to the turn the user is looking at. A turn with\n * text and no files gives an empty list, which is also the answer to \"the user\n * attached nothing this time\".\n *\n * NOT THE FILES A TOOL MADE. A file a tool showed with `put(…, { showModel:\n * true })` is injected as a user-role message and carries an `attachmentId`\n * too, and taking it would make it \"the user's upload\" to the next tool — so\n * the walk steps over every message a tool call's record names as injected,\n * the same test `historyForProvider` uses. A tool that wants what an earlier\n * tool produced has that tool's result to read the id from.\n *\n * IDS ONLY, AND NOT TRUSTED. The name and type beside them on the `FilePart`\n * are what the client said, so they are left off rather than offered as a\n * second, weaker copy of what `ctx.attachments.get(id)` answers from the\n * store. And the ids themselves are only as trustworthy as the history they\n * came from — which, for a stateless client, is whatever it posted. That is\n * fine for the reason everything else about attachments is fine: resolution\n * goes through `ctx.attachments`, whose scope was fixed by the request, so an\n * id from somebody else's upload answers `AttachmentNotFoundError` here\n * exactly as it would from the model's arguments. This list narrows which of\n * the caller's own files a tool reaches for; it grants nothing.\n *\n * Inside a sub-run the turn is the sub-run's own: the message its parent's\n * tool started it with, which has files only if that tool put them there. The\n * parent's upload is not inherited — the tool that called `runAgent` read its\n * own `ctx.turn` and decided what the sub-agent is given.\n */\nexport interface ToolTurn {\n /**\n * The `attachmentId`s on that user message's file parts, in order, without\n * duplicates, and only ids of gemi's own shape. Frozen, and computed once\n * before the body runs.\n */\n readonly attachments: readonly string[];\n}\n\n/** What `ctx.runAgent` is given. `messages` and `prompt` are alternatives. */\nexport interface RunAgentParams {\n /** Prior turns for the sub-agent. Starts empty when omitted. */\n messages?: AgentMessage[];\n /** Sugar for a single user turn — the common case, and the whole message\n * list when there is no sub-conversation to continue. */\n prompt?: string;\n /** Appended to the sub-agent's own `instructions`, for this run only. */\n instructions?: string;\n /** Shown on the nested transcript, e.g. \"researching pricing\". */\n label?: string;\n /**\n * What to do when the sub-run ends `awaiting-input`. `\"escalate\"` (the\n * default) throws `PendingEscalation` so the question reaches the user;\n * `\"deny\"` refuses every pending call and lets the sub-run finish, which is\n * what a tool wants when the sub-agent is meant to be autonomous.\n *\n * `\"deny\"` is refused *in place*, inside the sub-run's own loop, so the\n * sub-agent is told it cannot ask and takes another step rather than ending\n * parked — and it is inherited by everything below, so a grandchild asking to\n * escalate is overruled too. A promise that nothing from this subtree reaches\n * the user is only worth making if the whole subtree keeps it.\n */\n onPending?: \"escalate\" | \"deny\";\n /**\n * Override the sub-agent's own ceiling for this run.\n *\n * Not inherited from the parent. A sub-agent is a different job with a\n * different output size — a generator writing a document against a router\n * answering one word — and silently handing down the caller's ceiling would\n * either strangle the one or fail to bound the other.\n */\n maxOutputTokens?: number;\n temperature?: number;\n}\n\n/**\n * What a completed sub-run gives back.\n *\n * `nested` is the transcript as it is recorded on the parent's tool-call part,\n * so a tool that wants to summarize what its sub-agent did reads the same\n * object the UI renders rather than a second representation of it.\n */\nexport interface NestedRunResult<O = unknown> {\n runId: string;\n /** The sub-agent's name — carried so a caller that fans out over several\n * agents can tell the results apart without tracking the order. */\n agent: string;\n messages: AgentMessage[];\n finishReason: FinishReason;\n usage: Usage;\n /** Set when the sub-agent declares an `output` schema and the run finished. */\n output?: O;\n /** Why the sub-run failed: set exactly when `finishReason` is `\"error\"`. See\n * `AgentRunResult.error`. */\n error?: AgentRunFailure;\n /** The record written to the parent's `ToolCallPart.nested`. */\n nested: NestedRun;\n}\n\n/**\n * Thrown by `ctx.runAgent` when a sub-run ends `awaiting-input`.\n *\n * An exception rather than a return value because it must not be mistaken for\n * an answer: a tool that ignored an `{ escalated: true }` field would return a\n * result to the model as if the sub-agent had finished, and the model would act\n * on an answer nobody gave. `executeTool` lets this one propagate instead of\n * turning it into a `tool_error`, and the step loop collects `pending` exactly\n * like the pending calls it produced itself.\n *\n * `path` is the chain of tool-call ids down to the escalating call; each entry\n * of `pending` already carries its own full path, and this is the prefix they\n * share.\n */\nexport class PendingEscalation extends Error {\n readonly pending: PendingToolCall[];\n readonly path: string[];\n /** The sub-run that parked, so the parent can record its transcript before\n * ending the turn — an escalation is a pause, not a lost run. */\n readonly nested: NestedRun;\n\n constructor(params: { pending: PendingToolCall[]; path: string[]; nested: NestedRun }) {\n super(`A nested agent run is waiting on the user for ${params.pending.length} tool call(s).`);\n this.name = \"PendingEscalation\";\n this.pending = params.pending;\n this.path = params.path;\n this.nested = params.nested;\n }\n}\n\n/**\n * What a per-run `inputSchema` is resolved from: the run's caller and the\n * app's request body, the same `context` and `body` its tools are given.\n */\nexport interface ToolSchemaContext {\n context: AgentContext;\n /** CLIENT-CONTROLLED, exactly as `ToolContext.body` is. */\n body: Record<string, unknown>;\n runId: string;\n threadId?: string;\n /** Aborted with the run. */\n signal: AbortSignal;\n}\n\n/**\n * A tool's input schema: fixed, or resolved once per run.\n *\n * The function form is for a tool whose arguments depend on data — the fields\n * of the collection a page edits, the options a tenant configured. It is\n * called once when a run starts, before the model is shown the tools, and the\n * schema it returns is both what the model sees and what the run validates\n * the tool's arguments against, for every call in that run (a turn that\n * answers a pending call is a new run and resolves it again). Build the\n * schema with `s`, `s.fromJSONSchema` included; it has to be an object at the\n * root, like any tool's.\n *\n * A resolver that throws, or returns a non-object schema, fails the run with\n * `tool_error` before anything is sent to the provider.\n */\nexport type ToolInputSchema<Input> =\n | Schema<Input>\n | ((ctx: ToolSchemaContext) => Schema<Input> | Promise<Schema<Input>>);\n\n/**\n * A tool either resolves once, or yields progress and then returns.\n *\n * The generator form exists because a tool that takes twenty seconds is the\n * normal case, not the exotic one, and a chat UI that shows nothing for twenty\n * seconds looks broken. Yields become `tool-progress` events; the return value\n * is the result the model sees.\n */\nexport type ToolExecute<Input, Output, Progress = unknown> = (\n input: Input,\n ctx: ToolContext,\n) =>\n | Promise<Output | JobHandle<Output>>\n | AsyncGenerator<Progress, Output | JobHandle<Output>, void>;\n\ntype ToolDefinitionBase<Name extends string, Input, Output> = {\n name: Name;\n /** The model's only description of when to reach for this. */\n description: string;\n /** A schema, or a function resolving one per run. See `ToolInputSchema`. */\n inputSchema: ToolInputSchema<Input>;\n /**\n * Optional for a server tool, required for a client one — there it is what\n * the answer is validated against before the model sees it, and what types\n * the value the browser has to produce.\n */\n outputSchema?: Schema<Output>;\n /**\n * Withholds this tool's parameter schema from the request: the model is shown\n * only the name and description, and pulls the rest in with the provider's\n * `tool_search` when it decides it wants the tool (`defer_loading` on the\n * wire).\n *\n * It says nothing about who runs the tool or when — it is a statement about\n * the prompt, not about execution. What it buys is context: an agent with\n * forty tools spends most of its prompt on schemas for tools it will not\n * call, and deferred ones load at the end of the window, so adding one\n * mid-conversation does not invalidate the cache.\n *\n * Purely an optimization, and gemi treats it as one: a provider that cannot\n * do tool search is sent the schemas inline, and the agent behaves the same.\n * So it is safe to set on a model that does not support it, and worth setting\n * only for tools that are large, numerous, or rarely reached.\n */\n deferred?: boolean;\n /**\n * How long one call of this tool may take, in milliseconds. No limit by\n * default; the run's own `maxRunDurationMs` still bounds it.\n *\n * When it is reached, `ctx.signal` is aborted with a `TimeoutError`, the\n * model gets an `error` result for the call with code `\"timeout\"`, and the\n * run carries on: the model can retry, try something else, or answer\n * without it. The run stops waiting for the call at that moment, so a tool\n * that ignores `ctx.signal` cannot hold the run open past it, and anything\n * it yields or returns afterwards is dropped.\n *\n * Set it on any tool that waits on something it does not control (a third\n * party API, a `fetch` with no timeout of its own). Not used by client tools,\n * which the server never runs.\n */\n timeoutMs?: number;\n /**\n * Declares that the tool may hand its work to a background job with\n * `ctx.jobs.start` or `ctx.jobs.track` (#461). `deadlineMs` is how long such\n * a job may run before it is failed with code `\"timeout\"`; an hour when\n * absent. A tool without it cannot start a job.\n */\n async?: { deadlineMs?: number };\n};\n\n/**\n * Two ways a tool's result comes to exist, and neither changes the shape of the\n * conversation.\n *\n * `execute` — the server runs it.\n * `answeredBy: \"client\"` — the browser produces the result: a question for the\n * user, or something only the page can do. The stream ends `awaiting-input`\n * and the answer arrives as an ordinary turn.\n *\n * `requiresApproval` applies to the first: the server can run the tool, but\n * asks first. That, too, ends the stream `awaiting-input`, which is the whole\n * reason there is no second endpoint — an approval is a question whose answer\n * happens to be yes or no.\n */\nexport type ToolDefinition<Name extends string, Input, Output, Progress = never> =\n | (ToolDefinitionBase<Name, Input, Output> & {\n answeredBy?: \"server\";\n execute: ToolExecute<Input, Output, Progress>;\n requiresApproval?: boolean;\n })\n | (ToolDefinitionBase<Name, Input, Output> & {\n answeredBy: \"client\";\n outputSchema: Schema<Output>;\n execute?: never;\n /** Meaningless here: the client answering *is* the approval. */\n requiresApproval?: never;\n });\n\n/**\n * `Progress` is inferred, never written down.\n *\n * It comes from the yield type of an `execute` that is an async generator, and\n * from nothing else — a tool that returns a promise gets `never`, which is the\n * honest statement that it cannot yield and is what makes\n * `ToolShapesOf`'s `progress` member safe to emit unconditionally. It is\n * carried as a fourth parameter rather than derived on demand because it has to\n * survive the trip through `ToolNamespace`, `FlattenTools` and `ToolShapesOf`\n * into the browser, and only a type argument does that.\n *\n * Structurally it lives on `execute`, which is optional, and which is also why\n * `AnyAgentTool` must pass `any` here: `Progress` sits covariantly inside\n * `AsyncGenerator<Progress, …>`, so a bound of `never` would make every\n * yielding tool fail the `Extract` in `ToolShapesOf` and silently vanish from\n * the shapes.\n */\nexport class AgentTool<\n Name extends string = string,\n Input = unknown,\n Output = unknown,\n Progress = never,\n> {\n readonly name: Name;\n readonly description: string;\n readonly inputSchema: ToolInputSchema<Input>;\n readonly outputSchema?: Schema<Output>;\n readonly requiresApproval: boolean;\n readonly deferred: boolean;\n readonly answeredBy: \"server\" | \"client\";\n /** See `ToolDefinition.timeoutMs`. `undefined` is no limit of its own. */\n readonly timeoutMs?: number;\n /** See `ToolDefinition.async`. `undefined` for a tool that cannot start a job. */\n readonly async?: { deadlineMs?: number };\n /**\n * There is deliberately no `namespace` here. A tool is a module-scope\n * singleton, so a field naming its group would hold whichever agent\n * constructed its namespace last and report that to every other one — the\n * same global-effect-from-a-local-declaration that `ToolNamespace.deferred`\n * avoids. Where a tool sits is a property of the agent, and it lives on the\n * agent's `ResolvedTool`.\n */\n readonly execute?: ToolExecute<Input, Output, Progress>;\n\n private constructor(params: ToolDefinition<Name, Input, Output, Progress>) {\n this.name = params.name;\n this.description = params.description;\n this.inputSchema = params.inputSchema;\n this.outputSchema = params.outputSchema;\n this.requiresApproval = params.requiresApproval === true;\n this.deferred = params.deferred === true;\n this.answeredBy = params.answeredBy === \"client\" ? \"client\" : \"server\";\n this.execute = params.execute ?? undefined;\n this.timeoutMs = params.timeoutMs;\n this.async = params.async;\n }\n\n /**\n * `const` on the params is what preserves `name` as a literal, which is what\n * lets the browser discriminate a tool part by name.\n */\n static create<const Name extends string, Input, Output, Progress = never>(\n params: ToolDefinition<Name, Input, Output, Progress>,\n ): AgentTool<Name, Input, Output, Progress> {\n // Only the input: it is the one schema the provider is shown. The\n // `outputSchema` validates what `execute` or the browser hands back and is\n // never sent, so any shape is fine there.\n // A per-run schema is checked when a run resolves it.\n if (typeof params.inputSchema !== \"function\") {\n assertObjectRoot(params.inputSchema, `The tool \"${params.name}\"`, \"inputSchema\");\n }\n if (params.timeoutMs !== undefined) {\n assertDuration(params.timeoutMs, `The tool \"${params.name}\"`, \"timeoutMs\");\n }\n if (params.async?.deadlineMs !== undefined) {\n assertDuration(params.async.deadlineMs, `The tool \"${params.name}\"`, \"async.deadlineMs\");\n }\n if (params.async && params.answeredBy === \"client\") {\n throw new Error(\n `The tool \"${params.name}\" is answered by the client and cannot be \\`async\\`: background jobs are for tools the server runs.`,\n );\n }\n return new AgentTool(params);\n }\n\n /**\n * Sugar for the common client tool: the agent asks the user something and\n * waits. Equivalent to `answeredBy: \"client\"` with an input schema of one\n * prompt field.\n */\n static ask<const Name extends string, Output>(params: {\n name: Name;\n description: string;\n outputSchema: Schema<Output>;\n }): AgentTool<Name, { question: string }, Output> {\n return AgentTool.create({\n name: params.name,\n description: params.description,\n inputSchema: questionSchema,\n outputSchema: params.outputSchema,\n answeredBy: \"client\",\n });\n }\n}\n\n/**\n * The one schema this module owns, rather than one built with `s`.\n *\n * `Schema<T>` carries a phantom property keyed by a symbol `Schema.ts` does not\n * export, so nothing outside that file can produce one without a cast — and\n * reaching for `s` here would make the agent runtime depend on the schema\n * builder for a single hard-coded object. One field, no `describe`, no\n * optionality: the cast is cheaper than the coupling.\n */\nconst questionSchema = {\n toJSONSchema: () => ({\n type: \"object\",\n properties: { question: { type: \"string\", description: \"What to ask the user\" } },\n required: [\"question\"],\n additionalProperties: false as const,\n }),\n parse(value: unknown) {\n const result = questionSchema.safeParse(value);\n if (result.ok === false) throw new Error(result.errors.join(\", \"));\n return result.value;\n },\n safeParse(value: unknown) {\n if (\n typeof value !== \"object\" ||\n value === null ||\n typeof (value as any).question !== \"string\"\n ) {\n return { ok: false as const, errors: [\"question: expected a string\"] };\n }\n return { ok: true as const, value: { question: (value as any).question } };\n },\n} as unknown as Schema<{ question: string }>;\n\nexport type AnyAgentTool = AgentTool<string, any, any, any>;\n\n/**\n * A group of tools the model can search as a unit.\n *\n * The provider's tool search works over namespaces, and the guidance is fewer\n * than ten functions in each — the model looks at a namespace's description to\n * decide whether anything inside is worth loading, so the grouping is part of\n * the prompt, not bookkeeping. A namespace is also the only place a\n * *collection* of tools can be described; on a flat list that sentence has\n * nowhere to go.\n *\n * Tool names stay globally unique within an agent, so the browser still\n * discriminates on `name` alone and the namespace never leaks into the client's\n * types.\n */\nexport class ToolNamespace<\n Name extends string = string,\n T extends readonly AnyAgentTool[] = readonly AnyAgentTool[],\n> {\n readonly name: Name;\n readonly description: string;\n readonly tools: T;\n /**\n * Kept here rather than pushed onto each tool. A tool is a module-scope\n * singleton and may be listed bare as well as inside a group; writing the\n * group's `deferred` onto it would defer it everywhere, which is a global\n * effect from a local declaration.\n */\n readonly deferred: boolean;\n\n private constructor(params: { name: Name; description: string; tools: T; deferred?: boolean }) {\n this.name = params.name;\n this.description = params.description;\n this.tools = params.tools;\n this.deferred = params.deferred === true;\n }\n\n static create<const Name extends string, const T extends readonly AnyAgentTool[]>(params: {\n name: Name;\n /** What the model reads when deciding whether to search inside. */\n description: string;\n tools: T;\n /** Defers every tool in the group, so the whole namespace costs its own\n * description plus one line per tool until something is loaded. */\n deferred?: boolean;\n }): ToolNamespace<Name, T> {\n return new ToolNamespace(params);\n }\n}\n\n/** What an agent's `tools` may hold: tools, or namespaces of them. */\nexport type ToolEntry = AnyAgentTool | ToolNamespace<string, readonly AnyAgentTool[]>;\n\ntype FlattenTools<T extends readonly ToolEntry[]> = T[number] extends infer E\n ? E extends ToolNamespace<any, infer NT>\n ? NT[number]\n : E\n : never;\n\n/**\n * The tool tuple, erased to the payload types the client is allowed to see.\n *\n * `progress` is emitted for every tool, `never` included, rather than only for\n * the ones that can yield. A conditional that dropped the member would make\n * `T[K][\"progress\"]` in `types.ts` resolve differently per tool, and this\n * package compiles with `strict: false` — where `undefined extends T` is true\n * of everything and an optional member is indistinguishable from a required\n * one. Two inference bugs in this module already came from testing a shape\n * under those options and believing the answer (see `OptionalSchema` in\n * `Schema.ts`); an unconditional member has nothing to get wrong.\n */\nexport type ToolShapesOf<T extends readonly ToolEntry[]> =\n ShapesOf<NamedTools<Extract<FlattenTools<T>, AnyAgentTool>>> extends infer Named\n ? [keyof Named] extends [never]\n ? ShapesOf<Extract<FlattenTools<T>, AnyAgentTool>>\n : Named\n : never;\n\n/**\n * The tools whose name is a literal (#771). A tool named only `string` — an\n * untyped `toAgentTools`, or one built from a name read at runtime — would\n * give the shapes a string index signature, and `ToolCallPart`, which indexes\n * the shapes by `keyof`, would then answer the index's untyped member for\n * every tool, the literal ones included. So it is left out, and degrades only\n * itself: its parts are not in the client's union. An agent with no literal\n * name at all keeps the index, as before.\n */\ntype NamedTools<K> = K extends AnyAgentTool ? (string extends K[\"name\"] ? never : K) : never;\n\ntype ShapesOf<U extends AnyAgentTool> = {\n [K in U as K[\"name\"]]: K extends AgentTool<any, infer I, infer O, infer P>\n ? { input: I; output: O; progress: P }\n : never;\n};\n\n// --- skills --------------------------------------------------------------\n\n/**\n * A skill is instructions the model can go and fetch.\n *\n * Inlining every skill into the system prompt costs its tokens on every request\n * and gets worse with each skill added. So a skill is lowered to a tool: one\n * zero-parameter function per skill, in a reserved `skills` namespace, whose\n * description is the skill's and whose result is `instructions` plus any\n * `files`. Only those descriptions are prompted, and a skill the model never\n * reaches for costs a line of text.\n *\n * Lowering to a tool rather than to a synthetic `load_skill(name)` dispatcher\n * is the whole trick: discovery is then the same mechanism as everything else\n * the model chooses between, which means it runs on the provider's own\n * tool-selection machinery instead of on a string argument gemi would have to\n * validate, and a skill that is never loaded is a namespace entry rather than a\n * branch in our code. It is also why `deferred` applies here unchanged — with\n * tool search the namespace is searched, and without it the same tools are\n * listed inline, which for zero-parameter functions costs almost nothing.\n */\nexport interface SkillDefinition<Name extends string = string> {\n name: Name;\n /** Read on every request — this is what the model decides to load from. */\n description: string;\n /** A thunk so a large body stays off the startup path and out of memory. */\n instructions: string | (() => string | Promise<string>);\n /** Paths resolved relative to the app root, appended after `instructions`. */\n files?: string[];\n}\n\nexport class Skill<Name extends string = string> {\n readonly name: Name;\n readonly description: string;\n readonly instructions: string | (() => string | Promise<string>);\n readonly files?: string[];\n\n private constructor(params: SkillDefinition<Name>) {\n this.name = params.name;\n this.description = params.description;\n this.instructions = params.instructions;\n this.files = params.files;\n }\n\n static create<const Name extends string>(params: SkillDefinition<Name>): Skill<Name> {\n return new Skill(params);\n }\n}\n\n/** Reserved: a skill is lowered into a namespace of exactly this name. */\nexport const SKILLS_NAMESPACE = \"skills\";\n\nconst SKILLS_NAMESPACE_DESCRIPTION =\n \"Instructions this agent can load on demand. Load the relevant one before acting in the area it covers.\";\n\n/**\n * Throws unless `schema` emits an object at its root.\n *\n * Both places a schema reaches the provider — a tool's parameters and an\n * agent's structured `output` — require one there: OpenAI's strict function\n * parameters and strict `json_schema` reject `anyOf` at the root (it is legal\n * only under a property), and a primitive or array root is not a parameter\n * list at all. Left to the provider, that is a 400 on the first request that\n * carries the schema, which an app then has to decode; checked here, it is an\n * error at startup naming the tool or agent that declared it.\n *\n * Read off the emitted JSON Schema rather than the builder's tree, so that a\n * hand-built schema (`questionSchema`, the skills' empty one, MCP's merged\n * input) is held to the same rule as one built with `s`.\n */\nfunction assertObjectRoot(schema: Schema<any>, owner: string, field: string): void {\n const json: JSONSchema | undefined = schema?.toJSONSchema?.();\n if (json?.type === \"object\") return;\n const found = !json\n ? \"no JSON Schema\"\n : json.anyOf\n ? \"a union (`anyOf`) — `s.union(...)`\"\n : json.type !== undefined\n ? `a schema of type ${JSON.stringify(json.type)}`\n : \"an unconstrained schema (`s.json()`)\";\n throw new Error(\n `${owner} declares an \\`${field}\\` whose root is ${found}, but the provider only accepts an object there (OpenAI rejects \\`anyOf\\` or a non-object at the root of tool parameters and structured output). Wrap it in an object, e.g. \\`s.object({ value: s.union([...]) })\\`, and read \\`.value\\` off the result.`,\n );\n}\n\n/**\n * A time limit has to be a positive number of milliseconds. `0` and a negative\n * number are refused rather than read as \"no limit\" or \"already expired\": both\n * readings are plausible, and a run that times out on its first tick, or a\n * limit that silently does nothing, is the kind of surprise worth an error at\n * startup instead.\n */\nfunction assertDuration(value: unknown, owner: string, field: string): void {\n if (typeof value === \"number\" && value > 0) return;\n throw new Error(\n `${owner} sets \\`${field}\\` to ${String(value)}, but it has to be a positive number of milliseconds. Use \\`null\\` for no limit.`,\n );\n}\n\n/** `Infinity` and `null` both mean \"no limit\"; `undefined` means \"not said\". */\nfunction normalizeDuration(value: number | null | undefined): number | null | undefined {\n if (value === undefined) return undefined;\n if (value === null || !Number.isFinite(value)) return null;\n return value;\n}\n\n/**\n * The longest delay `setTimeout` keeps: past it the runtime fires in about a\n * millisecond, which for a deadline would mean \"expire now\". A limit longer\n * than this (about 24.8 days) is no limit in practice and is treated as one.\n */\nconst MAX_TIMER_MS = 2 ** 31 - 1;\n\n/**\n * Calls `onExpire` after `ms`, unless `ms` is no limit. Returns the cancel.\n */\nfunction startTimer(ms: number | null, onExpire: () => void): () => void {\n if (ms === null || ms > MAX_TIMER_MS) return () => {};\n const timer = setTimeout(onExpire, ms);\n return () => clearTimeout(timer);\n}\n\n/** `1500` as \"1.5s\", `600000` as \"10m\": for messages a model and a log read. */\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${+(ms / 1000).toFixed(1)}s`;\n return `${+(ms / 60_000).toFixed(1)}m`;\n}\n\nconst EMPTY_PARAMETERS = {\n type: \"object\",\n properties: {},\n required: [] as string[],\n additionalProperties: false as const,\n};\n\n// --- agent ---------------------------------------------------------------\n\n/**\n * How hard the model should think before it answers, sent as the provider's own\n * effort setting (`reasoning.effort` on the Responses API).\n *\n * WHICH VALUES A MODEL TAKES IS THE MODEL'S BUSINESS, not gemi's. gpt-5 takes\n * `\"minimal\"` and not `\"none\"`; gpt-5.1 and later take `\"none\"`; Azure's\n * gpt-6-sol answers 400 to `\"minimal\"` and lists `none | low | medium | high |\n * xhigh | max` (#658). A closed union meant an app could not say the one value\n * its model wanted, and every new value waited on a gemi release. So the known\n * values are listed for autocomplete and any other string is passed through\n * unchanged — the same bet `capabilitiesForModel` makes on unknown model ids: a\n * value the model rejects fails loudly, once, with the API naming the values it\n * does accept (on `result().error`), and the fix is one line.\n *\n * `\"none\"` turns reasoning off on models that support it, which is what a short,\n * latency-bound call wants: with any effort at all, `maxOutputTokens` caps the\n * reasoning tokens too, and a small cap can be spent entirely on thinking. It is\n * not the same as leaving `reasoning` unset, which gets the model's default\n * (usually `\"medium\"`). On a model with no reasoning parameter at all\n * (`capabilities.reasoning` is false) every value, `\"none\"` included, is\n * dropped, since there is nothing to turn off.\n */\nexport type ReasoningEffort =\n | \"none\"\n | \"minimal\"\n | \"low\"\n | \"medium\"\n | \"high\"\n | \"xhigh\"\n | \"max\"\n // `string & {}` keeps the literals above in autocomplete; a bare `string`\n // would swallow them.\n | (string & {});\n\nexport interface CreateAgentParams<\n T extends readonly ToolEntry[],\n S extends readonly Skill[],\n O extends Schema<any> | undefined,\n> {\n name: string;\n /** The system prompt. Per-request additions belong on the controller, which\n * has the request; this is the part that is the same for everyone. */\n instructions?: string;\n provider: AgentProvider;\n tools?: T;\n /** Lowered into the reserved `skills` namespace — see `Skill`. The name is\n * reserved, so a namespace of your own cannot be called `skills`. */\n skills?: S;\n /**\n * Makes the final assistant turn strict JSON instead of prose. Tool turns are\n * unaffected — only the answer is constrained, which is the only place a\n * schema can apply once there is a tool loop.\n */\n output?: O;\n /** Ends the run with `finishReason: \"max-steps\"` rather than throwing: an\n * agent that loops is a bug to show, not an exception to swallow. */\n maxSteps?: number;\n /**\n * How far `ctx.runAgent` may nest below this agent. Default 3.\n *\n * It is a limit on the *tree*, taken from the run at the root, so raising it\n * on a sub-agent cannot deepen a run it did not start. A cycle is caught by\n * the agent-name chain before this is reached — this is for the mutually\n * recursive shape a name check cannot see, and for the merely runaway one.\n */\n maxDepth?: number;\n /** The model's reasoning effort, e.g. `\"none\"` for a quick one-liner or\n * `\"high\"` for a hard problem. Unset gets the model's default. Any string\n * the model accepts works — see `ReasoningEffort`. */\n reasoning?: ReasoningEffort;\n /**\n * A ceiling on the tokens one model call may produce, passed to the provider\n * as its own `max_output_tokens`.\n *\n * It bounds a degenerate generation. A model asked for non-strict JSON can\n * fall into emitting the same character until something stops it, and with\n * no cap the only thing that does is the client giving up — a turn that\n * never ends rather than one that fails. The cap turns that into a run\n * ending with `finishReason: \"length\"`, which an app can retry.\n *\n * Per model call, not per run: a run of four steps may produce four times\n * this. `maxSteps` is the bound on the run.\n */\n maxOutputTokens?: number;\n /**\n * Passed to the provider unchanged. Lower is steadier, which is worth having\n * for a generation whose shape matters more than its phrasing.\n *\n * SENT WHENEVER SET, and not capability-gated the way `reasoning` is.\n * `ProviderCapabilities` carries no flag for it, so `buildResponsesRequest`\n * writes it whenever it is a number and never drops it. That matters because\n * the newer reasoning models reject the parameter outright: setting this for\n * one is a 400 rather than a quietly degraded request. It is the same bargain\n * `output` takes in `request.ts` — an explicit choice is sent and the API gets\n * to say no, because silently dropping one leaves an app believing something\n * about its request that is not true.\n */\n temperature?: number;\n /**\n * Whether a run of this agent that ends with `finishReason: \"error\"` is\n * written to the app's log (`Log.error`, so `storage/logs` and the log\n * config's `onLogCreated`). Default `true`.\n *\n * On by default because the failure otherwise exists only as an `error` frame\n * on a stream a server-side caller may never read, and `result()` resolves\n * rather than rejects. A provider that cannot be reached, or a 400 for a\n * parameter the model refuses, then looks like an agent that said nothing.\n * Turn it off when the app already reports `result().error` (or the\n * controller's `onError`) itself and a second line would be noise.\n *\n * Also covers a tool that throws anything but a `ToolError`: the model and\n * the client only read that it failed (see `redactError`), so the log is\n * where its message and stack are.\n */\n logErrors?: boolean;\n /**\n * The longest one run of this agent may take, in milliseconds. Default\n * `DEFAULT_MAX_RUN_DURATION_MS`, ten minutes. `null` (or `Infinity`) turns\n * the limit off.\n *\n * When it is reached the run is stopped the way `stop()` stops it (every\n * tool call still in flight gets a `denied` result, `ctx.signal` aborts, the\n * provider request is cancelled) and it ends with `finishReason: \"error\"`\n * and `result().error.code` `\"timeout\"`, so it is logged and\n * `result({ throwOnError: true })` rejects. The transcript is finalized and\n * stored like any other.\n *\n * ON BY DEFAULT because the failure it bounds is silent and permanent. A tool\n * that never settles (a `fetch` with no timeout) used to keep its run open\n * for the life of the process, and the live-run registry with it: nobody is\n * watching, nobody calls `/stop`, and nothing expires. Ten minutes is far\n * past any interactive turn (a turn is `maxSteps` model calls plus their\n * tools), and it is per run, not per thread. Time spent waiting for the user\n * does not count, since a run waiting for input has already ended\n * (`awaiting-input`). Raise it for an agent whose runs are legitimately\n * long, such as a batch job or a long research loop.\n *\n * A sub-run started with `ctx.runAgent` is bounded by its parent's limit,\n * since it shares the parent's signal, and has none of its own unless its\n * agent sets one explicitly.\n */\n maxRunDurationMs?: number | null;\n /**\n * Bounds what each model call of this agent is sent: the latest turns of the\n * history that fit, cut at a turn start, with the cut moving in steps so the\n * provider's prompt cache keeps hitting. See `ContextWindowOptions` and\n * `windowMessages`. Unset (the default) sends the whole history, as before.\n *\n * Only the request changes. The run's history, `onMessage`, the store and\n * `result().messages` hold every message, so a thread stays whole and a\n * later turn can be sent a different window.\n */\n contextWindow?: ContextWindowOptions;\n /**\n * Called before every model call of a run of this agent, with the messages\n * about to be sent (after `contextWindow`), and may answer other ones, or\n * other instructions, for that call alone. See `PrepareStep`.\n */\n prepareStep?: PrepareStep;\n /**\n * Background jobs (#461). `contextBlock` bounds the `<jobs>` block the\n * controller adds to the system prompt on a thread with jobs: 20 by\n * default, `false` for none. See `AgentJobsOptions`.\n */\n jobs?: AgentJobsOptions;\n}\n\n/**\n * What `prepareStep` is told before a model call.\n */\nexport type PrepareStepContext = {\n /** 1 for the run's first model call, 2 for the one after its tools ran, … */\n step: number;\n /**\n * What this call would send: the run's history (stored and new), with older\n * tool-produced files already swapped for a line of text, and cut to\n * `contextWindow` when one is set. Copies where anything was changed; never\n * mutate a message in it, since the others are the run's own.\n */\n messages: AgentMessage[];\n /** The same history before `contextWindow` cut it. */\n history: readonly AgentMessage[];\n /** The system prompt this call would send. */\n instructions: string | undefined;\n /** What the run has spent so far, tools' sub-runs included. */\n usage: Usage;\n /** The previous model call's own usage, when it reported one. Its\n * `inputTokens` is how big the last request actually was. */\n lastStepUsage?: Usage;\n /** How the previous model call of this run ended. Absent on step 1. */\n lastFinishReason?: FinishReason;\n runId: string;\n threadId?: string;\n /** The agent's name. */\n agent: string;\n /** 0 for a run started at the top, 1 for a sub-run of one of its tools, … */\n depth: number;\n context: AgentContext;\n signal: AbortSignal;\n};\n\n/**\n * What `prepareStep` may change for one model call. Anything left out is sent\n * as it would have been.\n */\nexport type PrepareStepResult = {\n /**\n * The messages to send instead. Never stored, and the next step starts from\n * the run's history again rather than from these. A tool call left without\n * its result (or a result without its call) is repaired by the provider's\n * request builder, but cutting at `turnStarts` avoids it altogether.\n */\n messages?: AgentMessage[];\n /** The system prompt to send instead. */\n instructions?: string;\n};\n\n/**\n * A hook before every model call: see `CreateAgentParams.prepareStep`. It may\n * be async, and anything it throws fails the run (`finishReason: \"error\"`).\n *\n * The usual job is the context window: `windowMessages` with options decided\n * per call, a summary in place of older turns, a note. Keep it deterministic\n * for the same history and the provider's prompt cache keeps working.\n */\nexport type PrepareStep = (\n ctx: PrepareStepContext,\n) => PrepareStepResult | void | Promise<PrepareStepResult | void>;\n\n/**\n * How long a run may take when its agent does not say. See\n * `CreateAgentParams.maxRunDurationMs`.\n */\nexport const DEFAULT_MAX_RUN_DURATION_MS = 10 * 60 * 1000;\n\n/**\n * One call per client turn — a first message and an answer to a pending\n * approval take the same path, because they are the same thing: the next turn\n * of a conversation.\n */\nexport type AgentStreamParams = AgentStreamParamsBase & ContextParam;\n\ninterface AgentStreamParamsBase {\n /** Prior turns. The controller loads these from its store, or takes what the\n * client sent when running stateless. */\n messages: AgentMessage[];\n /** The client's turn: text, answers to pending calls, or both. */\n turn?: ClientTurn;\n /** Aborted by an explicit `stop`, not by a disconnect. */\n signal?: AbortSignal;\n runId?: string;\n threadId?: string;\n /** Appended to the agent's own `instructions` for this request only. */\n instructions?: string;\n /**\n * The app's own fields from the turn's request body, handed to every tool of\n * this run as `ctx.body`.\n *\n * Carried on the run because a run outlives the request that started it, so\n * that a refresh can reattach, and by the time a tool executes there is no\n * body left to read. See `AgentController`'s `Body`.\n */\n body?: Record<string, unknown>;\n /** Per-request model choice, e.g. letting a user pick. */\n provider?: AgentProvider;\n maxSteps?: number;\n reasoning?: ReasoningEffort;\n /** Overrides the agent's own for this run. A generation whose size varies by\n * request — a page with ten components against one with two — is the case\n * a fixed ceiling on the agent cannot serve. */\n maxOutputTokens?: number;\n temperature?: number;\n /** Overrides the agent's `maxRunDurationMs` for this run. `null` turns the\n * limit off. */\n maxRunDurationMs?: number | null;\n /**\n * Overrides the agent's `contextWindow` for this run. `false` sends the whole\n * history even when the agent sets one. Not handed down to a sub-run, which\n * uses its own agent's.\n */\n contextWindow?: ContextWindowOptions | false;\n /**\n * Runs after the agent's own `prepareStep`, on what that answered. Not\n * handed down to a sub-run. `AgentController` sets this from its\n * `prepareStep` method.\n */\n prepareStep?: PrepareStep;\n /**\n * Where `contextWindow.compact` keeps this thread's summaries, unless the\n * window names its own `store`. `AgentController` passes its `AgentStore`\n * when that implements the summary methods. Default\n * `defaultSummaryStore`, in memory.\n */\n summaryStore?: SummaryStore;\n /**\n * Fires once for every message this run completes — the user's turn, each\n * assistant turn, and any earlier message this turn amended by resolving a\n * pending call. It is the controller's persistence point, and it fires\n * whether or not anyone is still reading the stream, which is what makes a\n * run that outlives its request useful.\n *\n * A message may be reported twice across runs under the same id when a\n * pending call is resolved later; a store keyed by id should upsert.\n */\n onMessage?: (message: AgentMessage) => void | Promise<void>;\n /**\n * Fires once for the message this run made of the client's `turn` (its text\n * and files), right after `onMessage` has been called for it and before the\n * model is asked anything (#806). Not for an earlier message the turn\n * amended, nor for a file a tool showed, both of which are user messages\n * too: this is how a caller tells the turn itself apart from them. Not\n * called for a turn with no text and no files, or one the run failed before\n * taking in. `AgentController` uses it to call the app's `onMessage` for the\n * turn while the run is still going.\n */\n onTurn?: (message: AgentMessage) => void | Promise<void>;\n /**\n * What a client is told about a failure: the run's `error` frame, and the\n * result of a tool that threw (which the model reads too). Default\n * `redactError`, which keeps the code and replaces any message gemi did not\n * write (a provider's error body, an exception's text) with a fixed\n * sentence, since those carry hostnames, resource names, request ids and\n * connection strings. A tool that throws a `ToolError` keeps its message.\n *\n * Full detail stays server-side: on `result().error`, in the log, and in\n * the controller's `onError`. `AgentController` sets this from its\n * `redactError` method. Handed down unchanged to a sub-run.\n */\n redactError?: ErrorRedactor;\n /**\n * Where the nonces of answered pending calls and re-entered sub-run records\n * are spent, which is what makes a signed answer single-use (#445). Default\n * the process-wide `MemoryNonceStore`: exact for one instance, but with\n * several each would accept a replayed answer once. Give a shared store\n * (`RedisNonceStore`, or your own `NonceStore`) when running more than one.\n * `AgentController` sets this from its `nonces`. Handed down unchanged to a\n * sub-run.\n */\n nonces?: NonceStore;\n /**\n * Where an approved tool's execution is claimed and its result recorded,\n * which is what makes an approval run its tool at most once (#458). Before\n * an approved tool runs, the run claims an id derived from the call the\n * approval covers: a presentation of an approval that already ran gets the\n * recorded result back instead of running the tool again, and one presented\n * while another instance is still running it gets a `tool_error` result.\n * Without a store an approved tool runs as before, guarded by the nonce\n * alone. `AgentController` sets this from its `receipts`. Handed down\n * unchanged to a sub-run.\n */\n receipts?: ReceiptStore;\n /**\n * Who this run is answering: the principal every pending call and parked\n * sub-run record it mints is bound to (#447). An answer, or a record, only\n * verifies on a later run with the same `subject`, so a token lifted from\n * one user's history cannot be spent in another user's turn. `null`, or\n * omitted, is an anonymous run, and only verifies on another anonymous one.\n *\n * `AgentController` sets this from `runOwner` (`user:<id>` by default), so it\n * must answer the same on the turn that asks and the turn that answers.\n * Handed down unchanged to a sub-run.\n */\n subject?: string | null;\n /**\n * The attachment handle every tool of this run is given as `ctx.attachments`.\n *\n * Resolved by the controller from the request — `attachmentsFor(req,\n * threadId)` — and passed in rather than reached for, because the scope is a\n * fact about the caller and the run has no way to derive one. `null`, or\n * omitted, is a request with no subject: the object tools get still exists\n * and every method on it throws a sentence naming `attachmentScope()`.\n *\n * Handed down unchanged to a sub-run started by `ctx.runAgent`. A sub-agent\n * is running on behalf of the same caller — that is the only reason it is\n * allowed to run at all — so it reads and writes the same scope, and a tool\n * three levels down can be given an id its parent parked. Widening it here\n * would be the confused-deputy hole in reverse.\n */\n attachments?: ScopedAttachments | null;\n /**\n * Lets this run's tools start background jobs with `ctx.jobs` (#461).\n * `AgentController` passes it on a threaded turn: a job settles into the\n * thread, so a run with no thread has nowhere to put the result. Without it\n * `ctx.jobs.start` throws `JobsRequireThreadError`. Not handed to sub-runs.\n */\n jobs?: RunJobs;\n /**\n * Set by `ctx.runAgent` and by nothing else.\n *\n * It rides on the public params rather than on a back door because\n * `Agent.stream` is the only way to start a run and a sub-run is a run —\n * giving nesting its own construction path would mean two places where a run\n * is set up, and the second one would drift. Omitted, a run is a root: depth\n * 0, no path, signatures over its own id.\n */\n nesting?: NestedContext;\n}\n\n/**\n * Where a run sits inside a tree of runs. Carried down by `ctx.runAgent`.\n *\n * `signingRunId` and `signingPath` are the reason this is threaded rather than\n * recomputed: a pending call a sub-agent raises is answered by the *client*,\n * which only ever sees the root run, so the token has to be minted under the\n * root's id and the sub-run's path from the start. Re-signing the token at each\n * level on the way up would work too, and would throw away every signature but\n * the outermost one — this way the run that asks the question is also the run\n * that can check the answer, which is where the tool, its schema and its `kind`\n * all already are.\n */\nexport type NestedContext = {\n /** 0 at the root; `ctx.depth` inside a tool of this run. */\n depth: number;\n /** The `maxDepth` of the run at the root of the tree. */\n maxDepth: number;\n /** Agent names from the root down to and including this one, so a cycle can\n * be reported as the chain that caused it. */\n chain: string[];\n /** The root run's id: what a pending call raised here is signed under. */\n signingRunId: string;\n /** Tool-call ids from the root down to the call that started this run. */\n signingPath: string[];\n /**\n * Inherited, and once it is `\"deny\"` it stays `\"deny\"` all the way down. A\n * caller that asked for an autonomous sub-agent must not have a question\n * surface from three levels below it, and the only way to promise that is to\n * make the whole subtree refuse rather than to check at the top.\n */\n onPending: \"escalate\" | \"deny\";\n};\n\n/**\n * Why a run ended with `finishReason: \"error\"`, as the server sees it.\n *\n * The same `code`, `message` and `retryable` as the `error` frame the run put\n * on its stream, plus what only the server should have: the HTTP `status` and\n * the provider's `requestId` when the failure was a response from the\n * provider. Neither is ever written to a frame. A frame is built from this\n * through one method (`redact`), which copies the `AgentError` fields by name,\n * so a field added here stays server-side unless someone puts it there on\n * purpose, and redacts the message (#446, see `redactError`).\n *\n * `message` is the provider's own sentence (\"Unsupported parameter:\n * 'temperature' ...\"), which is what a log needs and why this is kept off the\n * wire in any form richer than the frame already is.\n */\nexport type AgentRunFailure = AgentError & {\n /** The provider's HTTP status, when the failure was a non-2xx response. */\n status?: number;\n /** The provider's request id (`x-request-id`), when it sent one. */\n requestId?: string;\n};\n\nexport type AgentRunResult<T extends ToolShapes, O> = {\n runId: string;\n /** Everything produced this run — the controller persists these. */\n messages: AgentMessage<T, O>[];\n finishReason: FinishReason;\n usage: Usage;\n /** Set when the agent declares an `output` schema and the run finished. */\n output?: O;\n /**\n * Why the run failed. Set exactly when `finishReason` is `\"error\"`, and\n * absent otherwise — an aborted run, `max-steps` and `length` are outcomes,\n * not failures, and carry no error.\n *\n * Before this field a server-side caller that awaited `result()` saw only\n * `finishReason: \"error\"` and no output: the cause was an `error` event on a\n * stream it never read. Pass `result({ throwOnError: true })` to have the run\n * reject with an `AgentRunError` instead.\n */\n error?: AgentRunFailure;\n};\n\nexport type AgentResultOptions = {\n /**\n * Reject with an `AgentRunError` when the run ends with\n * `finishReason: \"error\"`, instead of resolving with `result.error` set.\n * Every other finish reason resolves as usual. Default `false`.\n */\n throwOnError?: boolean;\n};\n\n/**\n * What `result({ throwOnError: true })` rejects with.\n *\n * It carries the whole `result` as well as the error's fields, because a run\n * that failed on step three still produced steps one and two — their messages\n * and their usage are billed and may need persisting — and a rejection that\n * dropped them would make `throwOnError` the lossy way to call `result()`.\n */\nexport class AgentRunError extends Error {\n readonly code: AgentRunFailure[\"code\"];\n readonly retryable: boolean;\n readonly status?: number;\n readonly requestId?: string;\n readonly toolCallId?: string;\n readonly runId: string;\n readonly result: AgentRunResult<ToolShapes, unknown>;\n\n constructor(result: AgentRunResult<ToolShapes, unknown> & { error: AgentRunFailure }) {\n super(result.error.message);\n this.name = \"AgentRunError\";\n this.code = result.error.code;\n this.retryable = result.error.retryable;\n this.status = result.error.status;\n this.requestId = result.error.requestId;\n this.toolCallId = result.error.toolCallId;\n this.runId = result.runId;\n this.result = result;\n }\n}\n\n/**\n * A run is an async iterable of events, and the SSE encoding is a method on it\n * rather than a separate helper — so the same object serves a controller\n * returning a `Response` and a server-side caller that just wants to await the\n * result.\n *\n * A run keeps going when its request ends. That is what makes reattaching after\n * a refresh possible, and it is why `stop()` is an explicit call rather than the\n * client closing a socket.\n */\nexport interface AgentRun<T extends ToolShapes = ToolShapes, O = unknown> extends AsyncIterable<\n AgentStreamEvent<T, O>\n> {\n readonly runId: string;\n /** Numbered events, replayable from a cursor. `toResponse` is this, encoded. */\n frames(from?: number): AsyncIterable<AgentStreamFrame<T, O>>;\n toResponse(params?: { from?: number }): Response;\n /**\n * Settles when the run is over. Resolves for every finish reason, `\"error\"`\n * included, with the cause on `result.error`; pass `{ throwOnError: true }`\n * to reject with an `AgentRunError` for that one instead.\n */\n result(options?: AgentResultOptions): Promise<AgentRunResult<T, O>>;\n /**\n * Cancels the run and closes the conversation behind it: every tool call\n * still in flight gets a `denied` result with `cause: \"stopped\"`, the\n * assistant message is finalized with `finishReason: \"aborted\"`, and both go\n * through `onMessage` like any other message.\n *\n * That last part is the point. A cancel that merely stops emitting leaves a\n * history the provider will reject on the next turn, so the run's last act is\n * to make the transcript valid — which is also what lets the user carry on\n * talking instead of starting over.\n */\n stop(params?: { reason?: string }): void;\n}\n\n/**\n * A tool plus where it sits in the prompt. Fixed for the life of the agent,\n * except `inputSchema`, which a run fills in for a tool whose schema is\n * resolved per run (`ToolInputSchema`).\n */\ntype ResolvedTool = {\n tool: AnyAgentTool;\n namespace?: string;\n deferred: boolean;\n /** `undefined` until the run resolves a per-run schema. */\n inputSchema?: Schema<any>;\n};\n\n/** What a run needs from its agent, resolved once at `Agent.create`. */\ntype RunConfig = {\n name: string;\n instructions?: string;\n provider: AgentProvider;\n registry: Map<string, ResolvedTool>;\n providerTools: (ProviderToolSpec | ProviderToolNamespace)[];\n output?: Schema<any>;\n maxSteps: number;\n maxDepth: number;\n reasoning?: ReasoningEffort;\n maxOutputTokens?: number;\n temperature?: number;\n logErrors: boolean;\n /**\n * As the agent or the stream params gave it, with `Infinity` already folded\n * into `null`. `undefined` is \"not said\", which a root run reads as\n * `DEFAULT_MAX_RUN_DURATION_MS` and a sub-run as no limit of its own.\n */\n maxRunDurationMs: number | null | undefined;\n contextWindow?: ContextWindowOptions;\n /** The agent's hook, then the stream's, in that order. */\n prepareStep: PrepareStep[];\n};\n\nconst DEFAULT_MAX_STEPS = 8;\n/** Three is enough for \"agent, sub-agent, specialist\" and small enough that a\n * runaway tree is a readable error rather than a stack trace. */\nconst DEFAULT_MAX_DEPTH = 3;\n\nexport class Agent<\n T extends readonly ToolEntry[] = readonly ToolEntry[],\n S extends readonly Skill[] = readonly Skill[],\n O extends Schema<any> | undefined = undefined,\n> {\n readonly name: string;\n readonly tools: T;\n readonly skills: S;\n readonly provider: AgentProvider;\n readonly output: O;\n readonly instructions?: string;\n readonly maxSteps: number;\n readonly maxDepth: number;\n readonly reasoning?: ReasoningEffort;\n /**\n * The time limit a run of this agent gets when it is started at the top (a\n * sub-run is bounded by its parent): `DEFAULT_MAX_RUN_DURATION_MS` unless\n * `Agent.create` said otherwise, and `null` for no limit.\n */\n readonly maxRunDurationMs: number | null;\n /** See `CreateAgentParams.jobs`. */\n readonly jobs: AgentJobsOptions;\n\n private readonly config: RunConfig;\n\n private constructor(params: CreateAgentParams<T, S, O>) {\n this.name = params.name;\n this.instructions = params.instructions;\n this.provider = params.provider;\n this.tools = (params.tools ?? ([] as unknown as T)) as T;\n this.skills = (params.skills ?? ([] as unknown as S)) as S;\n this.output = params.output as O;\n this.maxSteps = params.maxSteps ?? DEFAULT_MAX_STEPS;\n this.maxDepth = params.maxDepth ?? DEFAULT_MAX_DEPTH;\n this.reasoning = params.reasoning;\n this.jobs = params.jobs ?? {};\n const limit = normalizeDuration(params.maxRunDurationMs);\n this.maxRunDurationMs = limit === undefined ? DEFAULT_MAX_RUN_DURATION_MS : limit;\n\n const { registry, providerTools } = lowerTools(this.tools, this.skills);\n this.config = {\n name: this.name,\n instructions: this.instructions,\n provider: this.provider,\n registry,\n providerTools,\n output: params.output as Schema<any> | undefined,\n maxSteps: this.maxSteps,\n maxDepth: this.maxDepth,\n reasoning: this.reasoning,\n maxOutputTokens: params.maxOutputTokens,\n temperature: params.temperature,\n logErrors: params.logErrors ?? true,\n maxRunDurationMs: limit,\n contextWindow: params.contextWindow,\n prepareStep: params.prepareStep ? [params.prepareStep] : [],\n };\n }\n\n static create<\n const T extends readonly ToolEntry[],\n const S extends readonly Skill[],\n O extends Schema<any> | undefined = undefined,\n >(params: CreateAgentParams<T, S, O>): Agent<T, S, O> {\n if (params.output) {\n assertObjectRoot(params.output as Schema<any>, `The agent \"${params.name}\"`, \"output\");\n }\n if (params.maxRunDurationMs != null) {\n assertDuration(params.maxRunDurationMs, `The agent \"${params.name}\"`, \"maxRunDurationMs\");\n }\n const block = params.jobs?.contextBlock;\n if (block && block.max !== undefined && !(Number.isInteger(block.max) && block.max > 0)) {\n throw new Error(\n `The agent \"${params.name}\" sets \\`jobs.contextBlock.max\\` to ${String(block.max)}, but it has to be a whole number above 0. Use \\`contextBlock: false\\` for no block.`,\n );\n }\n return new Agent(params);\n }\n\n stream(params: AgentStreamParams): AgentRun<ToolShapesOf<T>, OutputOf<O>> {\n const config: RunConfig = {\n ...this.config,\n provider: params.provider ?? this.config.provider,\n maxSteps: params.maxSteps ?? this.config.maxSteps,\n reasoning: params.reasoning ?? this.config.reasoning,\n maxOutputTokens: params.maxOutputTokens ?? this.config.maxOutputTokens,\n temperature: params.temperature ?? this.config.temperature,\n maxRunDurationMs:\n params.maxRunDurationMs !== undefined\n ? normalizeDuration(params.maxRunDurationMs)\n : this.config.maxRunDurationMs,\n contextWindow:\n params.contextWindow === false\n ? undefined\n : (params.contextWindow ?? this.config.contextWindow),\n prepareStep: params.prepareStep\n ? [...this.config.prepareStep, params.prepareStep]\n : this.config.prepareStep,\n };\n if (params.maxRunDurationMs != null) {\n assertDuration(\n params.maxRunDurationMs,\n `Agent.stream for \"${this.name}\"`,\n \"maxRunDurationMs\",\n );\n }\n return new AgentRunImpl(config, params) as unknown as AgentRun<ToolShapesOf<T>, OutputOf<O>>;\n }\n}\n\nexport type OutputOf<O> = O extends Schema<any> ? Infer<O> : never;\n\nexport type AnyAgent = Agent<any, any, any>;\n\n// --- lowering ------------------------------------------------------------\n\nfunction toolSpec(resolved: ResolvedTool): ProviderToolSpec {\n const schema = resolved.inputSchema;\n return {\n name: resolved.tool.name,\n description: resolved.tool.description,\n // A per-run schema is not known yet; the run swaps this spec for one built\n // from the resolved schema (`AgentRunImpl.resolveToolSchemas`) before the\n // provider ever sees it.\n parameters: schema ? schema.toJSONSchema() : EMPTY_PARAMETERS,\n // Read off the schema, not asserted: an input containing an `s.json()`\n // field cannot be sent strict, and the tool that says so is the only place\n // that knows.\n strict: schema ? supportsStrict(schema) : true,\n deferred: resolved.deferred,\n };\n}\n\n/** The tool's schema when it is fixed, `undefined` when it is resolved per run. */\nfunction staticInputSchema(tool: AnyAgentTool): Schema<any> | undefined {\n return typeof tool.inputSchema === \"function\" ? undefined : tool.inputSchema;\n}\n\n/**\n * Flattens the declared tuple into the registry the loop dispatches on, and the\n * shape the provider is shown.\n *\n * Both are built once, at `Agent.create`, because neither depends on the\n * request: a tool is a singleton and a namespace is a static grouping. Building\n * them per run would be work repeated on every turn for an answer that cannot\n * change — and it would move the name-collision errors below out of startup and\n * into the first user's first message.\n */\nfunction lowerTools(\n entries: readonly ToolEntry[],\n skills: readonly Skill[],\n): {\n registry: Map<string, ResolvedTool>;\n providerTools: (ProviderToolSpec | ProviderToolNamespace)[];\n} {\n const registry = new Map<string, ResolvedTool>();\n const providerTools: (ProviderToolSpec | ProviderToolNamespace)[] = [];\n\n const register = (resolved: ResolvedTool) => {\n if (registry.has(resolved.tool.name)) {\n throw new Error(\n `Two tools are named \"${resolved.tool.name}\". Tool names are global within an agent — the client discriminates a tool part by name alone.`,\n );\n }\n registry.set(resolved.tool.name, resolved);\n };\n\n for (const entry of entries) {\n if (entry instanceof ToolNamespace) {\n if (entry.name === SKILLS_NAMESPACE) {\n throw new Error(\n `\"${SKILLS_NAMESPACE}\" is reserved for the namespace skills are lowered into. Rename the namespace — silently shadowing it would make every skill unreachable with no error to read.`,\n );\n }\n const members: ProviderToolSpec[] = [];\n for (const tool of entry.tools) {\n const resolved = {\n tool,\n namespace: entry.name,\n deferred: entry.deferred || tool.deferred,\n inputSchema: staticInputSchema(tool),\n };\n register(resolved);\n members.push(toolSpec(resolved));\n }\n providerTools.push({ name: entry.name, description: entry.description, tools: members });\n continue;\n }\n const resolved = {\n tool: entry,\n deferred: entry.deferred,\n inputSchema: staticInputSchema(entry),\n };\n register(resolved);\n providerTools.push(toolSpec(resolved));\n }\n\n if (skills.length > 0) {\n const members: ProviderToolSpec[] = [];\n for (const skill of skills) {\n const tool = skillTool(skill);\n register({\n tool,\n namespace: SKILLS_NAMESPACE,\n deferred: false,\n inputSchema: staticInputSchema(tool),\n });\n members.push({\n name: skill.name,\n description: skill.description,\n parameters: EMPTY_PARAMETERS,\n strict: true,\n // Not deferred: the whole cost of a skill in the prompt is its name and\n // description, and those are exactly what deferral keeps. Withholding\n // an empty parameter object saves nothing and adds a round trip.\n deferred: false,\n });\n }\n providerTools.push({\n name: SKILLS_NAMESPACE,\n description: SKILLS_NAMESPACE_DESCRIPTION,\n tools: members,\n });\n }\n\n return { registry, providerTools };\n}\n\n/** The zero-parameter tool a skill becomes. */\nfunction skillTool(skill: Skill): AnyAgentTool {\n return AgentTool.create({\n name: skill.name,\n description: skill.description,\n inputSchema: {\n toJSONSchema: () => EMPTY_PARAMETERS,\n parse: () => ({}),\n safeParse: () => ({ ok: true as const, value: {} }),\n } as unknown as Schema<Record<string, never>>,\n // The thunk is called here, on load, and not at startup: a skill body can\n // be a megabyte of markdown, and an agent that declares twelve of them\n // should not read twelve files to answer \"hello\".\n execute: async () => {\n const body =\n typeof skill.instructions === \"function\" ? await skill.instructions() : skill.instructions;\n const sections = [body];\n for (const file of skill.files ?? []) {\n sections.push(`--- ${file} ---\\n${await readSkillFile(file)}`);\n }\n return sections.join(\"\\n\\n\");\n },\n }) as unknown as AnyAgentTool;\n}\n\nasync function readSkillFile(file: string): Promise<string> {\n try {\n return await Bun.file(file).text();\n } catch (error) {\n // A missing file is told to the model rather than thrown: the rest of the\n // skill is still worth having, and a run should not die because one of\n // several appendices moved.\n return `(could not be read: ${(error as Error).message})`;\n }\n}\n\n// --- the run -------------------------------------------------------------\n\nfunction isAsyncGenerator(value: unknown): value is AsyncGenerator<unknown, unknown, void> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as AsyncGenerator).next === \"function\" &&\n Symbol.asyncIterator in (value as object)\n );\n}\n\ntype StepOutcome = {\n reason: FinishReason;\n error?: AgentError;\n /** The HTTP response behind `error`, when the provider reported one. */\n detail?: { status?: number; requestId?: string };\n};\n\n/**\n * The prior transcript plus what a later run produced, upserted by id.\n *\n * A run only reports the messages it *made*, so a resumed sub-run's\n * `result().messages` is the tail and not the whole thing — and a message it\n * amended (the one holding the call that was finally answered) comes back under\n * an id the prior transcript already has. Appending would duplicate it and\n * replacing the array would lose everything before the resume, so the record on\n * `ToolCallPart.nested` is rebuilt by upsert, which is the same rule a store\n * keyed by message id follows.\n */\nfunction mergeMessages(prior: AgentMessage[], produced: AgentMessage[]): AgentMessage[] {\n const merged = [...prior];\n const index = new Map(merged.map((message, at) => [message.id, at]));\n for (const message of produced) {\n const at = index.get(message.id);\n if (at === undefined) {\n index.set(message.id, merged.length);\n merged.push(message);\n } else {\n merged[at] = message;\n }\n }\n return merged;\n}\n\n/** Tool calls in a transcript with no result anywhere in it. */\nfunction openCallIds(messages: AgentMessage[]): Set<string> {\n const resolved = new Set<string>();\n for (const message of messages) {\n for (const part of message.content) {\n if (part.type === \"tool-result\") resolved.add(part.toolCallId);\n }\n }\n const open = new Set<string>();\n for (const message of messages) {\n for (const part of message.content) {\n if (part.type === \"tool-call\" && !resolved.has(part.toolCallId)) open.add(part.toolCallId);\n }\n }\n return open;\n}\n\n/**\n * A sub-agent's structured answer, read back out of its transcript.\n *\n * `NestedRun` has nowhere to put an `output` — it is a transcript, and the\n * output part is already in it — so a memoized run recovers the value the same\n * way a client would. That keeps the memo honest: what a replay returns is\n * derived from what was persisted, not from a second copy that could disagree\n * with it.\n */\nfunction outputOf(messages: AgentMessage[]): unknown {\n for (let i = messages.length - 1; i >= 0; i--) {\n const content = messages[i].content;\n for (let j = content.length - 1; j >= 0; j--) {\n const part = content[j];\n if (part.type === \"output\" && part.partial !== true) return part.value;\n }\n }\n return undefined;\n}\n\n/** For the replay-mismatch message, where the label is what tells two runs of\n * the same agent apart. */\nfunction describeRun(agent: string, label: string | undefined): string {\n return label === undefined ? `\"${agent}\"` : `\"${agent}\" labelled \"${label}\"`;\n}\n\n/** A message flattened to text, for comparing one turn's seed against another's. */\nfunction textOfMessage(message: AgentMessage): string {\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : `<${part.type}>`))\n .join(\"\");\n}\n\n/**\n * What a `runAgent` call would start its sub-run from, as a comparable string.\n *\n * `null` when the call names no seed at all — `runAgent(agent, {})` — which is\n * the one shape with nothing to compare against, since the record's first\n * message would then be something the sub-agent said rather than something it\n * was told.\n */\nfunction seedOf(params: RunAgentParams): string | null {\n if (params.prompt !== undefined) return `user:${params.prompt}`;\n const first = params.messages?.[0];\n return first ? `${first.role}:${textOfMessage(first)}` : null;\n}\n\n// Moved to `contextWindow.ts`, which splits a thread into turns with it, and\n// re-exported here for the controller and the tests that import it from here.\nexport { injectedMessageIds };\n\n/**\n * How many tool-produced files stay attached to the request. See\n * `AgentRunImpl.historyForProvider`, which is where the reasoning lives.\n */\nconst SHOWN_FILE_WINDOW = 1;\n\n/**\n * Why the Nth attachment of a replayed tool body is not the Nth attachment of\n * the turn that escalated, or `null` when it is.\n *\n * DELIBERATELY WEAKER THAN `replayMismatch`, and the reason is what each of them\n * is protecting. A crossed sub-run pairs a human's answer with a question they\n * never saw, which is consent applied to the wrong thing and is invisible\n * afterwards; a crossed attachment shows the model the wrong picture, which is\n * wrong and is also the sort of wrong the next turn can talk its way out of. So\n * this checks the two things that cannot change for an honest reason and\n * nothing else.\n *\n * Not the size, and not any digest of the bytes: the body that produced this\n * blob ran again from the top and produced it again, and almost nothing that\n * makes an image — a model, a renderer with a timestamp in it, a compressor\n * with a thread pool — is byte-identical twice. Comparing bytes would fail the\n * common case and catch the rare one.\n *\n * Not the name either, for a smaller version of the same reason: filenames\n * carry dates and counters, and an app that names its output\n * `chart-${Date.now()}.png` would find its tool broken on every resume.\n *\n * What is left is the media type and whether the caller asked to show it, which\n * is exactly what changes when a body takes a different branch — the CSV path\n * instead of the PNG path, the quiet `put` instead of the `showModel` one.\n */\nfunction putMismatch(\n recorded: ToolAttachmentPut,\n blob: Blob,\n params: PutAttachmentParams,\n): string | null {\n const mimeType = params.mimeType || blob.type || \"\";\n if (mimeType && recorded.attachment.mimeType !== mimeType) {\n return (\n `was ${JSON.stringify(recorded.attachment.mimeType)} on the turn that escalated ` +\n `and is ${JSON.stringify(mimeType)} on the replay`\n );\n }\n const shown = Boolean(params.showModel);\n if (shown !== Boolean(recorded.shown)) {\n return shown\n ? \"was stored without showModel on the turn that escalated and asks for showModel on the replay\"\n : \"was stored with showModel on the turn that escalated and asks for a plain put on the replay\";\n }\n return null;\n}\n\n/**\n * Why the Nth sub-run of a replayed tool body is not the Nth sub-run of the\n * turn that escalated, or `null` when it is.\n *\n * Agent and label catch the branchy shape. THE SEED IS WHAT CATCHES THE SHAPE\n * THE DOC COMMENT NAMES FIRST: `runAgent` in a loop, the same agent every time,\n * no label — the default and the common case — over a list that came back in a\n * different order, from a `Set`, a re-sorted query, or a second read of a\n * mutable column. Agent and label match for every element of such a loop, so\n * without this the user's answer to the second question is folded into the run\n * the tool now believes is the first, and the model is told the crossed pair as\n * fact. Nothing in the transcript, the stream or the store shows it happened.\n *\n * The record's first message is the seed because `runNested` records it that\n * way — the user turn built from `prompt`, or the first of `params.messages`.\n * `instructions` is not compared: it never enters the transcript, and\n * `NestedRun` has nowhere to keep it.\n */\nfunction replayMismatch(\n recorded: NestedRun,\n agent: AnyAgent,\n params: RunAgentParams,\n): string | null {\n if (recorded.agent !== agent.name || recorded.label !== params.label) {\n return (\n `was ${describeRun(recorded.agent, recorded.label)} on the turn that escalated ` +\n `and is ${describeRun(agent.name, params.label)} on the replay`\n );\n }\n const seed = seedOf(params);\n const first = recorded.messages[0];\n const was = first ? `${first.role}:${textOfMessage(first)}` : null;\n if (seed !== null && was !== null && seed !== was) {\n return (\n `was started with ${JSON.stringify(was)} on the turn that escalated ` +\n `and with ${JSON.stringify(seed)} on the replay`\n );\n }\n return null;\n}\n\n/**\n * What is left of an answer's path once this run's own prefix is removed.\n *\n * `null` means the answer is not addressed to this run at all, which is a\n * client error rather than a routing decision — an empty remainder means \"a\n * call this run made itself\", and a non-empty one names the tool call to\n * re-enter.\n */\nfunction pathBelow(path: string[] | undefined, prefix: string[]): string[] | null {\n const full = path ?? [];\n if (full.length < prefix.length) return null;\n for (let i = 0; i < prefix.length; i++) {\n if (full[i] !== prefix[i]) return null;\n }\n return full.slice(prefix.length);\n}\n\n/**\n * The one memo rule a re-entered tool body plays by, in one place.\n *\n * A tool that escalates cannot be suspended — a paused async generator does not\n * fit in a message history — so it is re-entered FROM THE TOP on the next turn\n * and everything it did the first time has to be recognised rather than done\n * again. The only key available is the order the calls happened in, and the only\n * place a record can live is the message history, because that is the sole state\n * that crosses a turn boundary in a thread and in the browser alike.\n *\n * So: an array on the `ToolCallPart`, a snapshot of its length taken before the\n * body runs (everything already there came from an earlier turn and is\n * replayable; everything appended past that point is happening for the first\n * time), and an index that walks it. `ctx.runAgent` and `ctx.attachments.put`\n * both need exactly this and they share it here rather than each growing their\n * own copy — the failure of two copies is that one of them is fixed and the\n * other is not, and both are invisible until someone resumes.\n *\n * The array is created by the first WRITE and not before. `nested: []` or\n * `attachments: []` on every tool call would be a wire and store change paid for\n * by every app that has neither — and \"on first use\" is not good enough, because\n * a slot is handed out before the work that fills it can fail. A tool whose only\n * `put` throws (no attachment scope, a provider that cannot read files) must\n * leave a tool call with no `attachments` field, not an empty array announcing\n * an attachment that does not exist.\n *\n * A SLOT IS RESERVED WHEN IT IS ASKED FOR, THOUGH, NOT WHEN IT IS FILLED, and\n * that is deliberate: a tool body may run its `put`s or its `runAgent`s\n * concurrently — `await Promise.all(images.map((i) => ctx.attachments.put(i)))`\n * is the obvious way to write it — and every one of them takes its index\n * synchronously, in map order, before its first `await`. Handing out the index\n * on success instead would number them by the order they *finished*, which the\n * network decides and which the next turn will not reproduce. So the index\n * always advances, and a slot whose work threw stays unwritten.\n *\n * An unwritten slot before a written one would be a hole, and a hole is `null`\n * once it goes through JSON — which is what a consumer walking `part.attachments`\n * would crash on. `fill` is what stands in its place. `runAgent` passes none, so\n * `nested` keeps exactly the shape it has had since sub-agents existed, holes\n * and all: `NestedRun` describes a sub-run that happened and has no honest shape\n * for one that did not, and inventing one is a change to nesting rather than to\n * the issue this memo was extracted for.\n *\n * What is NOT shared is what to do with a hit, and it could not be: a recorded\n * sub-run that parked has to be *continued*, so `runAgent`'s memo sometimes\n * returns and sometimes falls through, while a recorded `put` is total — the\n * bytes are already stored and the id is already in the transcript the model\n * read, so there is nothing left to finish. The drift check differs too, and for\n * a reason worth reading: see `replayMismatch` against the note on\n * `putMismatch`.\n */\nclass ReplayMemo<R> {\n private index = 0;\n private readonly replayable: number;\n\n constructor(\n private readonly read: () => R[] | undefined,\n private readonly create: () => R[],\n /** What stands in for a slot whose work threw. See the note above. */\n private readonly fill?: () => R,\n ) {\n this.replayable = read()?.length ?? 0;\n }\n\n /**\n * The next slot: its index, the record a previous turn left there if it left\n * one, and the way to write this turn's.\n *\n * `write` is the only thing that touches the array. Call it once the record\n * exists and not before — everything between `next()` and `write()` is work\n * that may throw, and a slot nobody writes is a slot that costs nothing.\n */\n next(): { at: number; recorded: R | undefined; write: (record: R) => void } {\n const at = this.index++;\n return {\n at,\n recorded: at < this.replayable ? this.read()?.[at] : undefined,\n write: (record: R) => {\n const rows = this.read() ?? this.create();\n if (this.fill) {\n for (let i = rows.length; i < at; i++) rows[i] = this.fill();\n }\n rows[at] = record;\n },\n };\n }\n}\n\nclass AgentRunImpl implements AgentRun<ToolShapes, unknown> {\n readonly runId: string;\n\n /** Replaced once, by `resolveToolSchemas`, when the agent has per-run tool schemas. */\n private config: RunConfig;\n private readonly params: AgentStreamParams;\n /** `params.context`, or `{}` for a run started without one. See `AgentContext`. */\n private readonly context: AgentContext;\n private readonly controller = new AbortController();\n\n private readonly buffer: AgentStreamFrame<ToolShapes, unknown>[] = [];\n private readonly waiters = new Set<() => void>();\n private seq = 0;\n private ended = false;\n\n /** The working history handed to the provider, and what this run produced. */\n private history: AgentMessage[] = [];\n /** `contextWindow.compact`'s summaries for this run, by cut. */\n private readonly compactMemo = new Map<string, ThreadSummary | null>();\n /** How the previous model call ended, for `prepareStep`. */\n private lastStep: { reason: FinishReason; usage?: Usage } | undefined;\n private produced: AgentMessage[] = [];\n private current: AgentMessage | null = null;\n /**\n * Whether a step of the message now open ran out of output budget.\n *\n * Separate from `finishReason` because they are different facts: a step that\n * hits the ceiling and also calls a tool closes its message `awaiting-input` or\n * `max-steps`. Cleared as each message is finalized.\n */\n private outputTruncated = false;\n\n /** Messages from an earlier run this one has amended, by id. Cloned once and\n * reused, so two results for the same message do not fork it. */\n private readonly amended = new Map<string, AgentMessage>();\n /**\n * Messages this run finished outside `finalizeMessage` that have not yet gone\n * through `onMessage`: earlier turns' messages it amended, and messages it\n * injected for a file a tool showed.\n *\n * They wait rather than being reported where they are made, because\n * `onMessage` is the persistence point for an app that has no `store` and an\n * append-only table keyed by a serial id reads back in the order the hook was\n * called. Reporting an injected message from inside `runTools` would call the\n * hook for it BEFORE the assistant message whose tool call produced it, since\n * that message is only finalized once the step is over — so the transcript in\n * the app's database would put the file above the turn that made it, while\n * `result.messages`, the stream and `history` all put it below.\n */\n private readonly unreported = new Set<AgentMessage>();\n\n private usage: Usage = emptyUsage();\n private finishReason: FinishReason = \"stop\";\n /** Set by `fail`, and only there: the cause of a run that ends `\"error\"`. */\n private failure: AgentRunFailure | undefined;\n private output: unknown;\n private stopReason: string | undefined;\n /**\n * The limit that stopped this run, when it was `maxRunDurationMs` rather\n * than `stop()` that did. Read by the abort path, which is shared: a run that\n * ran out of time is closed exactly like a stopped one, and only its finish\n * reason and its `error` differ.\n */\n private timedOutAfter: number | undefined;\n /** Clears the `maxRunDurationMs` timer. A no-op for a run without one. */\n private cancelDeadline: () => void = () => {};\n\n private readonly settled: Promise<AgentRunResult<ToolShapes, unknown>>;\n\n /**\n * Where this run sits in a tree of runs, all of it constant for the run.\n *\n * `signingRunId` is the *root's* id rather than this one's: the client only\n * ever sees the root run, so a question a sub-agent asks has to travel under\n * an id the client can hand back. `pathPrefix` is the chain of tool calls\n * above this run, and it is both what a pending call raised here is signed\n * over and what an answer coming back is matched against.\n */\n private readonly depth: number;\n private readonly maxDepth: number;\n private readonly chain: string[];\n private readonly signingRunId: string;\n private readonly pathPrefix: string[];\n private readonly onPending: \"escalate\" | \"deny\";\n /**\n * Sub-runs that have not yet written their transcript to the tool call.\n *\n * The abort path waits on these. A `stop()` reaches a sub-run through the\n * shared signal, so it is already closing — but `raceAbort` in `runTools`\n * returns the moment the signal fires, which would finalize and persist the\n * parent's message before the sub-run had recorded what it managed to do.\n * The work would be on the stream and missing from the store.\n */\n private readonly nestedSettling = new Set<Promise<unknown>>();\n /**\n * Messages for files a tool asked to show, held until its call settles, keyed\n * by tool call id. See `queueShown`.\n */\n private readonly shownQueue = new Map<string, AgentMessage[]>();\n\n constructor(config: RunConfig, params: AgentStreamParams) {\n this.config = config;\n this.params = params;\n // Cast because an app whose `AgentContext` has required fields makes `{}`\n // unassignable here — and such an app cannot reach this default, since\n // `ContextParam` makes it pass one.\n this.context = params.context ?? ({} as AgentContext);\n this.runId = params.runId ?? `run_${crypto.randomUUID()}`;\n this.history = [...params.messages];\n\n const nesting = params.nesting;\n this.depth = nesting?.depth ?? 0;\n this.maxDepth = nesting?.maxDepth ?? config.maxDepth;\n this.chain = nesting?.chain ?? [config.name];\n this.signingRunId = nesting?.signingRunId ?? this.runId;\n this.pathPrefix = nesting?.signingPath ?? [];\n this.onPending = nesting?.onPending ?? \"escalate\";\n\n if (params.signal) {\n if (params.signal.aborted) this.controller.abort();\n else params.signal.addEventListener(\"abort\", () => this.stop(), { once: true });\n }\n\n // The root's default, not a sub-run's: a sub-run shares its parent's\n // signal, so the parent's deadline already reaches it, and a default of its\n // own would cut short a parent that was deliberately given longer.\n const limit =\n config.maxRunDurationMs !== undefined\n ? config.maxRunDurationMs\n : nesting\n ? null\n : DEFAULT_MAX_RUN_DURATION_MS;\n this.cancelDeadline = startTimer(limit, () => this.expire(limit!));\n\n // Started here, not on first read. A run outlives the request that began\n // it, so nothing may depend on someone being attached — a client that\n // never reads still gets its tools run and its messages persisted.\n this.settled = this.execute();\n // And a request that started it stays open until it settles. A tool may\n // still read ambient request state — `Auth.user()`, a policied query — and\n // a client that leaves mid-run cancels the response body without stopping\n // the run; ending the request there would take the user away from step\n // four's tool call. Read ambiently rather than from a param because a run\n // need not come from a request at all: in a job or a script there is no\n // store, and nothing to hold open.\n RequestContext.getStore()?.waitUntil(this.settled);\n }\n\n // --- event plumbing ----------------------------------------------------\n\n private emit(event: AgentStreamEvent<ToolShapes, unknown>) {\n if (this.ended) return;\n this.buffer.push({ seq: ++this.seq, event });\n this.wake();\n }\n\n private wake() {\n const pending = [...this.waiters];\n this.waiters.clear();\n for (const resolve of pending) resolve();\n }\n\n private nextFrame(): Promise<void> {\n return new Promise<void>((resolve) => this.waiters.add(resolve));\n }\n\n /**\n * Replays from the buffer, then follows the run live.\n *\n * The whole run is buffered rather than a sliding window: a run is bounded by\n * `maxSteps`, and a client that reconnects two steps late wanting frame 42\n * must get frame 42 and not \"the oldest I still have\". Bounding it is the\n * live-run registry's job, where the policy question is how long a *finished*\n * run is kept.\n */\n async *frames(from = 0): AsyncIterable<AgentStreamFrame<ToolShapes, unknown>> {\n let index = from > 0 ? from - 1 : 0;\n for (;;) {\n while (index < this.buffer.length) {\n yield this.buffer[index++];\n }\n if (this.ended) return;\n await this.nextFrame();\n }\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<AgentStreamEvent<ToolShapes, unknown>> {\n for await (const frame of this.frames()) {\n yield frame.event;\n }\n }\n\n toResponse(params?: { from?: number }): Response {\n const frames = this.frames(params?.from);\n const encoder = new TextEncoder();\n let cancelled = false;\n\n let keepalive!: ReturnType<typeof sseKeepalive>;\n\n const body = new ReadableStream<Uint8Array>({\n start: async (controller) => {\n // A slow tool or a thinking sub-agent can leave the connection silent\n // for longer than a proxy's idle timeout, and a proxy that closes it\n // looks to the client exactly like a run that finished.\n keepalive = sseKeepalive(controller);\n try {\n for await (const frame of frames) {\n if (cancelled) break;\n // `id:` carries the cursor so a browser reconnecting with\n // `Last-Event-ID` is already asking the right question.\n controller.enqueue(\n encoder.encode(`id: ${frame.seq}\\ndata: ${JSON.stringify(frame.event)}\\n\\n`),\n );\n keepalive.touch();\n }\n } catch {\n // A stream that cannot be written to is a dead reader, not a dead\n // run. Nothing to report and nothing to stop.\n }\n keepalive.stop();\n try {\n controller.close();\n } catch {\n // already closed by a cancel\n }\n },\n cancel: () => {\n // Deliberately does not touch the run. A disconnect is a reader\n // leaving; `stop()` is the only thing that cancels work, because the\n // tool loop is here and a closed tab has not stopped step four from\n // charging a card.\n cancelled = true;\n keepalive.stop();\n },\n });\n\n return new Response(body, {\n headers: {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n // Tells nginx not to buffer, which would otherwise hold every frame\n // until the response ended and make a stream look like a long pause.\n \"X-Accel-Buffering\": \"no\",\n },\n });\n }\n\n result(options?: AgentResultOptions): Promise<AgentRunResult<ToolShapes, unknown>> {\n if (!options?.throwOnError) return this.settled;\n return this.settled.then((result) => {\n if (result.error) throw new AgentRunError({ ...result, error: result.error });\n return result;\n });\n }\n\n stop(params?: { reason?: string }): void {\n if (this.ended || this.controller.signal.aborted) return;\n this.stopReason = params?.reason;\n this.controller.abort();\n }\n\n /**\n * `maxRunDurationMs` ran out. Stopped through the same controller as\n * `stop()`, so everything that already honours a stop (the provider request,\n * `raceAbort` around the tools, `ctx.signal`, sub-runs) honours this too.\n * The difference is only in how the run ends: see `finalizeAborted`.\n */\n private expire(limit: number): void {\n if (this.ended || this.controller.signal.aborted) return;\n this.timedOutAfter = limit;\n this.stopReason = `The run reached its time limit of ${formatDuration(limit)} and was stopped.`;\n this.controller.abort(new DOMException(this.stopReason, \"TimeoutError\"));\n }\n\n // --- the loop ----------------------------------------------------------\n\n private async execute(): Promise<AgentRunResult<ToolShapes, unknown>> {\n this.emit({ type: \"run-start\", runId: this.runId, threadId: this.params.threadId });\n\n try {\n // First, because everything after it reads a tool's schema: re-entering\n // a parked call below validates its input, and the model is shown them.\n const unresolved = await this.resolveToolSchemas();\n // A turn that answers a sub-agent's question re-enters the tool that\n // asked it, and that tool may ask again — so the run can be finished\n // before it has taken a single model step. Going on to `loop()` here\n // would step the model with a tool call still open, which is exactly the\n // history the provider rejects.\n const escalated = unresolved ? [] : await this.ingestTurn();\n if (unresolved) {\n this.fail(unresolved);\n this.finishReason = \"error\";\n } else if (escalated.length > 0) {\n this.finishReason = \"awaiting-input\";\n this.emit({ type: \"awaiting-input\", runId: this.runId, pending: escalated });\n } else {\n await this.loop();\n }\n } catch (error) {\n if (error instanceof RunAborted || this.controller.signal.aborted) {\n await this.finalizeAborted();\n } else {\n this.fail(this.config.provider.normalizeError(error), httpErrorDetail(error));\n await this.finalizeMessage(\"error\");\n this.finishReason = \"error\";\n }\n }\n this.cancelDeadline();\n\n this.emit({ type: \"usage\", usage: this.usage });\n this.emit({ type: \"run-end\", runId: this.runId, finishReason: this.finishReason });\n this.ended = true;\n this.wake();\n // After the turn, not in it: the run's usage is final, and the summary\n // is billed to the next run that uses it.\n this.precompact();\n\n const failure = this.finishReason === \"error\" ? this.failure : undefined;\n if (failure && this.config.logErrors) this.logFailure(failure);\n\n return {\n runId: this.runId,\n messages: this.produced as AgentMessage<ToolShapes, unknown>[],\n finishReason: this.finishReason,\n usage: this.usage,\n output: this.output,\n // Only when there is one, so a successful result has the same keys it\n // always had.\n ...(failure ? { error: failure } : {}),\n };\n }\n\n /**\n * Resolves the per-run input schemas (`ToolInputSchema`'s function form) and\n * swaps them into this run's registry and provider tool list. A no-op for\n * an agent whose tool schemas are all fixed, which is the common case.\n *\n * Returns the run's error when a resolver throws or returns a schema the\n * provider cannot take; the caller fails the run with it. Its message names\n * the tool and the cause — server-side only, since the client's copy is\n * redacted like any `tool_error`. The run fails before the turn is ingested,\n * so a client turn it carried is not reported to `onMessage`.\n */\n private async resolveToolSchemas(): Promise<AgentError | undefined> {\n const pending = [...this.config.registry.values()].filter((entry) => !entry.inputSchema);\n if (pending.length === 0) return undefined;\n const ctx: ToolSchemaContext = {\n context: this.context,\n body: this.params.body ?? {},\n runId: this.runId,\n threadId: this.params.threadId,\n signal: this.controller.signal,\n };\n const schemas = new Map<string, Schema<any>>();\n const failures = await Promise.all(\n pending.map(async (entry) => {\n try {\n const resolve = entry.tool.inputSchema as (\n ctx: ToolSchemaContext,\n ) => Schema<any> | Promise<Schema<any>>;\n const schema = await resolve(ctx);\n assertObjectRoot(schema, `The tool \"${entry.tool.name}\"`, \"inputSchema\");\n schemas.set(entry.tool.name, schema);\n return undefined;\n } catch (error) {\n return `\"${entry.tool.name}\": ${error instanceof Error ? error.message : String(error)}`;\n }\n }),\n );\n if (this.controller.signal.aborted) throw new RunAborted();\n const failed = failures.filter((failure) => failure !== undefined);\n if (failed.length > 0) {\n return {\n code: \"tool_error\",\n message: `Could not resolve the input schema of ${failed.join(\"; \")}`,\n retryable: false,\n };\n }\n\n const registry = new Map<string, ResolvedTool>();\n for (const [name, entry] of this.config.registry) {\n registry.set(name, schemas.has(name) ? { ...entry, inputSchema: schemas.get(name) } : entry);\n }\n const swap = (spec: ProviderToolSpec): ProviderToolSpec =>\n schemas.has(spec.name) ? toolSpec(registry.get(spec.name)!) : spec;\n const providerTools = this.config.providerTools.map((tool) =>\n \"tools\" in tool ? { ...tool, tools: tool.tools.map(swap) } : swap(tool),\n );\n this.config = { ...this.config, registry, providerTools };\n return undefined;\n }\n\n /**\n * Records why the run is failing and puts the client's copy on the stream.\n *\n * The two are built apart on purpose. `failure` is the server's record —\n * what `result().error` returns and what is logged — and carries the HTTP\n * status and request id of the provider's response, when there was one.\n * The frame gets the redacted copy (`redact`): the `AgentError` fields\n * only, named one by one so a field added to `AgentRunFailure` cannot reach\n * a browser by accident, and a message gemi did not write replaced (#446).\n */\n private fail(error: AgentError, detail: { status?: number; requestId?: string } = {}): void {\n const failure: AgentRunFailure = { ...error, ...detail };\n this.failure = failure;\n this.emit({ type: \"error\", error: this.redact(failure, { source: \"run\", failure }) });\n }\n\n /**\n * The one place an error is redacted for the client, through the app's\n * `redactError` or the default. The original is remembered against the\n * copy so the controller's `onError`, which hears the frame in this\n * process, still gets the full detail.\n */\n private redact(error: AgentError, info: Parameters<ErrorRedactor>[1]): AgentError {\n const redacted = applyRedaction(this.params.redactError, error, info, (err) =>\n this.writeLog(`[gemi/ai] agent \"${this.config.name}\" redactError threw`, { error: err }),\n );\n rememberUnredacted(redacted, error);\n return redacted;\n }\n\n /**\n * Through the app's logger, so it lands in `storage/logs` and `onLogCreated`.\n *\n * Outside an application — a script, a test, a run started before boot —\n * there is no logger to resolve, and `Log.error` throws on the lookup. That\n * case falls back to `console.error` rather than being dropped, since the\n * point of this is that a failed run is never silent. In development it goes\n * to the console as well, because `gemi dev` does not print the log file and\n * the terminal is where a developer is looking.\n */\n private logFailure(failure: AgentRunFailure): void {\n const message = `[gemi/ai] agent \"${this.config.name}\" run failed (${failure.code}${\n failure.status !== undefined ? ` ${failure.status}` : \"\"\n }): ${failure.message}`;\n this.writeLog(message, { error: failure });\n }\n\n /**\n * A tool that threw something other than a `ToolError`. The model and the\n * client are only told that it failed (see `redactError`), so this is the\n * one place its message and stack survive.\n */\n private logToolFailure(call: ToolCallPart, error: unknown): void {\n const text = error instanceof Error ? error.message : String(error);\n this.writeLog(\n `[gemi/ai] agent \"${this.config.name}\" tool \"${String(call.name)}\" threw: ${text}`,\n { toolCallId: call.toolCallId, error },\n );\n }\n\n private writeLog(message: string, extra: Record<string, unknown>): void {\n const metadata = {\n agent: this.config.name,\n runId: this.runId,\n ...(this.params.threadId ? { threadId: this.params.threadId } : {}),\n ...(this.depth > 0 ? { chain: this.chain } : {}),\n ...extra,\n };\n let logged = false;\n try {\n Log.error(message, metadata);\n logged = true;\n } catch {\n // No application to resolve a logger from. Reported below instead.\n }\n if (!logged || process.env.NODE_ENV === \"development\") {\n console.error(message, metadata);\n }\n }\n\n private async loop(): Promise<void> {\n const maxSteps = Math.max(1, this.config.maxSteps);\n\n for (let step = 1; step <= maxSteps; step++) {\n const message = this.startMessage();\n const outcome = await this.runStep(message, step);\n this.lastStep = { reason: outcome.reason, usage: message.usage };\n\n if (outcome.error) {\n this.fail(outcome.error, outcome.detail);\n await this.finalizeMessage(\"error\");\n this.finishReason = \"error\";\n return;\n }\n\n const calls = message.content.filter(\n (part): part is ToolCallPart => part.type === \"tool-call\",\n );\n\n if (calls.length === 0) {\n this.finishReason = outcome.reason;\n await this.finalizeMessage(outcome.reason);\n return;\n }\n\n const pending = await this.runTools(message, calls, step);\n\n if (pending.length > 0) {\n // The message closes first, then the run says what it is waiting for:\n // `awaiting-input` is terminal, and everything needed to answer it has\n // to already be on the stream when it arrives.\n this.finishReason = \"awaiting-input\";\n await this.finalizeMessage(\"awaiting-input\");\n this.emit({ type: \"awaiting-input\", runId: this.runId, pending });\n return;\n }\n\n if (step === maxSteps) {\n // Not an exception. An agent that will not stop calling tools is a bug\n // the app has to be able to see and show, and a throw here would put it\n // in a log instead of in the transcript.\n this.finishReason = \"max-steps\";\n await this.finalizeMessage(\"max-steps\");\n return;\n }\n\n await this.finalizeMessage(outcome.reason);\n }\n }\n\n private startMessage(): AgentMessage {\n const message: AgentMessage = {\n id: `msg_${crypto.randomUUID()}`,\n role: \"assistant\",\n content: [],\n createdAt: new Date().toISOString(),\n };\n this.current = message;\n this.history.push(message);\n this.produced.push(message);\n this.emit({ type: \"message-start\", messageId: message.id, role: \"assistant\" });\n return message;\n }\n\n private async finalizeMessage(reason: FinishReason): Promise<void> {\n const message = this.current;\n if (!message) return;\n this.current = null;\n // Read and cleared together: it describes the message being closed, and the\n // next one starts with no opinion.\n const outputTruncated = this.outputTruncated;\n this.outputTruncated = false;\n message.finishReason = reason;\n // On the message and not only on the frame. The frame reaches a live client,\n // which is half the audience: `onMessage` persists this object and\n // `result().messages` hands it back, and a transcript restored through\n // `useChat({ initialMessages })` has nothing else to read. `finishReason`\n // cannot answer it — a step that ran out of budget while calling a tool\n // closes `awaiting-input`, which is the case this exists for.\n if (outputTruncated) message.outputTruncated = true;\n // Before the message is handed to `onMessage` to be persisted and before it\n // reaches `result()` — the two places it stops being written and starts\n // being kept. Every exit lands here, aborted and errored runs included.\n for (const part of message.content) {\n if (part.type === \"text\" || part.type === \"reasoning\") {\n if (typeof part.text === \"string\") part.text = resolveRope(part.text);\n }\n }\n this.emit({\n type: \"message-end\",\n messageId: message.id,\n finishReason: reason,\n // Only when true, so the frame an ordinary message ends with is unchanged.\n ...(outputTruncated ? { outputTruncated: true as const } : {}),\n // The model call's usage for this message alone (#467). Absent when the\n // call never reported one — aborted mid-stream, or a provider that sent\n // no terminal frame — rather than a zero that reads as \"free\".\n ...(message.usage ? { usage: message.usage } : {}),\n });\n await this.report(message);\n // After it, never before: a file a tool showed during this message belongs\n // below the message whose tool call produced it, in the hook exactly as it\n // is in `result().messages` and on the stream. Empty on every step of a run\n // with no such file, which is most of them.\n await this.reportDeferred();\n }\n\n private async report(message: AgentMessage): Promise<void> {\n if (!this.params.onMessage) return;\n try {\n await this.params.onMessage(message);\n } catch {\n // Persistence failing must not take the transcript with it: the messages\n // are still on the stream and still in `result()`.\n }\n }\n\n // --- one model call ----------------------------------------------------\n\n private async runStep(message: AgentMessage, step: number): Promise<StepOutcome> {\n const signal = this.controller.signal;\n const provider = this.config.provider;\n\n const request = await this.prepareRequest(message, step);\n if (\"error\" in request) return { reason: \"error\", error: request.error };\n\n let outcome: StepOutcome = { reason: \"stop\" };\n const partialArgs = new Map<string, { name: string; args: string; namespace?: string }>();\n // Searches the model ran in this step, waiting for the call that follows\n // them. See `ToolCallPart.toolSearches` for why they are kept at all.\n let searches: ToolSearchRecord[] = [];\n const takeSearches = (): { toolSearches?: ToolSearchRecord[] } => {\n if (searches.length === 0) return {};\n const taken = searches;\n searches = [];\n return { toolSearches: taken };\n };\n let outputText = \"\";\n\n const stream = provider.stream({\n // Not `this.history` directly: an image a tool showed is in the history\n // forever and must not be in every *request* forever, and a long thread\n // is cut to the context window. See `prepareRequest`.\n messages: request.messages,\n systemPrompt: request.instructions,\n tools: this.config.providerTools.length > 0 ? this.config.providerTools : undefined,\n output: this.config.output ? outputFormat(this.config.output) : undefined,\n reasoning: this.config.reasoning,\n maxOutputTokens: this.config.maxOutputTokens,\n temperature: this.config.temperature,\n signal,\n });\n\n const iterator = stream[Symbol.asyncIterator]();\n for (;;) {\n const next = await raceAbort(Promise.resolve(iterator.next()), signal);\n if (next.done) break;\n const event = next.value;\n\n switch (event.type) {\n case \"text-delta\": {\n appendText(message, \"text\", event.delta);\n this.emit({ type: \"text-delta\", messageId: message.id, delta: event.delta });\n break;\n }\n case \"reasoning-delta\": {\n appendReasoning(message, event.id, event.delta);\n this.emit({\n type: \"reasoning-delta\",\n messageId: message.id,\n delta: event.delta,\n id: event.id,\n });\n break;\n }\n case \"output-delta\": {\n outputText += event.delta;\n this.emit({\n type: \"output-delta\",\n messageId: message.id,\n delta: event.delta,\n snapshot: bestEffortParse(outputText),\n });\n break;\n }\n case \"tool-search\": {\n searches.push({\n namespaces: event.namespaces,\n loaded: event.loaded,\n ...(event.arguments !== undefined ? { arguments: event.arguments } : {}),\n });\n this.emit({ type: \"tool-search\", loaded: event.loaded });\n break;\n }\n case \"tool-call-delta\": {\n const held: { name: string; args: string; namespace?: string } = partialArgs.get(\n event.toolCallId,\n ) ?? { name: event.name, args: \"\" };\n held.args += event.argsDelta;\n held.name = event.name || held.name;\n held.namespace = event.namespace || held.namespace;\n partialArgs.set(event.toolCallId, held);\n this.emit({\n type: \"tool-call\",\n messageId: message.id,\n part: {\n type: \"tool-call\",\n toolCallId: event.toolCallId,\n name: held.name,\n input: bestEffortParse(held.args),\n partial: true,\n ...(held.namespace ? { namespace: held.namespace } : {}),\n },\n });\n break;\n }\n case \"tool-call\": {\n const namespace = event.namespace || partialArgs.get(event.toolCallId)?.namespace;\n partialArgs.delete(event.toolCallId);\n const part: ToolCallPart = {\n type: \"tool-call\",\n toolCallId: event.toolCallId,\n name: event.name,\n // A raw string when the model produced something that is not JSON.\n // Keeping it is what makes the `invalid_tool_input` result below\n // readable instead of an empty object nobody can explain.\n input: parseArgs(event.args),\n // Both are for the provider, which has to replay the call the way\n // the model made it (#776).\n ...(namespace ? { namespace } : {}),\n ...takeSearches(),\n };\n message.content.push(part);\n this.emit({ type: \"tool-call\", messageId: message.id, part });\n break;\n }\n case \"finish\": {\n this.usage = addUsage(this.usage, event.usage);\n // This step's own cost, on the message the step wrote (#467). The run\n // total above is the whole turn — every step plus tools' sub-runs,\n // `generate()` calls and images — and putting it on the last message\n // showed a three-step run's every token on step three. Added rather\n // than assigned in case a provider ever closes a call with more than\n // one finish frame.\n message.usage = addUsage(message.usage ?? emptyUsage(), event.usage);\n // The usage is taken either way, the reason only if nothing has\n // already failed. A provider is allowed to report an error and then\n // close the call with a finish frame — a content filter does exactly\n // that, and it still bills for the tokens — and letting the closing\n // frame overwrite the outcome would turn \"blocked\" into an empty\n // answer with no explanation anywhere.\n if (!outcome.error) outcome = { reason: event.reason };\n break;\n }\n case \"error\": {\n outcome = {\n reason: \"error\",\n error: event.error,\n detail: httpErrorDetail(event),\n };\n break;\n }\n case \"file-rejected\": {\n this.markFileRejected(event.fileId, event.message, httpErrorDetail(event));\n break;\n }\n }\n }\n\n // A tool call whose arguments never finished arriving. It is still a call\n // the model made, so it gets a part and, below, an `invalid_tool_input`\n // result — dropping it would leave the model unable to see what went wrong.\n for (const [toolCallId, held] of partialArgs) {\n const part: ToolCallPart = {\n type: \"tool-call\",\n toolCallId,\n name: held.name,\n input: parseArgs(held.args),\n ...(held.namespace ? { namespace: held.namespace } : {}),\n ...takeSearches(),\n };\n message.content.push(part);\n this.emit({ type: \"tool-call\", messageId: message.id, part });\n }\n\n // `length` is excluded, and it is the reason `maxOutputTokens` is worth\n // having at all. A cut-off answer is a prefix of the JSON the model meant\n // to write, and `bestEffortParse` closes whatever brackets are open — so a\n // truncated document arrives at `safeParse` looking like a whole one. For\n // a schema of `s.json()` fields it then *passes*, and the app is handed a\n // half-written page with nothing to distinguish it from a finished one.\n //\n // So a run that hit the ceiling produces no `output` part and ends with\n // `finishReason: \"length\"`, which is the channel for \"not an error, and not\n // a finished answer\" — the argument `max-steps` already makes in the\n // `FinishReason` type.\n //\n // No error is emitted, and that is a deliberate change rather than a\n // consequence of the cap. `length` does not mean the app set one: the\n // provider reports it from the model's own ceiling too, which is how this\n // was reachable before `maxOutputTokens` existed at all. Before this, a\n // truncated run fell through to `safeParse`, and a schema with required\n // keys among the missing ones failed it and raised a schema-mismatch error.\n // That diagnostic is gone on purpose — it described the truncation as a\n // model mistake, and it never fired for a schema loose enough to accept the\n // repaired prefix, which is the case that actually needed saying. What\n // replaces it is one answer for every schema: no output, and a finish\n // reason that says why.\n const truncated = outcome.reason === \"length\";\n // Recorded on the run rather than inferred from the message's finish reason,\n // which is not this: a step that hits the ceiling and also calls a tool ends\n // the message `awaiting-input` or `max-steps`. The client needs the fact\n // itself, or it completes a partial output the server withheld.\n if (truncated) this.outputTruncated = true;\n if (this.config.output && outputText && !outcome.error && !truncated) {\n const parsed = parseOutput(this.config.output, outputText);\n if (parsed.ok === true) {\n this.output = parsed.value;\n message.content.push({ type: \"output\", value: parsed.value });\n } else {\n this.emit({ type: \"error\", error: parsed.error });\n }\n }\n\n return outcome;\n }\n\n /**\n * What `contextWindow.compact` works from on this run, or `undefined` when\n * the run isn't compacted: compaction needs a stored thread (`threadId`) to\n * key summaries on, so stateless runs and sub-runs get the plain window.\n */\n private compactJobParams(\n history: AgentMessage[],\n current: AgentMessage | undefined,\n ): CompactJobParams | undefined {\n const window = this.config.contextWindow;\n if (!window?.compact || !this.params.threadId || this.depth !== 0) return undefined;\n const compact = window.compact === true ? {} : window.compact;\n return {\n history,\n stored: this.history.filter((message) => message !== current),\n window,\n compact,\n threadId: this.params.threadId,\n provider: this.config.provider,\n store: compact.store || this.params.summaryStore || defaultSummaryStore,\n };\n }\n\n /**\n * Starts the summary the thread's next turn will need, without waiting on\n * it (`ContextCompactOptions.background`). Never fails the run.\n */\n private precompact(): void {\n const window = this.config.contextWindow;\n if (!window?.compact || (window.compact !== true && window.compact.background === false)) {\n return;\n }\n try {\n const params = this.compactJobParams(this.historyForProvider(undefined), undefined);\n if (params) void precompactWindow(params);\n } catch {\n // Best effort: the next turn makes it inline.\n }\n }\n\n /**\n * What one model call is sent: the history as `historyForProvider` shapes\n * it, cut to `contextWindow`, then whatever the `prepareStep` hooks answer.\n *\n * Nothing here touches `this.history`. The hooks are handed copies of the\n * arrays, and what they answer is used for this call only, so the next step\n * starts from the whole history again and the store is never told about a\n * window.\n */\n private async prepareRequest(\n current: AgentMessage,\n step: number,\n ): Promise<{ messages: AgentMessage[]; instructions: string | undefined } | { error: AgentError }> {\n const history = this.historyForProvider(current);\n const window = this.config.contextWindow;\n const compact = this.compactJobParams(history, current);\n let messages = !window\n ? history\n : compact\n ? await compactWindow({\n ...compact,\n signal: this.controller.signal,\n // Billed whether or not the summary came out, as `ctx.generate` is.\n onUsage: (usage) => {\n this.usage = addUsage(this.usage, usage);\n },\n memo: this.compactMemo,\n })\n : windowMessages(history, window).messages;\n let instructions = await this.systemPrompt();\n\n for (const hook of this.config.prepareStep) {\n let answer: PrepareStepResult | void;\n try {\n answer = await hook({\n step,\n messages: [...messages],\n history: [...history],\n instructions,\n usage: this.usage,\n ...(this.lastStep?.usage ? { lastStepUsage: this.lastStep.usage } : {}),\n ...(this.lastStep ? { lastFinishReason: this.lastStep.reason } : {}),\n runId: this.runId,\n threadId: this.params.threadId,\n agent: this.config.name,\n depth: this.depth,\n context: this.context,\n signal: this.controller.signal,\n });\n } catch (error) {\n if (error instanceof RunAborted || this.controller.signal.aborted) throw error;\n const text = error instanceof Error ? error.message : String(error);\n return {\n error: { code: \"unknown\", message: `prepareStep threw: ${text}`, retryable: false },\n };\n }\n if (!answer) continue;\n if (answer.messages !== undefined) {\n if (!Array.isArray(answer.messages)) {\n return {\n error: {\n code: \"unknown\",\n message: \"prepareStep answered `messages` that is not an array.\",\n retryable: false,\n },\n };\n }\n messages = answer.messages;\n }\n if (answer.instructions !== undefined) instructions = answer.instructions || undefined;\n }\n\n return { messages, instructions };\n }\n\n private async systemPrompt(): Promise<string | undefined> {\n const parts = [this.config.instructions, this.params.instructions].filter(\n (part): part is string => Boolean(part && part.trim()),\n );\n return parts.length > 0 ? parts.join(\"\\n\\n\") : undefined;\n }\n\n // --- tools -------------------------------------------------------------\n\n private async runTools(\n message: AgentMessage,\n calls: ToolCallPart[],\n step: number,\n ): Promise<PendingToolCall[]> {\n const pending: PendingToolCall[] = [];\n const running: Promise<void>[] = [];\n\n for (const call of calls) {\n const resolved = this.config.registry.get(String(call.name));\n\n if (!resolved) {\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"tool_error\",\n message: `There is no tool named \"${String(call.name)}\".`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n });\n continue;\n }\n\n const parsed = resolved.inputSchema!.safeParse(call.input);\n if (parsed.ok === false) {\n // Back to the model, not up the stack. A model that mis-typed one\n // argument can usually fix it on the next step, and throwing turns a\n // recoverable mistake into a dead run.\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_input\",\n message: `Invalid arguments for \"${String(call.name)}\": ${parsed.errors.join(\", \")}`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n });\n continue;\n }\n\n // The parsed value replaces the raw arguments on the part, and from here\n // on it is the only input this call has.\n //\n // A schema normalizes — it fills defaults, coerces, and drops the `null`s\n // that strict mode forces a model to send for an omitted optional. So\n // `safeParse(input)` and `input` are different values, and a pending call\n // has to be signed over, shown as, verified against and executed with the\n // *same* one. Keeping the raw value in the transcript and signing the\n // parsed one meant the MACs could not match on the way back: every\n // approval of a tool with an optional field came back looking forged, and\n // the user who clicked Approve was told they had refused.\n //\n // Writing it here rather than re-parsing on the way back also avoids\n // assuming `safeParse` is idempotent — the history now carries the value\n // the signature covers, so verification is a comparison and not a second\n // guess at what the first parse produced.\n call.input = parsed.value;\n\n const kind = pendingKind(resolved.tool);\n if (kind) {\n if (this.onPending === \"deny\") {\n this.addResult(message, this.deniedByPolicy(call));\n continue;\n }\n pending.push({\n toolCallId: call.toolCallId,\n name: call.name,\n input: parsed.value,\n kind,\n signature: signPendingCall(\n this.claimsFor(call.toolCallId, String(call.name), kind, parsed.value),\n ),\n ...(this.pathPrefix.length > 0 ? { path: [...this.pathPrefix] } : {}),\n });\n continue;\n }\n\n running.push(\n this.executeTool(resolved, message.id, call, parsed.value, step)\n .then(async (result) => {\n this.addResult(message, result);\n // The call has settled. Anything it asked to show goes into the\n // history now, after its own result — which is the order the\n // provider validates and the order it happened in.\n await this.settleShown(call.toolCallId);\n })\n .catch((error) => {\n if (error instanceof PendingEscalation) {\n if (this.onPending === \"deny\") {\n this.addResult(message, this.deniedByPolicy(call));\n return;\n }\n // Collected exactly like a pending call this run made itself, and\n // deliberately without a result on `call`: the tool did not\n // finish, so its call stays open and the next turn re-enters it.\n // Siblings are untouched — `Promise.all` below still waits for\n // them, and one that completes keeps its result rather than being\n // thrown away because a different tool asked a question.\n pending.push(...error.pending);\n return;\n }\n // Only `RunAborted` reaches here, and the abort path denies every\n // unresolved call at once — swallowing it keeps a stopped run from\n // also raising an unhandled rejection.\n }),\n );\n }\n\n await raceAbort(\n Promise.all(running).then(() => undefined),\n this.controller.signal,\n );\n return pending;\n }\n\n /**\n * What a pending call is signed over.\n *\n * `signingRunId` is the root run's, not this one's: the client only ever sees\n * the root, so a sub-agent's question has to be minted under an id the client\n * can hand back and this run can still recognise on the way in.\n */\n private claimsFor(\n toolCallId: string,\n name: string,\n kind: \"approval\" | \"question\" | \"client\",\n input: unknown,\n ) {\n return {\n runId: this.signingRunId,\n toolCallId,\n name,\n kind,\n input,\n // Absent rather than empty at the top level, so the signature a root run\n // mints is byte-for-byte the one it minted before nesting existed.\n path: this.pathPrefix.length > 0 ? [...this.pathPrefix] : undefined,\n // The principal the question is asked of (#447): an answer presented by\n // anyone else fails the MAC.\n subject: this.params.subject ?? null,\n };\n }\n\n /**\n * The refusal a sub-run running under `onPending: \"deny\"` gives itself.\n *\n * Told to the model rather than dropped, like every other denial: the\n * sub-agent asked for something it cannot have here, and the next step goes\n * better for knowing that than for finding a hole where a result should be.\n */\n private deniedByPolicy(call: ToolCallPart): ToolResultPart {\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"denied\",\n cause: \"refused\",\n reason: `\"${String(call.name)}\" needs the user, and this run was started with onPending: \"deny\". Answer from what you already have.`,\n };\n }\n\n private async executeTool(\n resolved: ResolvedTool,\n messageId: string,\n call: ToolCallPart,\n input: unknown,\n step: number,\n resume?: { answers: ClientToolResult[] },\n ): Promise<ToolResultPart> {\n const timeoutMs = resolved.tool.timeoutMs;\n if (timeoutMs === undefined) {\n return this.runToolBody(\n resolved,\n messageId,\n call,\n input,\n step,\n resume,\n this.controller.signal,\n () => false,\n );\n }\n\n // The call's own signal: the run's, plus this call's `timeoutMs`. Everything\n // the call starts is handed this one rather than the run's, so a timeout\n // cancels its image calls and sub-runs too, and the run's stop still\n // reaches them through it. The forwarding is never removed, so a stop\n // reaches whatever the call left running after it answered, exactly as it\n // does with the run's own signal.\n const callController = new AbortController();\n const runSignal = this.controller.signal;\n const forwardStop = () => callController.abort(runSignal.reason);\n if (runSignal.aborted) forwardStop();\n else runSignal.addEventListener(\"abort\", forwardStop, { once: true });\n\n // Set once the call has answered, by either route. Whatever the body yields\n // after that belongs to a call the model has already been told about, and\n // must not reach the stream.\n let answered = false;\n const body = this.runToolBody(\n resolved,\n messageId,\n call,\n input,\n step,\n resume,\n callController.signal,\n () => answered,\n );\n\n let cancelTimer = () => {};\n const timedOut = new Promise<ToolResultPart>((resolve) => {\n cancelTimer = startTimer(timeoutMs, () => {\n const message = `\"${String(call.name)}\" did not finish within ${formatDuration(timeoutMs)} (timeoutMs: ${timeoutMs}) and was cancelled.`;\n callController.abort(new DOMException(message, \"TimeoutError\"));\n resolve({\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: { code: \"timeout\", message, toolCallId: call.toolCallId, retryable: true },\n });\n });\n });\n // A body that settles after the timeout has nobody to tell. Its rejection\n // (an `AbortError` from honouring the signal, usually) is swallowed here\n // rather than surfacing as an unhandled one.\n body.catch(() => {});\n try {\n return await Promise.race([body, timedOut]);\n } finally {\n answered = true;\n cancelTimer();\n }\n }\n\n /** One call of a server tool, from `execute` to the result the model sees. */\n private async runToolBody(\n resolved: ResolvedTool,\n messageId: string,\n call: ToolCallPart,\n input: unknown,\n step: number,\n resume: { answers: ClientToolResult[] } | undefined,\n signal: AbortSignal,\n answered: () => boolean,\n ): Promise<ToolResultPart> {\n // One object, because the three of them share a memo — see `toolFiles`.\n const files = this.toolFiles(call, signal);\n const ctx: ToolContext = {\n context: this.context,\n // `{}` rather than undefined, so a tool can read a field without a guard\n // and get the same answer — absent — whether the client sent nothing or\n // the run was started without a body at all.\n body: this.params.body ?? {},\n runId: this.runId,\n threadId: this.params.threadId,\n toolCallId: call.toolCallId,\n signal,\n step,\n depth: this.depth,\n resumed: resume !== undefined,\n attachments: files.attachments,\n generateImage: files.generateImage,\n editImage: files.editImage,\n turn: this.toolTurn(messageId),\n runAgent: this.nestedRunner(messageId, call, signal, resume),\n generate: ((params: GenerateParams) =>\n this.generateForTool(params, signal, call.toolCallId)) as ToolContext[\"generate\"],\n jobs: toolJobs({\n jobs: this.depth === 0 ? this.params.jobs : undefined,\n threadId: this.params.threadId,\n runId: this.runId,\n toolCallId: call.toolCallId,\n toolName: String(call.name),\n depth: this.depth,\n async: resolved.tool.async,\n attachments: this.params.attachments ?? null,\n }),\n };\n\n try {\n const started = resolved.tool.execute!(input as any, ctx);\n let output: unknown;\n if (isAsyncGenerator(started)) {\n let next = await started.next();\n while (!next.done) {\n if (answered()) {\n // Timed out. Closed rather than drained: nothing it yields from\n // here can be shown, and a generator that is still being pulled\n // is one that keeps working.\n void started.return(undefined as never).catch(() => {});\n throw new RunAborted();\n }\n this.emit({ type: \"tool-progress\", toolCallId: call.toolCallId, data: next.value });\n next = await started.next();\n }\n output = next.value;\n } else {\n output = await started;\n }\n if (isJobHandle(output)) {\n // The call went to the background (#461). Its result is `running`,\n // and the job's own outcome replaces it once it settles.\n if (output.toolCallId !== call.toolCallId) {\n throw new ToolError(\n `\"${String(call.name)}\" returned the handle of a job another tool call started. Return the handle from this call's own ctx.jobs.`,\n { retryable: false },\n );\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"running\",\n job: {\n id: output.id,\n ...(output.summary !== undefined ? { summary: output.summary } : {}),\n },\n };\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"ok\",\n output,\n };\n } catch (error) {\n if (error instanceof RunAborted || this.controller.signal.aborted) {\n // Left to the abort path, which denies every unresolved call at once.\n throw new RunAborted();\n }\n if (error instanceof PendingEscalation) {\n // The one throw that is not a failure. Turning it into a `tool_error`\n // here would tell the model the tool broke and tell the user nothing,\n // and the question the sub-agent asked would be lost with no trace of\n // where it went — which is precisely the silent failure this branch\n // exists to prevent.\n throw error;\n }\n // A throwing tool is a result, not an exception out of the run: the model\n // is told the call failed and can try something else, which is what a\n // person would do. What it is told is redacted (#446): the same part goes\n // to the model, to the client and into the store, and an exception's\n // message is whatever the code under the tool said, connection strings\n // and internal hostnames included. A `ToolError` is the tool saying its\n // message is meant to be read; anything else is logged in full here.\n const deliberate = error instanceof ToolError;\n if (!deliberate && this.config.logErrors) this.logToolFailure(call, error);\n const raw: AgentError = {\n code: \"tool_error\",\n message: error instanceof Error ? error.message : String(error),\n toolCallId: call.toolCallId,\n retryable: deliberate ? error.retryable : true,\n };\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: this.redact(raw, { source: \"tool\", toolName: String(call.name), cause: error }),\n };\n }\n }\n\n /**\n * `ctx.generate`. See `ToolContext.generate` for why the binding matters.\n *\n * The usage is added before the abort check on purpose: a call cut short by\n * `stop()` may still have been billed for what it produced, and the turn's\n * total is the one place an app reads what the turn cost.\n */\n private async generateForTool(\n params: GenerateParams,\n callSignal: AbortSignal,\n toolCallId: string,\n ): Promise<GenerateResult<unknown>> {\n // `callSignal` is the tool call's `ctx.signal`: it aborts on a stop, at the\n // run's deadline, and at the tool's own `timeoutMs`. Only the first two\n // abort the turn (`controller.signal`), and only those throw below.\n const turn = this.controller.signal;\n return generateWithin(\n {\n ...params,\n signal: params.signal ? AbortSignal.any([callSignal, params.signal]) : callSignal,\n },\n {\n origin: {\n agent: this.config.name,\n runId: this.runId,\n ...(this.params.threadId ? { threadId: this.params.threadId } : {}),\n toolCallId,\n },\n // Before the failure is logged or thrown: the usage was billed either\n // way, and a stopped turn throws `RunAborted` rather than a\n // `throwOnError` rejection the tool might catch and carry on from.\n settled: (result) => {\n this.usage = addUsage(this.usage, result.usage);\n if (turn.aborted) throw new RunAborted();\n },\n },\n );\n }\n\n // --- nested runs -------------------------------------------------------\n\n /**\n * The `ctx.runAgent` given to one tool call, with its own memo.\n *\n * MEMOIZATION IS BY CALL INDEX, and the index is the only key there is. A\n * paused async generator cannot be put into a message history, so an\n * escalating tool is re-entered from the top rather than resumed in place,\n * and the Nth `runAgent` of the re-entered body has to be paired with the Nth\n * sub-run of the previous attempt. `ToolCallPart.nested` is that record, which\n * is also why it lives on the message: it is exactly the history the next turn\n * loads anyway, from the store or from the client.\n *\n * A tool whose `runAgent` calls sit inside a branch or a loop can produce a\n * different sequence on replay, and then index N means two different things.\n * That is checked below rather than trusted — pairing a user's answer with the\n * wrong sub-run is the failure this whole mechanism exists to avoid, and it\n * would be invisible.\n */\n private nestedRunner(\n messageId: string,\n call: ToolCallPart,\n signal: AbortSignal,\n resume?: { answers: ClientToolResult[] },\n ): ToolContext[\"runAgent\"] {\n // Snapshotted before the tool body runs, and lazily created on first use.\n // Both rules, and the reasoning behind them, are on `ReplayMemo` — which\n // `ctx.attachments.put` shares, so that the two memos on one tool call\n // cannot drift apart in how they decide what is a replay.\n const memo = new ReplayMemo<NestedRun>(\n () => call.nested,\n () => (call.nested = []),\n );\n\n return async (agent: AnyAgent, params: RunAgentParams = {}): Promise<NestedRunResult> => {\n const { at, recorded, write } = memo.next();\n\n if (recorded) {\n const mismatch = replayMismatch(recorded, agent, params);\n if (mismatch) {\n throw new ToolError(\n `Nested run ${at} of \"${String(call.name)}\" ${mismatch}. ` +\n `runAgent is memoized by call index, so a body whose runAgent calls depend on a condition that changed between turns cannot be resumed — the answer would be paired with a different sub-run. ` +\n `Make the sequence of runAgent calls, and what each one is asked, the same every time this tool runs, or branch on ctx.resumed.`,\n );\n }\n if (recorded.finishReason !== \"awaiting-input\") {\n // The whole point of the memo: no provider is called, no sub-tool\n // runs, and no usage is counted a second time — this turn did not\n // spend it, an earlier one did.\n return {\n runId: recorded.runId,\n agent: recorded.agent,\n messages: recorded.messages,\n finishReason: recorded.finishReason ?? \"stop\",\n usage: recorded.usage ?? emptyUsage(),\n output: outputOf(recorded.messages),\n nested: recorded,\n };\n }\n }\n\n return this.runNested(\n messageId,\n call,\n signal,\n agent,\n params,\n write,\n recorded,\n resume?.answers ?? [],\n );\n };\n }\n\n /**\n * Starts, or continues, one sub-run and joins it to this one.\n *\n * Joining is the only reason this exists — a tool can already make an agent\n * and iterate it. What it cannot do by hand is put the sub-run's events on\n * this run's stream in this run's `seq`, roll its usage up, record its\n * transcript where the next turn will look for it, and carry the depth and\n * the name chain so a cycle is a sentence rather than a stack overflow.\n */\n private async runNested(\n messageId: string,\n call: ToolCallPart,\n signal: AbortSignal,\n agent: AnyAgent,\n params: RunAgentParams,\n write: (record: NestedRun) => void,\n recorded: NestedRun | undefined,\n answers: ClientToolResult[],\n ): Promise<NestedRunResult> {\n // Both checks before anything starts, so the failure is a tool result the\n // model can read rather than a partly-run tree. The name chain catches the\n // common cycle (A runs A, A runs B runs A) exactly; the depth limit catches\n // the shapes a name cannot see, such as the same agent under two names.\n const chain = [...this.chain, agent.name];\n if (this.chain.includes(agent.name)) {\n throw new ToolError(\n `\"${agent.name}\" is already running further up this chain: ${chain.join(\" -> \")}. An agent cannot run itself, directly or through another agent.`,\n );\n }\n const depth = this.depth + 1;\n if (depth > this.maxDepth) {\n throw new ToolError(\n `Nested agent runs are ${this.maxDepth} deep at most and this one would be ${depth}: ${chain.join(\" -> \")}. Raise maxDepth on the agent at the root of the run if the tree is meant to be this deep.`,\n );\n }\n\n const label = params.label;\n const signingPath = [...this.pathPrefix, call.toolCallId];\n // Inherited downwards and never relaxed: a caller that asked for an\n // autonomous sub-agent must not have a question surface from two levels\n // below it, and only the subtree refusing can promise that.\n const onPending = this.onPending === \"deny\" ? \"deny\" : (params.onPending ?? \"escalate\");\n\n const resuming = recorded !== undefined;\n const open = resuming ? openCallIds(recorded.messages) : new Set<string>();\n // Only the answers this sub-run can actually attach to a call of its own,\n // or route further down. Handing it the rest would make it report a result\n // for a call nobody made.\n const mine = resuming\n ? answers.filter((answer) => {\n const below = pathBelow(answer.path, signingPath);\n if (below === null) return false;\n return open.has(below.length > 0 ? below[0] : answer.toolCallId);\n })\n : [];\n\n const sub = agent.stream({\n // A resume starts from what was persisted, not from what the tool passed\n // this time: the body ran again from the top and rebuilt its `prompt`,\n // and honouring it would replay a first turn the sub-agent has already\n // had. The persisted transcript already contains it.\n messages: resuming ? recorded.messages : (params.messages ?? []),\n turn: resuming ? { toolResults: mine } : params.prompt ? { text: params.prompt } : undefined,\n // The same caller, so the same context. See `ToolContext.context`.\n context: this.context,\n // The same scope, down the whole tree. A sub-agent runs on behalf of the\n // caller who started the parent — that is the only reason it is allowed\n // to run at all — so it reads and writes the caller's attachments, and a\n // tool three levels down can be handed an id its parent parked. There is\n // nothing to widen here and nothing to narrow: a second scope would be a\n // second answer to a question the request already answered once.\n attachments: this.params.attachments,\n // Inherited for the same reason the scope above is: a sub-agent is part\n // of the turn its parent is serving, so the fields the client sent with\n // that turn are as much its context as the parent's. A generator run\n // through `runAgent` whose tools could not see `pageId` would have to be\n // passed it through the prompt, as text, for the model to copy back.\n body: this.params.body,\n // Inherited, not new: this is what makes the parent's `stop()` reach a\n // sub-run three levels down without anything in between forwarding it.\n // The call's signal rather than the run's: it is the run's plus the\n // tool's own `timeoutMs`, so a tool that times out takes its sub-runs\n // with it instead of leaving them to finish for nobody.\n signal,\n threadId: this.params.threadId,\n // The same caller is reading, so the same rules for what it is told.\n redactError: this.params.redactError,\n // The same store, so a sub-run's answers are single-use across every\n // instance exactly as the parent's are.\n nonces: this.params.nonces,\n // And the same receipts, so a sub-agent's approved tool runs once too.\n receipts: this.params.receipts,\n // The same principal, so a sub-agent's question is bound to the user the\n // root run was started for.\n subject: this.params.subject,\n instructions: params.instructions,\n maxOutputTokens: params.maxOutputTokens,\n temperature: params.temperature,\n // Kept across turns so the transcript the client already has keeps its\n // identity when the run continues.\n runId: resuming ? recorded.runId : undefined,\n nesting: {\n depth,\n maxDepth: this.maxDepth,\n chain,\n signingRunId: this.signingRunId,\n signingPath,\n onPending,\n },\n }) as AgentRun;\n\n let asked: PendingToolCall[] = [];\n const forward = (event: AgentStreamEvent) =>\n this.emit({\n type: \"nested-event\",\n toolCallId: call.toolCallId,\n runId: sub.runId,\n agent: agent.name,\n label,\n event,\n });\n const forwarding: Promise<void> = (async () => {\n for await (const event of sub as AsyncIterable<AgentStreamEvent>) {\n if (event.type === \"awaiting-input\") asked = event.pending;\n forward(event);\n if (event.type === \"run-start\" && !resuming) {\n // The seed, streamed (#470). It is recorded below as the head of the\n // transcript, but the sub-run never emits it — a run streams only the\n // messages it makes — so a client building the transcript from these\n // frames had none of it, while one that loaded the record (or got the\n // re-sent `tool-call`) did, and the two rendered different\n // conversations. Whole `message` frames, because the seed is finished\n // before the sub-run starts. A `prompt` is the sub-run's own turn and\n // is emitted by the sub-run itself (`ingestTurn`). A resume emits\n // nothing here: the record it continues already holds the seed.\n for (const message of params.messages ?? []) forward({ type: \"message\", message });\n }\n if (event.type === \"error\") {\n // Re-raised on the parent's own stream (#468). Wrapped in a\n // `nested-event` it reaches nobody: the client reduces it into a\n // throwaway sub-state, and the controller's hooks only hear\n // top-level frames, so `useChat.error`, `onError` and the\n // controller's `onError` never heard that a sub-agent failed. The\n // same object, not a copy: it was redacted by the sub-run already,\n // and the controller's `onError` finds the unredacted original by\n // identity. Not terminal — the tool decides what the failure means.\n this.emit({\n type: \"error\",\n error: event.error,\n nested: { toolCallId: call.toolCallId, runId: sub.runId, agent: agent.name },\n });\n }\n }\n })();\n\n // Recording is its own promise so that the abort path can wait for exactly\n // this — the transcript reaching the tool call — rather than for the whole\n // tool, which may be ignoring the signal.\n const recording = (async () => {\n const result = await sub.result();\n await forwarding;\n // The seed leads, because a run only reports the messages it *made* and\n // `params.messages` is not one of them. Recording the transcript without\n // its opening is two bugs: a resume re-enters the sub-agent with the\n // conversation it was started from missing, and the replay check below\n // has nothing to fingerprint the seed against. Upserted rather than\n // concatenated because the sub-run may have amended one of these on its\n // way through.\n const messages = resuming\n ? mergeMessages(recorded.messages, result.messages)\n : mergeMessages(params.messages ?? [], result.messages);\n const record: NestedRun = {\n runId: sub.runId,\n agent: agent.name,\n label,\n messages,\n finishReason: result.finishReason,\n usage: resuming ? addUsage(recorded.usage ?? emptyUsage(), result.usage) : result.usage,\n // A parked record is what the next turn re-enters the tool on, and in\n // stateless mode it comes back from the browser. Signed here, by the\n // run that knows it is true, over where the sub-run parked, what it is\n // waiting on and the input the tool was running with — `parkedBelow`\n // will not act on a record without it. `call.input` is the parsed\n // value by now, on every path that reaches here, so the transcript\n // carries exactly what was signed.\n ...(result.finishReason === \"awaiting-input\"\n ? {\n signature: signNestedRun({\n runId: this.signingRunId,\n path: signingPath,\n nestedRunId: sub.runId,\n open: [...openCallIds(messages)],\n input: call.input,\n subject: this.params.subject ?? null,\n }),\n }\n : {}),\n };\n // Written before anything below can throw. An escalation is a pause, not\n // a lost run, and a cancelled sub-run is still work the user should be\n // able to read — both of those depend on the transcript already being on\n // the part when the throw happens.\n write(record);\n // Only what this turn actually spent. A memoized sub-run adds nothing,\n // above, because the turn that ran it already counted it.\n this.usage = addUsage(this.usage, result.usage);\n return { result, record };\n })();\n\n const settling = recording.then(\n () => undefined,\n () => undefined,\n );\n this.nestedSettling.add(settling);\n let result: AgentRunResult<ToolShapes, unknown>;\n let record: NestedRun;\n try {\n ({ result, record } = await recording);\n } finally {\n this.nestedSettling.delete(settling);\n }\n\n if (this.controller.signal.aborted) {\n // The sub-run was cancelled by the parent's `stop()`. Failing the tool\n // rather than returning an aborted result is what stops the tool body\n // from carrying on with half an answer while the run around it is dying.\n throw new RunAborted();\n }\n\n if (result.finishReason === \"awaiting-input\") {\n if (asked.length === 0) {\n // Nothing to ask means nothing the client could answer, and escalating\n // an empty list would end the parent awaiting-input with a tool call\n // that can never be resolved.\n throw new ToolError(\n `\"${agent.name}\" ended awaiting input but asked nothing, so there is no question to escalate.`,\n );\n }\n // The signature is on the server's copy of the record, and a stateless\n // client has built its own from the forwarded events. Re-sending the\n // call is what puts the server's copy in the client's hands to carry\n // back: the reducer takes a re-sent `nested` as authoritative, so this\n // replaces what the client accumulated rather than adding to it. Marked\n // `resent` because it is not a call: the model made this one earlier —\n // in this run or, on a re-park, in a previous one — and a hook that\n // counts calls has already seen it.\n this.emit({ type: \"tool-call\", messageId, part: call, resent: true });\n throw new PendingEscalation({ pending: asked, path: signingPath, nested: record });\n }\n\n return {\n runId: record.runId,\n agent: agent.name,\n messages: record.messages,\n finishReason: result.finishReason,\n usage: record.usage ?? emptyUsage(),\n output: result.output ?? outputOf(record.messages),\n ...(result.error ? { error: result.error } : {}),\n nested: record,\n };\n }\n\n private addResult(message: AgentMessage, part: ToolResultPart) {\n message.content.push(part);\n this.emit({ type: \"tool-result\", messageId: message.id, part });\n }\n\n // --- files a tool made -------------------------------------------------\n\n /**\n * The `ctx.attachments` given to one tool call.\n *\n * Built per call rather than per run for one reason, and it is the same\n * reason `runAgent` is: the memo. A `put` has to be recognisable on the next\n * turn as the same `put`, and the only address a re-entered body has is \"the\n * Nth attachment of this tool call\" — so the object that counts them has to\n * belong to the call, not to the run.\n */\n /**\n * The file half of a tool's context: `ctx.attachments`, `ctx.generateImage`\n * and `ctx.editImage`.\n *\n * BUILT TOGETHER BECAUSE THEY SHARE ONE MEMO, and sharing it is not an\n * optimization. `ToolCallPart.attachments` is a list indexed by the order the\n * puts happened in, and a generated image *is* a put — so two `ReplayMemo`s\n * over the same list would each start at zero and hand out the same slots,\n * and a tool that both stored a file and generated one would replay the wrong\n * record for each. One list, one cursor.\n */\n private toolFiles(\n call: ToolCallPart,\n signal: AbortSignal,\n ): {\n attachments: ToolAttachments;\n generateImage: ToolContext[\"generateImage\"];\n editImage: ToolContext[\"editImage\"];\n } {\n const scoped = this.params.attachments ?? null;\n const memo = new ReplayMemo<ToolAttachmentRecord>(\n () => call.attachments,\n () => (call.attachments = []),\n // A put that threw took an index and wrote nothing, and if a later put in\n // the same call succeeds the gap has to be something rather than a hole:\n // `[null, { attachment }]` is what a hole becomes on the wire and in the\n // store, and it is what a UI or an app walking the memo crashes on. The\n // slot is re-attempted on a replay — `put` treats a failed record as no\n // record — so a transient failure heals itself on the turn the call\n // finally settles, and a permanent one stays legible as \"this put did not\n // produce a file\" instead of pretending it produced nothing at all.\n () => ({ failed: true }),\n );\n\n /**\n * The scope, or a sentence saying why there isn't one.\n *\n * A request with no subject gets no attachments at all — that is #489's\n * rule and this is where a tool meets it. The throw lands in `executeTool`,\n * which turns it into a `tool_error` the model reads, so the model is told\n * the tool cannot store files rather than being told nothing while the tool\n * quietly answers an id for bytes nobody kept. The message names the hook\n * an app has to override, because the reader who can act on it is the\n * developer looking at the transcript, not the model.\n */\n const scopeOrThrow = (): ScopedAttachments => {\n if (!scoped) {\n throw new InvalidAttachmentScopeError(\n \"This request has no attachment scope, so a tool cannot store or read files on it. `attachmentScope()` returned null — put the chat route behind authentication, send a `threadId`, or override `attachmentScope()` on the controller.\",\n );\n }\n return scoped;\n };\n\n /**\n * Everything a filled slot needs, with nothing of the memo in it.\n *\n * Shared by `put` and by the two image calls, which differ only in where the\n * bytes came from and in whether a `generated` record rides along. The\n * upload-then-store ordering, the `fileInput` refusal and the minted message\n * id are one copy for all three.\n */\n const park = async (\n blob: Blob,\n params: PutAttachmentParams,\n generated?: ToolAttachmentPut[\"generated\"],\n ): Promise<ToolAttachmentPut> => {\n const attachments = scopeOrThrow();\n const mimeType = params.mimeType || blob.type || \"\";\n // A name is settled here rather than left to `ScopedAttachments.put`,\n // which falls back to the attachment id. The provider's upload wants a\n // filename, the injected `FilePart` carries one, and the stored record\n // has one — three copies that have to agree, so there is one value.\n const name = params.name ?? (blob instanceof File ? blob.name : \"attachment\");\n\n let fileId: string | undefined;\n if (params.showModel) {\n const provider = this.config.provider;\n if (!provider.capabilities.fileInput) {\n // Refused before a byte moves. `toResponsesInput` drops a file part\n // for a provider that cannot read one, so without this the tool\n // pays for an upload, stores a record claiming the model was shown\n // the file, and the model answers about an image that never reached\n // the wire — with nothing in the transcript, the logs or the bill\n // saying which of those three things went wrong.\n throw new ToolError(\n `\"${String(call.name)}\" asked to show a file to ${provider.model}, which does not accept file input. Drop \\`showModel\\` for this provider, or run this agent on a model that takes files — \\`capabilities.fileInput\\` is what says which do.`,\n );\n }\n // The provider first, storage second — the opposite of `upload`'s\n // order in `AgentController`, deliberately.\n //\n // That route stores first because either failure fails the request\n // and the only question is whose orphan it becomes. Here there is a\n // second question and it decides: the record this writes claims\n // `destination: \"both\"`, and a record cannot claim the vendor has a\n // copy before the vendor says so. Uploading first also means a file\n // the vendor refuses — a type it will not take, a size over its cap —\n // costs no storage write at all, and `showModel` is exactly the path\n // where that refusal is likeliest. The orphan when storage fails\n // afterwards is a file at the vendor with no record here, which is\n // the same orphan `AgentController.upload` accepts in the other\n // direction.\n fileId = await provider.upload(new File([blob], name, { type: mimeType || undefined }));\n }\n\n const attachment = await attachments.put(blob, { name, mimeType, fileId });\n return {\n attachment,\n ...(generated ? { generated } : {}),\n ...(fileId\n ? {\n shown: {\n fileId,\n // Minted here and written down, not derived later. The next\n // turn replays this record and has to produce the same\n // message — same id, same timestamp — or a reattached client\n // and a live one hold two copies of one image.\n messageId: `msg_${crypto.randomUUID()}`,\n createdAt: new Date().toISOString(),\n },\n }\n : {}),\n };\n };\n\n /**\n * A slot that was filled by a different call than the one asking for it now.\n *\n * The sequence of file calls inside a tool body is the memo's only key, so a\n * body that stored a file on the first attempt and generates one at the same\n * index on the replay has changed in a way nothing can reconcile — and the\n * failure without this check is silent and expensive: `generateImage` would\n * hand back an attachment nobody rendered, or `put` would return the id of a\n * generated image in place of the bytes it was given.\n */\n const assertKind = (recorded: ToolAttachmentPut, wanted: \"put\" | \"image\", at: number) => {\n const was = recorded.generated ? \"image\" : \"put\";\n if (was === wanted) return;\n throw new ToolError(\n `Attachment ${at} of \"${String(call.name)}\" was ${was === \"image\" ? \"a generated image\" : \"a stored file\"} on the first attempt and is ${wanted === \"image\" ? \"a generated image\" : \"a stored file\"} now. ` +\n `ctx.attachments.put, ctx.generateImage and ctx.editImage share one memo indexed by call order within a tool call, so the sequence has to be the same every time this tool runs. Branch on ctx.resumed if it cannot be.`,\n );\n };\n\n const runImage = async (\n model: ImageModel,\n params: ToolGenerateImageParams,\n render: () => Promise<GeneratedImage>,\n ): Promise<GeneratedAttachment> => {\n const { at, recorded, write } = memo.next();\n\n // Read BEFORE the render, which is the whole point of memoizing this\n // rather than letting it fall through to `ctx.attachments.put`. `put`\n // checks its memo when it is called, and by then the image has been\n // rendered and paid for — its own docblock says so: \"Work before a `put`\n // still runs again.\" Here the expensive part is the work before.\n if (recorded && \"attachment\" in recorded) {\n assertKind(recorded, \"image\", at);\n if (recorded.shown) this.queueShown(call.toolCallId, recorded);\n return {\n attachment: recorded.attachment,\n size: recorded.generated!.size,\n mimeType: recorded.attachment.mimeType,\n usage: recorded.generated!.usage,\n };\n }\n\n const image = await render();\n // Counted against the run exactly as a nested agent's is, so\n // `AgentRunResult.usage` is the whole cost of the turn and not only its\n // text. `imageInputTokens` keeps the image share legible inside it.\n this.usage = addUsage(this.usage, image.usage);\n\n const extension = image.mimeType === \"image/jpeg\" ? \"jpg\" : \"png\";\n const record = await park(\n image.image,\n {\n name: params.name ?? `${model.name}.${extension}`,\n mimeType: image.mimeType,\n ...(params.showModel ? { showModel: true } : {}),\n },\n { size: image.size, usage: image.usage },\n );\n\n write(record);\n if (record.shown) this.queueShown(call.toolCallId, record);\n return {\n attachment: record.attachment,\n size: image.size,\n mimeType: image.mimeType,\n usage: image.usage,\n };\n };\n\n /** An attachment id resolves through the scope; bytes pass through. */\n const asInput = async (input: ImageInput | string): Promise<ImageInput> =>\n typeof input === \"string\" ? await scopeOrThrow().file(input) : input;\n\n return {\n generateImage: (model, params) =>\n runImage(model, params, () => model.generate({ ...params, signal })),\n\n editImage: (model, params) =>\n runImage(model, params, async () => {\n // `images` and `mask` are peeled off rather than spread over: both\n // may be attachment ids here and neither is one by the time it\n // reaches `ImageModel`, so letting the originals through would type\n // as `string | Blob` and ship an id where bytes belong.\n const { images, mask, ...rest } = params;\n return await model.edit({\n ...rest,\n images: (await Promise.all(images.map(asInput))) as [ImageInput, ...ImageInput[]],\n ...(mask ? { mask: await asInput(mask) } : {}),\n signal,\n });\n }),\n\n attachments: {\n get: (id: string) => scopeOrThrow().get(id),\n read: (id: string) => scopeOrThrow().read(id),\n file: (id: string) => scopeOrThrow().file(id),\n put: async (blob: Blob, params: PutAttachmentParams = {}): Promise<Attachment> => {\n const { at, recorded, write } = memo.next();\n\n // A `failed` record is a slot an earlier turn took and could not fill,\n // so there is nothing to replay and the work is done again.\n if (recorded && \"attachment\" in recorded) {\n assertKind(recorded, \"put\", at);\n const mismatch = putMismatch(recorded, blob, params);\n if (mismatch) {\n throw new ToolError(\n `Attachment ${at} of \"${String(call.name)}\" ${mismatch}. ` +\n `ctx.attachments.put is memoized by call index within a tool call, so a body whose put calls depend on a condition that changed between turns cannot be replayed — the model would be shown a file under an id that names different bytes. ` +\n `Make the sequence of put calls the same every time this tool runs, or branch on ctx.resumed.`,\n );\n }\n // Nothing is stored and nothing is uploaded. What IS repeated is the\n // queueing: the first attempt escalated before its result attached,\n // so the message was queued and never flushed, and this turn is the\n // one where the call finally settles. `settleShown` refuses a message\n // id the history already holds, which is what makes queueing twice\n // safe rather than merely unlikely.\n if (recorded.shown) this.queueShown(call.toolCallId, recorded);\n return recorded.attachment;\n }\n\n const record = await park(blob, params);\n // The slot is filled only now, with everything that could throw behind\n // it: a put that fails leaves the tool call exactly as it found it.\n write(record);\n if (record.shown) this.queueShown(call.toolCallId, record);\n return record.attachment;\n },\n },\n };\n }\n\n /**\n * The `ctx.turn` given to one tool call. The reasoning is on `ToolTurn`.\n *\n * Anchored on `messageId`, the assistant message holding the call, which is\n * the same id on a re-entry: `amend` replaces the history entry with a clone\n * under the original's id, so the lookup is by id rather than by reference.\n * A message that is not in the history at all gets an empty list rather than\n * a guess.\n */\n private toolTurn(messageId: string): ToolTurn {\n const at = this.history.findIndex((message) => message.id === messageId);\n const injected = injectedMessageIds(this.history);\n let user: AgentMessage | undefined;\n for (let i = at - 1; i >= 0; i--) {\n const message = this.history[i];\n if (message.role !== \"user\" || injected.has(message.id)) continue;\n user = message;\n break;\n }\n const ids: string[] = [];\n for (const part of user?.content ?? []) {\n if (part.type !== \"file\") continue;\n // The prefix test `providers/request.ts` applies before telling the model\n // an id. A stateless client's history can put anything here, and a value\n // the model was never shown as an id should not reach a tool as one.\n const id = part.attachmentId;\n if (typeof id !== \"string\" || !id.startsWith(ATTACHMENT_ID_PREFIX)) continue;\n if (!ids.includes(id)) ids.push(id);\n }\n return Object.freeze({ attachments: Object.freeze(ids) });\n }\n\n /**\n * Holds the message for a shown file until its tool call settles.\n *\n * WHY IT WAITS. The message is input-role and it has to sit *after* the tool\n * call's result, because that is the order it happened in and the order the\n * provider validates: a `function_call` and its `function_call_output` are a\n * pair, and a user message wedged between them is a history the API rejects.\n * Emitting it the moment `put` returns would do exactly that, since the tool\n * is still running.\n *\n * WHY A TOOL THAT ESCALATED GETS NOTHING. Its call has no result yet, so\n * flushing would leave an image in the transcript attached to a call that has\n * not finished — and the next turn re-enters the body, replays the `put` and\n * would queue a second copy. The queue simply dies with the run; the record\n * on the tool call survives, and the turn that finally settles the call is\n * the turn that shows the file.\n */\n private queueShown(toolCallId: string, record: ToolAttachmentPut) {\n const shown = record.shown;\n if (!shown) return;\n const queued = this.shownQueue.get(toolCallId) ?? [];\n if (queued.some((message) => message.id === shown.messageId)) return;\n queued.push({\n id: shown.messageId,\n role: \"user\",\n content: [\n {\n type: \"file\",\n fileId: shown.fileId,\n name: record.attachment.name,\n mimeType: record.attachment.mimeType,\n // Shown to the model beside the file (see `attachmentLine` in\n // `providers/request.ts`), so a file one tool made can be the input\n // of the next. Not what marks the part as injected — a user's upload\n // carries one too; `historyForProvider` keys on the message id.\n attachmentId: record.attachment.id,\n },\n ],\n createdAt: shown.createdAt,\n // Complete the instant it is made. Without this the client's `run-end`\n // safety net would find a message with no finish reason and stamp one on,\n // which is a difference between a live client and a reattached one over a\n // message that was never streaming in the first place.\n finishReason: \"stop\",\n });\n this.shownQueue.set(toolCallId, queued);\n }\n\n /**\n * The tool call settled: its files go into the transcript now.\n *\n * Pushed to `history` (so the next step sees them), to `produced` (so\n * `result().messages` carries them and the controller persists them), emitted\n * (so a client watching live sees the same conversation a reattached one\n * replays), and queued for `onMessage` (so an app that persists from the hook\n * stores it). A message that is in some of those four and not the others is\n * the bug class #470 is about, and an injected message is the easiest place in\n * the codebase to write it.\n *\n * QUEUED FOR THE HOOK RATHER THAN REPORTED HERE, so that all four agree on\n * ORDER and not merely on contents. The assistant message that made this tool\n * call has not been finalized yet — `loop` does that after `runTools`\n * returns — so calling `onMessage` from here would hand an app the file\n * before the turn that produced it. `reportDeferred` is where the queue is\n * drained, immediately after that assistant message is reported.\n *\n * The id guard is for a history that already holds the message — a stateless\n * client posting back a transcript that contains the injection *and* still\n * shows the call as open, which is a rewind the server cannot rule out. One\n * copy either way.\n *\n * NOTHING IS SHOWN ONCE THE RUN IS OVER, and the check belongs here rather than\n * at the three call sites because one of those sites fires after the run has\n * finished. `finalizeAborted` never calls this — it denies every open call\n * instead — but a `/stop` does not wait for a tool that is already running:\n * `raceAbort` in `runTools` returns the moment the signal fires, the run\n * finalizes and ends, and the tool's own `.then` lands afterwards and calls\n * this. Without the guard the message goes into `history` and `produced` and\n * through `onMessage` while `emit` is already a no-op, so it is persisted and\n * never announced, and a client that reloads the thread sees an image a client\n * that watched it live never saw. That is the exact divergence this issue\n * asked to avoid, arrived at from the one direction nobody looks. Appending an\n * image to a conversation the user has just cancelled would also be the run\n * getting the last word. The bytes are kept and the record is on the tool\n * call, so a tool that runs again can still resolve the id; nothing is lost\n * but the showing.\n */\n private async settleShown(toolCallId: string): Promise<void> {\n const queued = this.shownQueue.get(toolCallId);\n if (!queued || queued.length === 0) return;\n this.shownQueue.delete(toolCallId);\n if (this.ended || this.controller.signal.aborted) return;\n for (const message of queued) {\n if (this.history.some((held) => held.id === message.id)) continue;\n this.history.push(message);\n this.produced.push(message);\n this.emit({ type: \"message\", message });\n this.unreported.add(message);\n }\n }\n\n /**\n * The history as the provider sees it: everything, minus all but the most\n * recent tool-produced file.\n *\n * THE PROBLEM. `buildResponsesRequest` is handed the whole history on every\n * step, so a file injected at step two is re-sent at steps three, four and\n * five. An edit loop that iterates three times therefore pays for three\n * images on every later call — image tokens are not small, and they are\n * charged again each step — on top of one provider upload per iteration. Left\n * alone this is a cost that grows with the square of the loop and shows up on\n * an invoice rather than in a stack trace.\n *\n * WHAT IS TRIMMED, AND WHERE. Here, on the way to the provider, and nowhere\n * else. The transcript keeps every injected message: `history`, `produced`,\n * `onMessage`, the stream, and the client all hold the same conversation they\n * would have held without this method, so a `/attach` replay still matches a\n * live stream and a user scrolling back still sees every version the agent\n * made. Trimming the stored transcript instead would have meant editing a\n * message after it was persisted and announced, which is the one thing the\n * message contract does not allow.\n *\n * WHAT IT COSTS, AND IT IS A REAL CAPABILITY. With a window of one, the model\n * cannot compare this iteration against the last one. \"Is this closer than\n * the previous attempt?\" is a question it can no longer answer from what it\n * can see, and an agent whose job is to converge on a target by comparison\n * genuinely wants two. One is the default because the failure of too small a\n * window is visible and cheap — the model says it cannot see the earlier\n * image, in the transcript, on the first run — while the failure of too large\n * a one is a bill nobody reads until the end of the month. The dropped part\n * is replaced by a line of text rather than removed, so the model is told the\n * image existed and why it is gone; a hole would leave it to conclude it had\n * imagined seeing anything.\n *\n * IT IS A CONSTANT, NOT A KNOB, ON PURPOSE. A configurable window is one line\n * to add later and cannot be taken back once apps depend on it, and nobody\n * has a second value to name yet. Only files the run injected are counted —\n * a file the *user* attached is one they expect to stay attached, and\n * dropping it would be the agent losing the thing it was asked about.\n */\n private historyForProvider(current: AgentMessage | undefined): AgentMessage[] {\n const messages = this.history.filter((message) => message !== current);\n\n // Injected messages are named by the tool call that made them, and that\n // record is the test — not `attachmentId` on the part. A user's own upload\n // carries an `attachmentId` too: `ingestTurn` copies it from `turn.files`,\n // and `useChat` spreads the entry onto its local user message.\n const injected = injectedMessageIds(messages);\n\n const shown: FilePart[] = [];\n for (const message of messages) {\n if (!injected.has(message.id)) continue;\n for (const part of message.content) {\n if (part.type === \"file\") shown.push(part);\n }\n }\n if (shown.length <= SHOWN_FILE_WINDOW) return messages;\n\n const dropped = new Set(shown.slice(0, shown.length - SHOWN_FILE_WINDOW));\n return messages.map((message) => {\n if (!message.content.some((part) => part.type === \"file\" && dropped.has(part))) {\n return message;\n }\n return {\n ...message,\n content: message.content.map((part) =>\n part.type === \"file\" && dropped.has(part)\n ? {\n type: \"text\" as const,\n text: `[A ${part.mimeType || \"file\"} produced by a tool (attachment ${part.attachmentId}) was attached here and has been dropped from this request: only the most recent tool-produced file is kept attached, to keep the context bounded. Call the tool again if you need to look at it.]`,\n }\n : part,\n ),\n };\n });\n }\n\n // --- the client's turn -------------------------------------------------\n\n /**\n * Resolves what the client sent back, then adds its words.\n *\n * Every pending call has to come out of this with a result — signed, refused\n * or implicitly denied. The provider rejects a history holding a tool call\n * with no result, so leaving one open would break not this turn but the next\n * one, at a point where the cause is no longer visible.\n */\n private async ingestTurn(): Promise<PendingToolCall[]> {\n const turn = this.params.turn;\n const open = this.openCalls();\n /** Questions a re-entered tool asked again. The run ends on these. */\n const escalated: PendingToolCall[] = [];\n\n if (open.length > 0) {\n const answered = new Set<string>();\n const seen = new Set<string>();\n /** Answers addressed *below* one of this run's tool calls, grouped by the\n * call that has to be re-entered to deliver them. */\n const reentry = new Map<string, ClientToolResult[]>();\n\n for (const answer of turn?.toolResults ?? []) {\n // One answer per call, first one wins. A turn carrying the same entry\n // twice is a retried submit or a double-clicked form, and without this\n // it ran the approved tool twice and left two results for one\n // toolCallId — a history the provider rejects, arrived at by exactly\n // the machinery that exists to keep the history well formed.\n //\n // Keyed by path *and* id, because a tool-call id is only unique within\n // one run: two sub-agents under two different tools each number their\n // calls from their own provider, and dropping the second as a duplicate\n // would strand the tool that was waiting on it. For a top-level answer\n // the key is the id, exactly as before.\n const key = `${(answer.path ?? []).join(\"/\")}#${answer.toolCallId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const reject = (message: string) =>\n this.emit({\n type: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message,\n toolCallId: answer.toolCallId,\n retryable: false,\n },\n });\n\n // The path says which run the answer belongs to; `toolCallId` only says\n // which call *within* that run. Both are covered by the signature, so a\n // client that moves an answer to another tool's sub-run does not\n // redirect anything — it routes the answer somewhere the MAC no longer\n // verifies, which is the property that makes carrying the path safe.\n const below = pathBelow(answer.path, this.pathPrefix);\n if (below === null) {\n reject(\n `The answer for \"${answer.toolCallId}\" is addressed to a tool call this run is not inside.`,\n );\n continue;\n }\n\n if (below.length > 0) {\n const host = below[0];\n const hosting = open.find((entry) => entry.call.toolCallId === host);\n if (!hosting) {\n reject(`No pending tool call with id \"${host}\" to deliver a nested answer to.`);\n continue;\n }\n // THE ONE CHECK THAT MAKES RE-ENTRY SAFE, and the reason it is here\n // rather than in `reenter`.\n //\n // Re-entry runs the tool. Everything else in this method verifies a\n // signature first, but a path cannot be verified here — the claims\n // are the *inner* call's, and only the run that minted them knows its\n // tool, its `kind` and its input, which is why `resolveAnswer` runs\n // down there and not up here. So the decision to execute has to be\n // gated on something the server derived instead: there must be a\n // sub-run parked on this exact call, and it must be waiting on the\n // exact question the answer names. Without this, a turn that posts\n // `{ path: [<any open call>], signature: \"\" }` re-enters a tool that\n // is merely awaiting an *approval* — running, unapproved, a call the\n // user was shown and never said yes to, with its input taken from a\n // client-carried history. Content is still checked below, in the\n // sub-run; this is what stops an unsigned request from choosing to\n // execute at all.\n const parked = this.parkedBelow(hosting.call, below, answer.toolCallId);\n if (parked.ok === false) {\n const under = `The answer for \"${answer.toolCallId}\" is addressed under \"${host}\", which`;\n reject(\n parked.reason === \"unparked\"\n ? `${under} has no sub-agent run waiting on that question.`\n : parked.reason === \"expired\"\n ? `${under} parked a sub-agent run that has since expired. Ask again.`\n : `${under} carries a record of a parked sub-agent run the server did not sign.`,\n );\n continue;\n }\n let group = reentry.get(host);\n if (!group) {\n // Spent here, ahead of the body, for the reason the record is\n // signed at all: re-entry runs the tool before the sub-run gets to\n // refuse a spent answer, so a history rewound to before the result\n // would run it once per replay. Once per record per turn — the\n // sub-run may have asked two things at once, and every answer to\n // it re-enters the same tool a single time.\n if (!(await this.spend(spendNestedRun, parked.signature))) {\n reject(\n `The answer for \"${answer.toolCallId}\" is addressed under \"${host}\", which has already been re-entered on that record. Ask again.`,\n );\n continue;\n }\n group = [];\n reentry.set(host, group);\n // Marked answered so the refusal pass below leaves it alone: the\n // tool is about to be re-entered and will produce the real result.\n answered.add(host);\n }\n group.push(answer);\n continue;\n }\n\n const target = open.find((entry) => entry.call.toolCallId === answer.toolCallId);\n if (!target) {\n // Nothing to attach it to, so it cannot be told to the model even as\n // an error part — a result for a call that was never made.\n reject(`No pending tool call with id \"${answer.toolCallId}\".`);\n continue;\n }\n\n const result = await this.resolveAnswer(target, answer, escalated);\n if (result === null) continue;\n answered.add(answer.toolCallId);\n // `\"open\"` is an approved tool whose own sub-agent asked something on\n // the way through: answered, so the refusal pass leaves it alone, but\n // no result attaches — the call stays open and the next turn re-enters\n // it, exactly as an escalation from the step loop does. Nothing it\n // showed is flushed either, for the same reason: the call has not\n // settled, so the file waits for the turn where it does.\n if (result !== \"open\") {\n this.attachToHistory(target, result);\n await this.settleShown(answer.toolCallId);\n }\n }\n\n for (const [host, answers] of reentry) {\n const entry = open.find((item) => item.call.toolCallId === host)!;\n const result = await this.reenter(entry, answers, escalated);\n if (result) {\n this.attachToHistory(entry, result);\n // The turn a re-entered tool finally settles on is the turn its files\n // are shown, however many turns ago it stored them.\n await this.settleShown(host);\n }\n }\n\n for (const entry of open) {\n if (answered.has(entry.call.toolCallId)) continue;\n // The turn said something else. That is a refusal — the honest reading,\n // and the only one that cannot strand the thread. A tool whose\n // sub-agent asked a question and did not get an answer is refused here\n // like any other: the sub-run is abandoned with its transcript intact,\n // and the call gets a result rather than dangling into the next turn.\n this.attachToHistory(entry, {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"denied\",\n cause: \"refused\",\n });\n }\n\n await this.reportDeferred();\n }\n\n if (turn && (turn.text || (turn.files && turn.files.length > 0))) {\n const message: AgentMessage = {\n id: `msg_${crypto.randomUUID()}`,\n role: \"user\",\n content: [\n ...(turn.text ? [{ type: \"text\" as const, text: turn.text }] : []),\n // Field by field rather than spread: an entry can carry whatever\n // `attach()` answered (`downgraded`, `size`), and only these four\n // mean anything on a `FilePart`. `attachmentId` is among them — it is\n // what lets the model name this file to a tool — and an absent\n // `fileId` is a storage-only upload, left out rather than written as\n // `undefined`.\n ...(turn.files ?? []).map((file) => ({\n type: \"file\" as const,\n ...(file.fileId ? { fileId: file.fileId } : {}),\n name: file.name,\n mimeType: file.mimeType,\n ...(file.attachmentId ? { attachmentId: file.attachmentId } : {}),\n })),\n ],\n createdAt: new Date().toISOString(),\n finishReason: \"stop\",\n };\n this.history.push(message);\n this.produced.push(message);\n // A sub-run's turn was written by the tool that started it, not typed by\n // the client watching, so nothing on the stream would ever tell that\n // client it exists (#470). A top-level turn is not echoed: the client\n // sent it and already has it. What it does not have is this id, so it is\n // told that alone, keyed by the id it gave its own copy (#466). The\n // message rides along for any other client watching the run (#778): a\n // tab that attached to it never held the copy, and the reducer appends\n // it only there.\n if (this.depth > 0) this.emit({ type: \"message\", message });\n else if (turn.localId) {\n this.emit({ type: \"message-id\", localId: turn.localId, messageId: message.id, message });\n }\n await this.report(message);\n // After `report`, so a caller that persists from `onMessage` has queued\n // the message before it hears that this is the turn (#806).\n if (this.params.onTurn) {\n try {\n await this.params.onTurn(message);\n } catch {\n // As `report`: the turn is still on the stream and in `result()`.\n }\n }\n }\n\n return escalated;\n }\n\n /**\n * Whether a sub-run under `call` is actually parked on the question named.\n *\n * The transcript is the server's own record of where the run stopped:\n * `nested` is written from the sub-run's result before the escalation throws,\n * so a call that has never nested has no `nested` at all, and one whose\n * sub-runs all finished has none with `awaiting-input`. In stateless mode\n * that record arrives from the client and could say anything, and what\n * saying it buys is not small: the tool body runs — from the top, with the\n * input the history carries — before the sub-run gets to verify the answer,\n * so everything the body does ahead of its first `runAgent` happens on the\n * client's say-so. Which is why the record has to carry the server's\n * signature over the sub-run it parked, the calls it left open and the\n * input the tool was given, and why a record without one, or with one that\n * does not match what it now says, is not a parked run at all.\n *\n * The failure says which of those it was. \"Expired\" is an ordinary outcome\n * in threaded mode — a question answered a day late — and telling that\n * user the run never parked would send them looking for a bug that is not\n * there; a record that fails its MAC is the other thing entirely, and the\n * two are kept apart for the same reason `resolveAnswer` keeps them apart.\n *\n * `below` is the answer's path with this run's prefix already removed, so\n * `below[0]` is `call` itself and `below[1]`, when there is one, names the\n * call to re-enter one level further down.\n */\n private parkedBelow(\n call: ToolCallPart,\n below: string[],\n toolCallId: string,\n ): { ok: true; signature: string } | { ok: false; reason: \"unparked\" | \"unsigned\" | \"expired\" } {\n const wanted = below.length > 1 ? below[1] : toolCallId;\n const path = [...this.pathPrefix, call.toolCallId];\n const parked = (call.nested ?? []).find(\n (run) => run.finishReason === \"awaiting-input\" && openCallIds(run.messages).has(wanted),\n );\n if (!parked) return { ok: false, reason: \"unparked\" };\n if (typeof parked.signature !== \"string\") return { ok: false, reason: \"unsigned\" };\n const verified = verifyNestedRun(parked.signature, {\n path,\n nestedRunId: parked.runId,\n open: [...openCallIds(parked.messages)],\n input: call.input,\n subject: this.params.subject ?? null,\n });\n if (verified.ok === false) {\n return { ok: false, reason: verified.reason === \"expired\" ? \"expired\" : \"unsigned\" };\n }\n return { ok: true, signature: parked.signature };\n }\n\n /**\n * Re-enters a tool whose sub-agent asked the user something.\n *\n * From the top, with `ctx.resumed === true` — there is no other way. A JS\n * async generator cannot be suspended across a turn boundary, so the body\n * runs again and `runAgent` replays its finished sub-runs out of\n * `ToolCallPart.nested` instead of re-running them. Which means the code\n * *before* the escalating `runAgent` runs twice; that bargain is documented on\n * `ToolContext.runAgent` and it is the price of not needing a checkpoint API.\n */\n private async reenter(\n entry: { message: AgentMessage; call: ToolCallPart },\n answers: ClientToolResult[],\n escalated: PendingToolCall[],\n ): Promise<ToolResultPart | null> {\n const name = String(entry.call.name);\n const resolved = this.config.registry.get(name);\n if (!resolved || !resolved.tool.execute) {\n return {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message: `The tool \"${name}\" no longer exists, so the sub-agent's question cannot be delivered.`,\n toolCallId: entry.call.toolCallId,\n retryable: false,\n },\n };\n }\n\n // Checked the way `runTools` checked the model's arguments. The record's\n // signature has already said this is the input the tool parked on, so what\n // this catches is the tool itself having moved: a schema that changed\n // between the turn that parked and the turn that answers. The tool's typed\n // input is a contract with the tool as it is now, and a value the schema\n // rejects must not reach it — the failure is a result the model can read,\n // exactly like a mis-typed argument on the way in.\n const parsed = resolved.inputSchema!.safeParse(entry.call.input);\n if (parsed.ok === false) {\n return {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_input\",\n message: `Invalid arguments for \"${name}\": ${parsed.errors.join(\", \")}`,\n toolCallId: entry.call.toolCallId,\n retryable: true,\n },\n };\n }\n\n const call = this.amendCall(entry);\n // The parsed value is the only input the call has from here on, as in\n // `runTools` — the clone carries what the tool was actually given.\n call.input = parsed.value;\n try {\n // Step 0, like an approval executed on the way in: this belongs to the\n // turn, not to a step of the loop that has not started yet.\n return await raceAbort(\n this.executeTool(resolved, entry.message.id, call, parsed.value, 0, { answers }),\n this.controller.signal,\n );\n } catch (error) {\n if (error instanceof PendingEscalation) {\n // Asked again. No result attaches, so the call stays open and the next\n // turn re-enters it exactly as this one did.\n escalated.push(...error.pending);\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Clones the tool-call part before a replay writes to its `nested`.\n *\n * The message holding it came from an earlier run and belongs to the caller's\n * `messages` array; the run must not reach back into its own input and change\n * it under a controller that has already persisted it. Cloning the part into\n * the amended copy is also what makes the updated sub-run transcript\n * something `onMessage` can report — see `reportDeferred`, which is why the\n * message is marked unreported here even though no result may ever attach.\n */\n private amendCall(entry: { message: AgentMessage; call: ToolCallPart }): ToolCallPart {\n const message = this.amend(entry.message);\n const at = message.content.indexOf(entry.call);\n const call: ToolCallPart = {\n ...entry.call,\n nested: (entry.call.nested ?? []).map((run) => ({ ...run })),\n // Cloned for the same reason `nested` is: the replayed body's memo writes\n // into this array, and the array on the original part belongs to the\n // caller's `messages`, which is an input and not scratch space.\n ...(entry.call.attachments\n ? { attachments: entry.call.attachments.map((record) => ({ ...record })) }\n : {}),\n };\n if (at >= 0) message.content[at] = call;\n this.unreported.add(message);\n return call;\n }\n\n /** Tool calls in the history with no result anywhere after them. */\n private openCalls(): { message: AgentMessage; call: ToolCallPart }[] {\n const resolvedIds = new Set<string>();\n for (const message of this.history) {\n for (const part of message.content) {\n if (part.type === \"tool-result\") resolvedIds.add(part.toolCallId);\n }\n }\n const open: { message: AgentMessage; call: ToolCallPart }[] = [];\n for (const message of this.history) {\n for (const part of message.content) {\n if (part.type === \"tool-call\" && !resolvedIds.has(part.toolCallId)) {\n open.push({ message, call: part });\n }\n }\n }\n return open;\n }\n\n /**\n * Verifies one answer and turns it into a result part, or reports why not.\n *\n * `null` means the call stays unanswered and falls through to the implicit\n * denial above — which is the right outcome for a bad signature: the model\n * must not see a result the server cannot vouch for. `\"open\"` means the\n * opposite: the answer was good, the tool ran, and it is now waiting on a\n * question of its own, so the call must stay open *without* being denied.\n */\n /**\n * Spends a token's nonce in the run's `NonceStore`. A store that throws (its\n * Redis is down, say) is logged and counted as spent: the answer is refused\n * and the user asked again, rather than acted on unchecked.\n */\n private async spend(\n spendIn: (signature: string, store: NonceStore) => Promise<boolean>,\n signature: string,\n ): Promise<boolean> {\n try {\n return await spendIn(signature, this.params.nonces ?? defaultNonceStore);\n } catch (error) {\n this.writeLog(`[gemi/ai] agent \"${this.config.name}\" could not spend a nonce`, { error });\n return false;\n }\n }\n\n /**\n * Records an approved tool's result on its receipt once it is known (#458),\n * and only then hands it on, so a presentation that arrives after this run\n * answered finds it. Chained to the execution rather than to the run's race,\n * so a tool that finishes after a `stop()` still records what it did.\n *\n * A tool that never produces a result — it rejected, or escalated a question\n * of its own — leaves the claim held: whether it acted is unknown, and a\n * later presentation is `blocked` rather than run again.\n */\n private async recordReceipt(\n receipt: { store: ReceiptStore; id: string; expiresAt: number },\n execution: Promise<ToolResultPart>,\n ): Promise<ToolResultPart> {\n const result = await execution;\n try {\n await receipt.store.complete(receipt.id, result, receipt.expiresAt);\n } catch (error) {\n this.writeLog(`[gemi/ai] agent \"${this.config.name}\" could not record a tool receipt`, {\n error,\n });\n }\n return result;\n }\n\n private async resolveAnswer(\n entry: { message: AgentMessage; call: ToolCallPart },\n answer: ClientToolResult,\n escalated: PendingToolCall[],\n ): Promise<ToolResultPart | \"open\" | null> {\n const call = entry.call;\n const name = String(call.name);\n const resolved = this.config.registry.get(name);\n const reject = (message: string) => {\n this.emit({\n type: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message,\n toolCallId: call.toolCallId,\n retryable: false,\n },\n });\n return null;\n };\n\n if (!resolved) {\n return reject(`The tool \"${name}\" no longer exists, so its answer cannot be checked.`);\n }\n const kind = pendingKind(resolved.tool);\n if (!kind) {\n return reject(`\"${name}\" is a server tool with no pending question.`);\n }\n if (typeof answer.signature !== \"string\" || answer.signature.length === 0) {\n return reject(`The answer for \"${name}\" carried no signature.`);\n }\n\n // The issuing run, read out of the token. The turn answering a pending call\n // is a *new* run with a new id, so the id the signature was made under has\n // to travel with the signature — and it is covered by the MAC, so a client\n // that edits it fails below rather than being believed.\n const issued = readSignature(answer.signature);\n if (!issued) {\n return reject(`The signature for \"${name}\" is malformed.`);\n }\n\n // The path is this run's own, not the one the client sent. The client's\n // copy was used to route the answer here and nothing else; recomputing the\n // MAC over what the server issued is what makes a moved answer fail instead\n // of being believed.\n const verified = verifyPendingCall(answer.signature, {\n ...this.claimsFor(call.toolCallId, name, kind, call.input),\n runId: issued.runId,\n });\n\n if (verified.ok === false) {\n return reject(\n verified.reason === \"expired\"\n ? `The approval for \"${name}\" has expired. Ask again.`\n : `The answer for \"${name}\" does not match the call the server made.`,\n );\n }\n\n // An approval that already ran is answered with what it did, before the\n // nonce is looked at (#458): its nonce was spent by the run that executed\n // it, so the check below would refuse it, and a retried submit whose\n // response was lost would tell the user the approval was not used when the\n // tool has already acted on it. Claimed before spending, so that two\n // instances whose nonce stores are not shared still run it once.\n let receipt: { store: ReceiptStore; id: string; expiresAt: number } | undefined;\n if (\n this.params.receipts &&\n kind === \"approval\" &&\n \"approve\" in answer &&\n answer.approve === true\n ) {\n const store = this.params.receipts;\n const id = executionReceiptId(this.config.name, {\n ...this.claimsFor(call.toolCallId, name, kind, call.input),\n runId: issued.runId,\n });\n let claim: ReceiptClaim;\n try {\n claim = await store.claim(id, issued.expiresAt);\n } catch (error) {\n // As with a nonce store that throws: refused, not run unchecked.\n this.writeLog(`[gemi/ai] agent \"${this.config.name}\" could not claim a tool receipt`, {\n error,\n });\n return reject(`The approval for \"${name}\" could not be checked. Ask again.`);\n }\n if (claim.status === \"replay\") {\n return { ...claim.result, toolCallId: call.toolCallId, name: call.name } as ToolResultPart;\n }\n if (claim.status === \"blocked\") {\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"tool_error\",\n message: `\"${name}\" was already approved and started, and its result is not recorded yet: it is still running, or it stopped before finishing. It was not run again.`,\n toolCallId: call.toolCallId,\n retryable: false,\n },\n };\n }\n receipt = { store, id, expiresAt: issued.expiresAt };\n }\n\n // Verifying says the server once asked this exact question; spending the\n // nonce says nobody has answered it yet. Without this step a captured token\n // approves the same call every time it is presented — the client rewinds to\n // the history from before the result existed and replays, and the human who\n // approved once has approved forever.\n if (!(await this.spend(spendPendingCall, answer.signature))) {\n // Claimed for nothing: nothing ran, so a later presentation must not be\n // told it is running. Answered by a run that predates the store, or\n // denied before: either way there is no result to replay.\n await receipt?.store.release(receipt.id).catch((error) => {\n this.writeLog(`[gemi/ai] agent \"${this.config.name}\" could not release a tool receipt`, {\n error,\n });\n });\n return reject(`The answer for \"${name}\" has already been used. Ask again.`);\n }\n\n if (\"approve\" in answer) {\n if (kind !== \"approval\") {\n return reject(`\"${name}\" is answered by the client, not approved.`);\n }\n if (answer.approve === true) {\n // Raced against the abort signal exactly as `runTools` does. A tool\n // that does not honour `ctx.signal` must not be able to hold the run\n // open, and this is the one execution outside the loop — a `stop()`\n // landing here used to hang the run forever, which is precisely the\n // dangling state `stop()` exists to prevent.\n //\n // Step 0: the approval landed before this run took its first model\n // step, so it belongs to no step of this loop. `call.input` is the\n // value the signature covers — see `runTools`.\n //\n // Cloned first, for the same reason `reenter` clones: an approved tool\n // may nest, and `nestedRunner` writes `nested` onto the part it is\n // given. That part belongs to the caller's `messages` array, which is\n // an input and not scratch space — and the clone is what makes the\n // sub-run transcript something `onMessage` can report.\n const executing = this.amendCall(entry);\n const execution = this.executeTool(\n resolved,\n entry.message.id,\n executing,\n executing.input,\n 0,\n );\n try {\n return await raceAbort(\n receipt ? this.recordReceipt(receipt, execution) : execution,\n this.controller.signal,\n );\n } catch (error) {\n if (error instanceof PendingEscalation) {\n // An approval whose tool asked the user something of its own. The\n // step loop and `reenter` both collect this; without the same catch\n // here the rejection left `ingestTurn` and was normalized into a\n // `provider_error`, which ended the run with the sub-agent's\n // question thrown away and the approval's nonce already spent.\n escalated.push(...error.pending);\n return \"open\";\n }\n throw error;\n }\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"denied\",\n cause: \"refused\",\n reason: answer.reason,\n };\n }\n\n if (\"output\" in answer) {\n if (kind === \"approval\") {\n // An approval is a tool the *server* runs. A client handing back its\n // output would be fabricating a result, not approving one.\n return reject(`\"${name}\" is approved, not answered: the server produces its result.`);\n }\n const schema = resolved.tool.outputSchema;\n const parsed = schema\n ? schema.safeParse(answer.output)\n : { ok: true as const, value: answer.output };\n if (parsed.ok === false) {\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"error\",\n error: {\n code: \"invalid_tool_result\",\n message: `The answer for \"${name}\" did not match its output schema: ${parsed.errors.join(\", \")}`,\n toolCallId: call.toolCallId,\n retryable: true,\n },\n };\n }\n return {\n type: \"tool-result\",\n toolCallId: call.toolCallId,\n name: call.name,\n status: \"ok\",\n output: parsed.value,\n };\n }\n\n return reject(`The answer for \"${name}\" carried neither an approval nor an output.`);\n }\n\n /**\n * Puts the result next to the call that asked for it.\n *\n * The message being amended came from an earlier run, so it is cloned before\n * it is touched — the caller's `messages` array is an input, not scratch\n * space, and a controller that persisted it would otherwise see it change\n * under it. The clone is reported through `onMessage` and returned in\n * `result()`, which is why a store keyed by message id has to upsert.\n */\n private attachToHistory(\n entry: { message: AgentMessage; call: ToolCallPart },\n result: ToolResultPart,\n ) {\n const message = this.amend(entry.message);\n message.content.push(result);\n this.unreported.add(message);\n this.emit({ type: \"tool-result\", messageId: message.id, part: result });\n }\n\n /**\n * The provider refused a stored file and the call went ahead without it\n * (#684). Every part holding that id is marked `providerRejected`, so the\n * next request sends a note in its place rather than an id that fails the\n * request again — the history is sent whole on every turn, and without the\n * mark one dead file costs every later turn a refused request.\n *\n * Persisted the way a late tool result is: a message from an earlier run is\n * amended (cloned, then reported and returned in `result()`), and one this\n * run made is changed in place and reported again. Either way the store\n * sees the same id with new content, which its contract says to upsert.\n * The part is replaced rather than written to, because the original object\n * may still be the caller's.\n *\n * Logged as a warning, not an error: the run goes on, and the model is told\n * the file could not be read, so the user hears about it in the answer. The\n * log is for whoever has to work out why a file stopped being readable.\n */\n private markFileRejected(\n fileId: string,\n reason: string,\n detail: { status?: number; requestId?: string },\n ): void {\n for (const original of this.history) {\n const hit = original.content.some(\n (part) => part.type === \"file\" && part.fileId === fileId && !part.providerRejected,\n );\n if (!hit) continue;\n const message = this.produced.includes(original) ? original : this.amend(original);\n message.content = message.content.map((part) =>\n part.type === \"file\" && part.fileId === fileId && !part.providerRejected\n ? { ...part, providerRejected: true as const }\n : part,\n );\n // The message being built by this step is reported when it is finalized;\n // queueing it here as well would report it before it is finished.\n if (message !== this.current) this.unreported.add(message);\n }\n if (!this.config.logErrors) return;\n const message = `[gemi/ai] agent \"${this.config.name}\": the provider refused file ${fileId}${\n detail.status !== undefined ? ` (${detail.status})` : \"\"\n }; it was left out of the request and will not be sent again: ${reason}`;\n const metadata = {\n agent: this.config.name,\n runId: this.runId,\n ...(this.params.threadId ? { threadId: this.params.threadId } : {}),\n fileId,\n ...detail,\n };\n let logged = false;\n try {\n Log.warning(message, metadata);\n logged = true;\n } catch {\n // No application to resolve a logger from.\n }\n if (!logged || process.env.NODE_ENV === \"development\") console.warn(message, metadata);\n }\n\n /** The clone of an earlier run's message that this run may write to. One per\n * message id, so two results for the same message do not fork it. */\n private amend(original: AgentMessage): AgentMessage {\n const existing = this.amended.get(original.id);\n if (existing) return existing;\n const message: AgentMessage = { ...original, content: [...original.content] };\n const index = this.history.indexOf(original);\n if (index >= 0) this.history[index] = message;\n this.produced.push(message);\n this.amended.set(original.id, message);\n return message;\n }\n\n /**\n * Persists the messages this run finished outside `finalizeMessage`, once each\n * and in the order it finished them.\n *\n * Called from the end of `ingestTurn`, from the abort path, and from\n * `finalizeMessage`. From the abort path because a stop that lands while an\n * approved tool is running has to persist the results that *did* attach this\n * turn — otherwise the work is done, the transcript on the stream shows it,\n * and the store never hears about it. From `finalizeMessage` because an\n * injected message has to reach `onMessage` after the assistant message it\n * sits below, and a `Set` preserves insertion order, which here is transcript\n * order.\n */\n private async reportDeferred(): Promise<void> {\n const pending = [...this.unreported];\n this.unreported.clear();\n for (const message of pending) await this.report(message);\n }\n\n // --- stopping ----------------------------------------------------------\n\n /**\n * The run's last act: leave a transcript the next turn can be built on.\n *\n * Everything the model asked for and did not get becomes a `denied` result\n * with `cause: \"stopped\"`, and the interrupted message is finalized as\n * `aborted` keeping whatever text it had produced. Both go out on the stream\n * and through `onMessage`. A cancel that merely stopped emitting would leave\n * a dangling tool call, and the provider would reject the history on the very\n * next message the user sent.\n */\n private async finalizeAborted(): Promise<void> {\n // Sub-runs first. They share this run's signal so they are already closing;\n // what is being waited for is the moment each writes its transcript onto\n // its tool call, because everything below this line persists messages.\n if (this.nestedSettling.size > 0) {\n await Promise.all([...this.nestedSettling]);\n }\n // Calls left open anywhere in the history, not just on the message this run\n // was building. A stop that lands while an approval this turn is executing\n // has no current message at all — the call belongs to an *earlier* turn's\n // message — and denying only `this.current` would leave that one dangling\n // in the very transcript this method exists to keep valid.\n for (const entry of this.openCalls()) {\n if (entry.message === this.current) continue;\n this.attachToHistory(entry, {\n type: \"tool-result\",\n toolCallId: entry.call.toolCallId,\n name: entry.call.name,\n status: \"denied\",\n cause: \"stopped\",\n reason: this.stopReason,\n });\n }\n // Results that did attach this turn have not been persisted yet: the report\n // pass at the end of `ingestTurn` is one of the things the abort skipped.\n await this.reportDeferred();\n\n const message = this.current;\n if (message) {\n const answered = new Set(\n message.content\n .filter((part): part is ToolResultPart => part.type === \"tool-result\")\n .map((part) => part.toolCallId),\n );\n for (const part of [...message.content]) {\n if (part.type !== \"tool-call\" || answered.has(part.toolCallId)) continue;\n // A call whose arguments were still arriving is finalized too: the\n // client has already been shown it, and an unresolved part is exactly\n // what this method exists to prevent.\n delete part.partial;\n this.addResult(message, {\n type: \"tool-result\",\n toolCallId: part.toolCallId,\n name: part.name,\n status: \"denied\",\n cause: \"stopped\",\n reason: this.stopReason,\n });\n }\n }\n if (this.timedOutAfter !== undefined) {\n // An error, not an outcome: nobody asked for this run to end, and an app\n // has to be able to see that it did — in the log, on `result().error`,\n // and as a rejection under `throwOnError`. Recorded before the message\n // closes, as every other failure is.\n this.fail({\n code: \"timeout\",\n message: `The run did not finish within its time limit of ${formatDuration(this.timedOutAfter)} (maxRunDurationMs: ${this.timedOutAfter}) and was stopped.`,\n retryable: true,\n });\n this.finishReason = \"error\";\n await this.finalizeMessage(\"error\");\n return;\n }\n this.finishReason = \"aborted\";\n await this.finalizeMessage(\"aborted\");\n }\n}\n\nfunction pendingKind(tool: AnyAgentTool): \"approval\" | \"question\" | \"client\" | null {\n if (tool.answeredBy === \"client\") {\n // A question is a client tool whose input is the prompt itself. The\n // distinction is for the UI — one renders a dialog, the other runs code —\n // and it costs nothing to carry.\n return tool.inputSchema === questionSchema ? \"question\" : \"client\";\n }\n return tool.requiresApproval ? \"approval\" : null;\n}\n\nfunction parseArgs(args: string): any {\n if (!args || !args.trim()) return {};\n try {\n return JSON.parse(args);\n } catch {\n return args;\n }\n}\n",
|
|
14
5
|
"import { CronJob } from \"../../services/cron/CronJob\";\nimport { AgentJobs } from \"./AgentJob\";\n\n/**\n * Fails background jobs that ran past their deadline (#461), every minute.\n *\n * Schedule it by exporting it from a file under `app/cron`:\n *\n * export { AgentJobDeadlineSweep } from \"gemi/ai\";\n *\n * Safe on every instance at once: each job is failed by compare-and-set. An\n * app without it still sees an overdue job fail, when the controller next\n * loads the job's thread.\n */\nexport class AgentJobDeadlineSweep extends CronJob {\n name = \"AgentJobDeadlineSweep\";\n cron = \"* * * * *\";\n\n async callback(): Promise<void> {\n // In rounds, so a backlog after an outage is cleared in one tick without\n // holding one huge result set.\n while ((await AgentJobs.sweep({ limit: 100 })) === 100) {\n // keep going\n }\n }\n}\n",
|
|
15
6
|
"import type { AgentJobRecord } from \"./AgentJobStore\";\n\n/** How many jobs the `<jobs>` block lists by default. */\nexport const DEFAULT_JOBS_CONTEXT_MAX = 20;\n\n/** `Agent.create({ jobs })`. */\nexport type AgentJobsOptions = {\n /**\n * The `<jobs>` block added to the system prompt on a thread that has\n * background jobs: at most `max` of them (default 20), running ones first,\n * then the newest settled. `false` leaves it out.\n */\n contextBlock?: { max?: number } | false;\n};\n\nconst SUMMARY_CHARS = 300;\nconst ERROR_CHARS = 200;\n\n/**\n * The `<jobs>` block (#461): what the model is told about the thread's\n * background jobs on every turn, beside the tool results in the history.\n *\n * The history already shows each job's call and its `running` or settled\n * result. The block is for what the history cannot show: a job whose result\n * never reached the thread (an orphan), and a list in one place, so a model\n * asked to \"make the images\" sees that a job for them is already running\n * rather than starting another.\n *\n * Bounded by count, `max`, running before settled and newest first inside\n * each. Times are absolute (UTC) rather than ages, so the block is the same\n * text from one turn to the next until a job starts or settles, and the\n * prompt cache holds in between. `null` when there is nothing to list.\n */\nexport function renderJobsBlock(jobs: AgentJobRecord[], max: number): string | null {\n if (max <= 0 || jobs.length === 0) return null;\n const newest = (a: AgentJobRecord, b: AgentJobRecord) =>\n b.createdAt - a.createdAt || (a.id < b.id ? 1 : -1);\n const listed = [\n ...jobs.filter((job) => job.state === \"running\").sort(newest),\n ...jobs.filter((job) => job.state !== \"running\").sort(newest),\n ].slice(0, max);\n\n const lines = listed.map((job) => {\n const parts = [`- ${job.id} (${job.toolName})`];\n if (job.state === \"running\") {\n parts.push(`running since ${iso(job.createdAt)}`);\n } else if (job.state === \"ok\") {\n parts.push(`finished at ${iso(job.settledAt ?? job.updatedAt)}`);\n } else {\n const reason = job.error\n ? `${job.error.code}: ${clip(job.error.message, ERROR_CHARS)}`\n : \"failed\";\n parts.push(`failed at ${iso(job.settledAt ?? job.updatedAt)} (${reason})`);\n }\n if (job.summary !== undefined)\n parts.push(`summary: ${clip(JSON.stringify(job.summary), SUMMARY_CHARS)}`);\n if (job.orphaned) {\n parts.push(\"its tool call was lost when the turn that started it was cut short\");\n }\n return parts.join(\"; \");\n });\n\n return [\n \"<jobs>\",\n \"Background jobs that tools started in this conversation, running ones first. A running job's result replaces its tool result when it finishes. Do not start the same work again while a job for it is running.\",\n ...lines,\n \"</jobs>\",\n ].join(\"\\n\");\n}\n\nfunction iso(ms: number): string {\n return new Date(ms).toISOString().replace(/\\.\\d{3}Z$/, \"Z\");\n}\n\nfunction clip(text: string, chars: number): string {\n return text.length <= chars ? text : `${text.slice(0, chars - 1)}…`;\n}\n",
|
|
16
7
|
"import type { SQL, TransactionSQL } from \"bun\";\n\nimport type { DatabaseConnection } from \"../../database/Connection\";\nimport type { Dialect } from \"../../database/dialect\";\nimport { currentConnectionName, currentTransaction, withTransaction } from \"../../orm/context\";\nimport type {\n AgentJobRecord,\n AgentJobState,\n AgentJobStore,\n AgentJobUpdate,\n NewAgentJobRecord,\n} from \"./AgentJobStore\";\n\nexport type DatabaseAgentJobStoreOptions = {\n /**\n * The table. Default `gemi_agent_jobs`. A plain identifier (letters, digits\n * and underscores), because it is spliced into every statement.\n */\n table?: string;\n};\n\ntype Row = Record<string, unknown>;\n\n/**\n * Background jobs (#461) in a table of the app's own database, so a job and\n * its outcome outlive the process: a deploy in the middle of a render no\n * longer loses it, and every instance sees the same state.\n *\n * Opt in, like the agent store:\n *\n * AgentJobs.use(new DatabaseAgentJobStore(app(DatabaseManager).connection()));\n *\n * Written for SQLite, Postgres and MySQL 8 / MariaDB 10.6+ in raw SQL, as the\n * database queue driver is, and the table is the app's to create: add the\n * Prisma model from the docs, or call `createTable()`.\n *\n * - **Compare-and-set** is `UPDATE … WHERE id = ? AND state IN (…)`, so two\n * instances settling one job cannot both win.\n * - **Time** is epoch milliseconds read from the database's clock, so the\n * deadline sweep on any instance agrees on when a job is overdue.\n * - **Transactions.** `ctx.jobs.start` writes the record and queues the job\n * inside `transaction()`. On Postgres and MySQL, with the database queue\n * driver on the same connection, both rows commit together or not at all.\n * With any other queue the dispatch is held until the record has committed.\n */\nexport class DatabaseAgentJobStore implements AgentJobStore {\n readonly table: string;\n private readonly sql: SQL;\n private readonly dialect: Dialect;\n private readonly connection: string | undefined;\n\n constructor(\n connection: Pick<DatabaseConnection, \"sql\" | \"dialect\"> &\n Partial<Pick<DatabaseConnection, \"name\">>,\n options: DatabaseAgentJobStoreOptions = {},\n ) {\n const table = options.table ?? \"gemi_agent_jobs\";\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(table)) {\n throw new Error(\n `The agent jobs table name \"${table}\" is not a plain identifier. Use letters, digits and underscores.`,\n );\n }\n this.table = table;\n this.sql = connection.sql;\n this.dialect = connection.dialect;\n this.connection = connection.name;\n }\n\n /**\n * Creates the table and its indexes if they do not exist: the DDL Prisma\n * generates for the model in the docs. For tests and for an app that does\n * not manage its schema with Prisma.\n */\n async createTable(): Promise<void> {\n for (const statement of createAgentJobsTableStatements(this.dialect, this.table)) {\n await this.sql.unsafe(statement);\n }\n }\n\n /**\n * Runs `fn` in a transaction on this store's connection, joining one that is\n * already open on it. `ctx.jobs.start` writes the record and queues the job\n * in here.\n */\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n // A store built from a bare `{ sql, dialect }` has no connection name, so\n // it cannot tell its own transaction from another one, and runs without.\n if (this.connection === undefined || this.joinable()) return fn();\n return withTransaction(this.sql, () => fn(), { connection: this.connection });\n }\n\n async create(job: NewAgentJobRecord): Promise<AgentJobRecord> {\n const q = this.q();\n const now = this.clock(q);\n await q`\n INSERT INTO ${this.name(q)}\n (id, thread_id, run_id, tool_call_id, tool_name, owner, job, summary, state,\n orphaned, attachment_scope, created_at, updated_at, deadline_at)\n VALUES\n (${job.id}, ${job.threadId}, ${job.runId}, ${job.toolCallId}, ${job.toolName},\n ${job.owner}, ${job.job}, ${json(job.summary)}, 'running', 0, ${job.attachmentScope},\n ${now}, ${now}, ${now} + ${this.ms(q, job.deadlineMs)})\n `;\n const record = await this.get(job.id);\n if (!record)\n throw new Error(`The background job ${job.id} was not found after it was written.`);\n return record;\n }\n\n async get(id: string): Promise<AgentJobRecord | null> {\n const q = this.q();\n const rows: Row[] = await q`SELECT * FROM ${this.name(q)} WHERE id = ${id}`;\n return rows[0] ? recordOf(rows[0]) : null;\n }\n\n async listForThread(\n threadId: string,\n options: { states?: AgentJobState[]; limit?: number } = {},\n ): Promise<AgentJobRecord[]> {\n const q = this.q();\n const states =\n options.states === undefined\n ? q`1 = 1`\n : options.states.length === 0\n ? q`1 = 0`\n : q`state IN (${list(q, options.states)})`;\n const rows: Row[] =\n options.limit === undefined\n ? await q`\n SELECT * FROM ${this.name(q)}\n WHERE thread_id = ${threadId} AND ${states}\n ORDER BY created_at DESC, id DESC\n `\n : await q`\n SELECT * FROM ${this.name(q)}\n WHERE thread_id = ${threadId} AND ${states}\n ORDER BY created_at DESC, id DESC\n LIMIT ${Math.max(0, Math.floor(options.limit))}\n `;\n return rows.map(recordOf);\n }\n\n async transition(id: string, from: AgentJobState[], to: AgentJobUpdate): Promise<boolean> {\n if (from.length === 0) return false;\n const q = this.q();\n const now = this.clock(q);\n const sets = [q`updated_at = ${now}`];\n if (to.state !== undefined) sets.push(q`state = ${to.state}`);\n if (\"output\" in to) sets.push(q`output = ${json(to.output)}`);\n if (\"error\" in to) sets.push(q`error = ${json(to.error)}`);\n // `usage` is a reserved word in MySQL.\n if (\"usage\" in to) sets.push(q`${this.column(q, \"usage\")} = ${json(to.usage)}`);\n if (\"orphaned\" in to) sets.push(q`orphaned = ${to.orphaned ? 1 : 0}`);\n if (to.state !== undefined && to.state !== \"running\") {\n sets.push(\n to.settledAt !== undefined\n ? q`settled_at = COALESCE(settled_at, ${this.ms(q, to.settledAt)})`\n : q`settled_at = COALESCE(settled_at, ${now})`,\n );\n }\n const set = sets.reduce((all, one) => q`${all}, ${one}`);\n const result = await q`\n UPDATE ${this.name(q)} SET ${set}\n WHERE id = ${id} AND state IN (${list(q, from)})\n `;\n return affected(result) > 0;\n }\n\n async overdue(now: number, limit: number): Promise<AgentJobRecord[]> {\n const q = this.q();\n const rows: Row[] = await q`\n SELECT * FROM ${this.name(q)}\n WHERE state = 'running' AND deadline_at <= ${this.ms(q, now)}\n ORDER BY deadline_at, id\n LIMIT ${Math.max(0, Math.floor(limit))}\n `;\n return rows.map(recordOf);\n }\n\n async now(): Promise<number> {\n const q = this.q();\n const [row] = (await q`SELECT ${this.clock(q)} AS now`) as Array<{ now: unknown }>;\n return Number(row!.now);\n }\n\n /**\n * Deletes settled jobs that settled more than `olderThanMs` ago, and answers\n * how many. A settled result is written back into the thread on the next\n * turn, after which the record is only history; nothing removes it unless\n * this is called, from a cron job say. Running jobs are never pruned.\n */\n async prune(olderThanMs: number): Promise<number> {\n const q = this.q();\n const result = await q`\n DELETE FROM ${this.name(q)}\n WHERE state <> 'running' AND settled_at <= ${this.clock(q)} - ${this.ms(q, olderThanMs)}\n `;\n return affected(result);\n }\n\n /** The open ORM transaction, when it is on this store's connection. */\n private joinable(): TransactionSQL | undefined {\n if (this.connection === undefined) return undefined;\n const tx = currentTransaction();\n if (tx === undefined || currentConnectionName() !== this.connection) return undefined;\n return tx;\n }\n\n /** Read at each call and never kept: a stored transaction handle outlives its transaction. */\n private q(): SQL {\n return (this.joinable() as SQL | undefined) ?? this.sql;\n }\n\n private column(q: SQL, name: string) {\n const mysql = this.dialect === \"mysql\" || this.dialect === \"mariadb\";\n return q.unsafe(mysql ? `\\`${name}\\`` : `\"${name}\"`);\n }\n\n private name(q: SQL) {\n const mysql = this.dialect === \"mysql\" || this.dialect === \"mariadb\";\n return q.unsafe(mysql ? `\\`${this.table}\\`` : `\"${this.table}\"`);\n }\n\n /** The database's clock, in epoch milliseconds. As in `DatabaseQueueDriver`. */\n private clock(q: SQL) {\n switch (this.dialect) {\n case \"postgres\":\n return q`floor(extract(epoch from statement_timestamp()) * 1000)::bigint`;\n case \"mysql\":\n case \"mariadb\":\n return q`(TIMESTAMPDIFF(MICROSECOND, '1970-01-01 00:00:00', UTC_TIMESTAMP(6)) DIV 1000)`;\n case \"sqlite\":\n return q`CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)`;\n }\n }\n\n private ms(q: SQL, value: number) {\n const ms = Math.max(0, Math.round(value));\n return this.dialect === \"mysql\" || this.dialect === \"mariadb\"\n ? q`CAST(${ms} AS SIGNED)`\n : q`CAST(${ms} AS BIGINT)`;\n }\n}\n\nfunction list(q: SQL, values: string[]) {\n return values.map((value) => q`${value}`).reduce((all, one) => q`${all}, ${one}`);\n}\n\nfunction json(value: unknown): string | null {\n return value === undefined ? null : JSON.stringify(value);\n}\n\nfunction parse(value: unknown): unknown {\n if (value === null || value === undefined) return undefined;\n return JSON.parse(String(value));\n}\n\nfunction recordOf(row: Row): AgentJobRecord {\n const summary = parse(row.summary);\n const output = parse(row.output);\n const error = parse(row.error);\n const usage = parse(row.usage);\n return {\n id: String(row.id),\n threadId: String(row.thread_id),\n runId: String(row.run_id),\n toolCallId: String(row.tool_call_id),\n toolName: String(row.tool_name),\n owner: row.owner === null || row.owner === undefined ? null : String(row.owner),\n job: row.job === null || row.job === undefined ? null : String(row.job),\n ...(summary !== undefined ? { summary } : {}),\n state: String(row.state) as AgentJobState,\n ...(output !== undefined ? { output } : {}),\n ...(error !== undefined ? { error: error as AgentJobRecord[\"error\"] } : {}),\n ...(usage !== undefined ? { usage: usage as AgentJobRecord[\"usage\"] } : {}),\n ...(Number(row.orphaned) === 1 ? { orphaned: true as const } : {}),\n attachmentScope:\n row.attachment_scope === null || row.attachment_scope === undefined\n ? null\n : String(row.attachment_scope),\n createdAt: Number(row.created_at),\n updatedAt: Number(row.updated_at),\n deadlineAt: Number(row.deadline_at),\n ...(row.settled_at === null || row.settled_at === undefined\n ? {}\n : { settledAt: Number(row.settled_at) }),\n };\n}\n\n/** Rows a `DELETE` or `UPDATE` touched, across the three drivers. */\nfunction affected(result: unknown): number {\n const counts = result as { count?: number | null; affectedRows?: number | null };\n return Math.max(Number(counts.count ?? 0), Number(counts.affectedRows ?? 0));\n}\n\n/**\n * The table as Prisma generates it for the model in the docs, with\n * `IF NOT EXISTS` added.\n */\nexport function createAgentJobsTableStatements(dialect: Dialect, table: string): string[] {\n if (dialect === \"mysql\" || dialect === \"mariadb\") {\n return [\n `CREATE TABLE IF NOT EXISTS \\`${table}\\` (\n \\`id\\` VARCHAR(191) NOT NULL,\n \\`thread_id\\` VARCHAR(191) NOT NULL,\n \\`run_id\\` VARCHAR(191) NOT NULL,\n \\`tool_call_id\\` VARCHAR(191) NOT NULL,\n \\`tool_name\\` VARCHAR(191) NOT NULL,\n \\`owner\\` VARCHAR(191) NULL,\n \\`job\\` VARCHAR(191) NULL,\n \\`summary\\` LONGTEXT NULL,\n \\`state\\` VARCHAR(191) NOT NULL,\n \\`output\\` LONGTEXT NULL,\n \\`error\\` LONGTEXT NULL,\n \\`usage\\` LONGTEXT NULL,\n \\`orphaned\\` INTEGER NOT NULL DEFAULT 0,\n \\`attachment_scope\\` VARCHAR(191) NULL,\n \\`created_at\\` BIGINT NOT NULL,\n \\`updated_at\\` BIGINT NOT NULL,\n \\`deadline_at\\` BIGINT NOT NULL,\n \\`settled_at\\` BIGINT NULL,\n\n INDEX \\`${table}_thread_id_created_at_idx\\`(\\`thread_id\\`, \\`created_at\\`),\n INDEX \\`${table}_state_deadline_at_idx\\`(\\`state\\`, \\`deadline_at\\`),\n PRIMARY KEY (\\`id\\`)\n) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`,\n ];\n }\n\n const key = dialect === \"sqlite\" ? `\"id\" TEXT NOT NULL PRIMARY KEY,` : `\"id\" TEXT NOT NULL,`;\n const constraint =\n dialect === \"sqlite\" ? \"\" : `,\\n\\n CONSTRAINT \"${table}_pkey\" PRIMARY KEY (\"id\")`;\n return [\n `CREATE TABLE IF NOT EXISTS \"${table}\" (\n ${key}\n \"thread_id\" TEXT NOT NULL,\n \"run_id\" TEXT NOT NULL,\n \"tool_call_id\" TEXT NOT NULL,\n \"tool_name\" TEXT NOT NULL,\n \"owner\" TEXT,\n \"job\" TEXT,\n \"summary\" TEXT,\n \"state\" TEXT NOT NULL,\n \"output\" TEXT,\n \"error\" TEXT,\n \"usage\" TEXT,\n \"orphaned\" INTEGER NOT NULL DEFAULT 0,\n \"attachment_scope\" TEXT,\n \"created_at\" BIGINT NOT NULL,\n \"updated_at\" BIGINT NOT NULL,\n \"deadline_at\" BIGINT NOT NULL,\n \"settled_at\" BIGINT${constraint}\n)`,\n `CREATE INDEX IF NOT EXISTS \"${table}_thread_id_created_at_idx\" ON \"${table}\"(\"thread_id\", \"created_at\")`,\n `CREATE INDEX IF NOT EXISTS \"${table}_state_deadline_at_idx\" ON \"${table}\"(\"state\", \"deadline_at\")`,\n ];\n}\n",
|
|
17
|
-
"import {\n AgentTool,\n ToolNamespace,\n type AnyAgentTool,\n type ToolEntry,\n type ToolShapesOf,\n} from \"../../ai/Agent\";\nimport { ToolError } from \"../../ai/redact\";\nimport type { McpRouteDeclaration, McpRouter } from \"../../http/McpRouter\";\nimport { RequestContext } from \"../../http/requestContext\";\nimport type { McpRegistry, McpToolDescriptor, McpToolFilter } from \"./McpRegistry\";\n\n/** One namespace `toAgentTools` groups a tag's tools into. */\nexport type McpToolNamespaceOptions = {\n /**\n * What the model reads when deciding whether anything inside is worth\n * loading — the only description the group has. Required.\n */\n description: string;\n /** Overrides the top-level `deferred` for this namespace. */\n deferred?: boolean;\n};\n\nexport type ToAgentToolsOptions = {\n /** Narrows the tools, as `McpRegistry.descriptors` does. */\n filter?: McpToolFilter;\n /**\n * Withholds the tools' parameter schemas until the model searches for them\n * (`ToolNamespace.deferred` for a namespace, `AgentTool.deferred` for a bare\n * tool). The default for every namespace and every bare tool; a namespace\n * may override it. Purely a prompt optimization: a provider without tool\n * search is sent every schema inline, and the agent behaves the same.\n */\n deferred?: boolean;\n /**\n * Groups the tools into `ToolNamespace`s by tag: each key is a tag, and the\n * namespace's name. A tool goes into the namespace of the first of its tags\n * declared here, in the order the keys are written — tool names are unique\n * within an agent, so it cannot be in two. A tool with none of these tags\n * stays a bare tool.\n */\n namespaces?: Record<string, McpToolNamespaceOptions>;\n};\n\n// --- types, read off the router (#771) ----------------------------------------\n\ntype RoutesOf<R> = R extends { routes: infer T } ? T : never;\n\n/** Whether a filter's field narrows by literals, rather than by `string`s. */\ntype LiteralsOf<L> = L extends readonly (infer X)[] ? (string extends X ? never : X) : never;\n\n/** Whether the tool `N`, declared as `D`, passes the filter `F`. */\ntype Passes<N, D, F> =\n // `names`: kept when the filter names it, or names only `string`s.\n (F extends { names: readonly string[] }\n ? [LiteralsOf<F[\"names\"]>] extends [never]\n ? true\n : N extends LiteralsOf<F[\"names\"]>\n ? true\n : false\n : true) extends true\n ? // `tags`: kept when one of its tags is filtered for, or either side's\n // tags are only `string`s. A tool with no tags has none to match.\n F extends { tags: readonly string[] }\n ? [LiteralsOf<F[\"tags\"]>] extends [never]\n ? true\n : D extends McpRouteDeclaration<any, any, any, any, infer T>\n ? string extends T[number]\n ? true\n : [Extract<T[number], LiteralsOf<F[\"tags\"]>>] extends [never]\n ? false\n : true\n : true\n : true\n : false;\n\n/**\n * The tools of the router `R` that pass the filter `F`, as `toAgentTools`\n * builds them: named by their `routes` key, with the input the model sends and\n * the output the tool answers. An untyped router (`McpRouter<any>`, what the\n * container answers) gives `AnyAgentTool`, as before.\n */\nexport type McpAgentTool<R extends McpRouter<any>, F = {}> =\n string extends keyof RoutesOf<R>\n ? AnyAgentTool\n : {\n [N in keyof RoutesOf<R> & string]: Passes<N, RoutesOf<R>[N], F> extends true\n ? RoutesOf<R>[N] extends McpRouteDeclaration<any, any, infer I, infer O, any>\n ? AgentTool<N, I, O, never>\n : never\n : never;\n }[keyof RoutesOf<R> & string];\n\n/**\n * The client's shapes of the router's tools, as `ToolShapesOf` gives them for\n * an agent holding `toAgentTools(registry, { filter: F })`. For a chat built\n * on its tools alone; an agent mixing them with its own tools gets them from\n * `ToolShapesOf<typeof agent.tools>`.\n */\nexport type McpToolShapesOf<R extends McpRouter<any>, F = {}> = ToolShapesOf<\n McpAgentTool<R, F>[]\n>;\n\n/** What the grouped call answers: namespaces of the tools, and the bare ones. */\ntype McpToolEntry<R extends McpRouter<any>, F> =\n string extends keyof RoutesOf<R>\n ? ToolEntry\n : ToolNamespace<string, readonly McpAgentTool<R, F>[]> | McpAgentTool<R, F>;\n\ntype FilterOf<O> = O extends { filter: infer F } ? F : {};\n\n/** Namespace names are sent to the provider the way tool names are. */\nconst NAMESPACE_NAME = /^[A-Za-z0-9_-]{1,64}$/;\n\n/**\n * The registry's tools as `AgentTool`s, for an agent running in this server —\n * v1's only projection.\n *\n * Build them once and hand them to `Agent.create`. None of them holds a user:\n * the caller is `{ kind: \"local\", req }`, where `req` is the request the run is\n * executing inside, taken when the tool executes, so the same tools run as\n * whichever user's run calls them. That is the reason the caller is not an\n * argument here.\n *\n * AMBIENT, AND ONLY HERE. A run is not given a request (see `AgentContext`),\n * but these tools have no other way to act as a user: the route is dispatched\n * with the initiator's own credentials, and those live on the request. A run\n * started by `AgentController` executes inside its request, which the run holds\n * open until it settles, so the request is there to read. A run started from a\n * job or a script has none, and these tools refuse there with a sentence\n * saying so rather than dispatching as nobody.\n *\n * `requiresApproval` comes from the route's meta, where the app wrote it down;\n * it is never inferred from the verb.\n *\n * A failure the model should read — a 4xx, a missing file, a bad argument —\n * throws a `ToolError` (`McpToolError` is one), whose message is shown, and the agent loop turns a throw into a `tool_error` result the model\n * sees and can correct on its next step.\n *\n * Grouped (#758): with `namespaces`, the tools come back as `ToolNamespace`s\n * by tag, followed by the bare tools left over, ready for `Agent.create`'s\n * `tools`:\n *\n * ```ts\n * toAgentTools(registry, {\n * namespaces: {\n * pages: { description: \"Read and edit the pages of the site\" },\n * files: { description: \"Upload, list and delete files\" },\n * },\n * deferred: true,\n * });\n * ```\n *\n * The second argument is read as options when it has `filter`, `deferred` or\n * `namespaces`, and as a filter otherwise, so `toAgentTools(registry, filter)`\n * is unchanged.\n *\n * Typed (#771): given the app's router type, the tools keep their names,\n * inputs and outputs, so the client's `ToolShapesOf<typeof agent.tools>` types\n * their parts. A literal `filter` narrows them as it narrows the tools:\n *\n * ```ts\n * const registry = app(McpRegistry) as McpRegistry<SiteMcpRouter>;\n * toAgentTools(registry, { filter: { tags: [\"collections\"] } });\n * // AgentTool<\"listCollections\", { page: string | null }, { name: string }[]> | …\n * ```\n *\n * `toAgentTools<SiteMcpRouter>(app(McpRegistry), …)` types them too, but an\n * explicit type argument leaves the filter uninferred: every tool of the\n * router is in the type. An untyped registry answers `AnyAgentTool`s, as\n * before.\n */\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const F extends McpToolFilter = {},\n>(registry: McpRegistry<R> | McpRegistry, filter?: F): McpAgentTool<R, F>[];\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const O extends ToAgentToolsOptions & {\n namespaces: Record<string, McpToolNamespaceOptions>;\n } = ToAgentToolsOptions & { namespaces: Record<string, McpToolNamespaceOptions> },\n>(registry: McpRegistry<R> | McpRegistry, options: O): McpToolEntry<R, FilterOf<O>>[];\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const O extends ToAgentToolsOptions & { namespaces?: undefined } = ToAgentToolsOptions & {\n namespaces?: undefined;\n },\n>(registry: McpRegistry<R> | McpRegistry, options: O): McpAgentTool<R, FilterOf<O>>[];\n/** Options whose `namespaces` is not known statically: either shape. */\nexport function toAgentTools<R extends McpRouter<any> = McpRouter<any>>(\n registry: McpRegistry<R> | McpRegistry,\n options: ToAgentToolsOptions,\n): McpToolEntry<R, FilterOf<ToAgentToolsOptions>>[];\nexport function toAgentTools(\n registry: McpRegistry,\n arg?: McpToolFilter | ToAgentToolsOptions,\n): AnyAgentTool[] | ToolEntry[] {\n const options: ToAgentToolsOptions = isOptions(arg) ? arg : { filter: arg };\n const deferred = options.deferred === true;\n const descriptors = registry.descriptors(options.filter);\n\n if (!options.namespaces) {\n return descriptors.map((descriptor) => agentTool(registry, descriptor, deferred));\n }\n\n const declared = Object.entries(options.namespaces);\n const known = new Set(registry.descriptors().flatMap((descriptor) => descriptor.tags));\n for (const [tag, namespace] of declared) {\n if (!NAMESPACE_NAME.test(tag)) {\n throw new Error(\n `toAgentTools: \"${tag}\" is not a valid namespace name. A namespace is named by its tag and sent to the provider as a tool name is — letters, digits, \"_\" and \"-\", at most 64.`,\n );\n }\n if (typeof namespace?.description !== \"string\" || namespace.description.trim() === \"\") {\n throw new Error(\n `toAgentTools: the namespace \"${tag}\" needs a description. It is what the model reads to decide whether to look inside.`,\n );\n }\n // Checked against every tool, not the filtered ones: a filter may leave a\n // namespace empty on purpose, but a tag no tool carries is a typo, and a\n // typo here would silently leave its tools bare.\n if (!known.has(tag)) {\n throw new Error(`toAgentTools: no tool is tagged \"${tag}\", so its namespace would be empty.`);\n }\n }\n\n const grouped = new Map<string, AnyAgentTool[]>(declared.map(([tag]) => [tag, []]));\n const bare: AnyAgentTool[] = [];\n for (const descriptor of descriptors) {\n const tag = declared.find(([name]) => descriptor.tags.includes(name))?.[0];\n if (tag === undefined) {\n bare.push(agentTool(registry, descriptor, deferred));\n } else {\n // Deferral is the namespace's, not the tool's: `ToolNamespace.deferred`\n // covers its members, and a member deferred on its own would stay\n // deferred under a namespace that set `deferred: false`.\n grouped.get(tag)!.push(agentTool(registry, descriptor, false));\n }\n }\n\n const entries: ToolEntry[] = [];\n for (const [tag, namespace] of declared) {\n const tools = grouped.get(tag)!;\n // Emptied by the filter. A namespace with nothing in it is a description\n // the model would search for nothing.\n if (tools.length === 0) continue;\n entries.push(\n ToolNamespace.create({\n name: tag,\n description: namespace.description,\n tools,\n deferred: namespace.deferred ?? deferred,\n }),\n );\n }\n return [...entries, ...bare];\n}\n\nfunction isOptions(arg: unknown): arg is ToAgentToolsOptions {\n return (\n typeof arg === \"object\" &&\n arg !== null &&\n (\"filter\" in arg || \"namespaces\" in arg || \"deferred\" in arg)\n );\n}\n\nfunction agentTool(\n registry: McpRegistry,\n descriptor: McpToolDescriptor,\n deferred: boolean,\n): AnyAgentTool {\n return AgentTool.create({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: descriptor.inputSchema,\n ...(descriptor.outputSchema ? { outputSchema: descriptor.outputSchema } : {}),\n requiresApproval: descriptor.requiresApproval,\n deferred,\n execute: (input, ctx) => {\n const req = RequestContext.getStore()?.req;\n if (!req) {\n throw new ToolError(\n `\"${descriptor.name}\" calls an api route as the user who started this run, and this run was not started inside a request. Run it from an AgentController, or give this agent tools that do not go through the MCP registry.`,\n );\n }\n return registry.execute({ kind: \"local\", req }, descriptor.name, input, ctx);\n },\n });\n}\n",
|
|
8
|
+
"import {\n AgentTool,\n ToolNamespace,\n type AnyAgentTool,\n type ToolEntry,\n type ToolShapesOf,\n} from \"../../ai/Agent\";\nimport { ToolError } from \"../../ai/redact\";\nimport type {\n McpRouteDeclaration,\n McpRouter,\n McpToolDeclaration,\n} from \"../../http/McpRouter\";\nimport { RequestContext } from \"../../http/requestContext\";\nimport type { McpRegistry, McpToolDescriptor, McpToolFilter } from \"./McpRegistry\";\n\n/** One namespace `toAgentTools` groups a tag's tools into. */\nexport type McpToolNamespaceOptions = {\n /**\n * What the model reads when deciding whether anything inside is worth\n * loading — the only description the group has. Required.\n */\n description: string;\n /** Overrides the top-level `deferred` for this namespace. */\n deferred?: boolean;\n};\n\nexport type ToAgentToolsOptions = {\n /** Narrows the tools, as `McpRegistry.descriptors` does. */\n filter?: McpToolFilter;\n /**\n * Withholds the tools' parameter schemas until the model searches for them\n * (`ToolNamespace.deferred` for a namespace, `AgentTool.deferred` for a bare\n * tool). The default for every namespace and every bare tool; a namespace\n * may override it. Purely a prompt optimization: a provider without tool\n * search is sent every schema inline, and the agent behaves the same.\n */\n deferred?: boolean;\n /**\n * Groups the tools into `ToolNamespace`s by tag: each key is a tag, and the\n * namespace's name. A tool goes into the namespace of the first of its tags\n * declared here, in the order the keys are written — tool names are unique\n * within an agent, so it cannot be in two. A tool with none of these tags\n * stays a bare tool.\n */\n namespaces?: Record<string, McpToolNamespaceOptions>;\n};\n\n// --- types, read off the router (#771) ----------------------------------------\n\ntype RoutesOf<R> = R extends { routes: infer T } ? T : never;\n\n/** What a declaration types its tool as: a route's or a native tool's (#759). */\ntype ToolTypesOf<D> =\n D extends McpRouteDeclaration<any, any, infer I, infer O, infer T>\n ? { input: I; output: O; tags: T; progress: never }\n : D extends McpToolDeclaration<infer I, infer O, infer T, infer P>\n ? { input: I; output: O; tags: T; progress: P }\n : never;\n\n/** Whether a filter's field narrows by literals, rather than by `string`s. */\ntype LiteralsOf<L> = L extends readonly (infer X)[] ? (string extends X ? never : X) : never;\n\n/** Whether the tool `N`, declared as `D`, passes the filter `F`. */\ntype Passes<N, D, F> =\n // `names`: kept when the filter names it, or names only `string`s.\n (F extends { names: readonly string[] }\n ? [LiteralsOf<F[\"names\"]>] extends [never]\n ? true\n : N extends LiteralsOf<F[\"names\"]>\n ? true\n : false\n : true) extends true\n ? // `tags`: kept when one of its tags is filtered for, or either side's\n // tags are only `string`s. A tool with no tags has none to match.\n F extends { tags: readonly string[] }\n ? [LiteralsOf<F[\"tags\"]>] extends [never]\n ? true\n : ToolTypesOf<D> extends { tags: infer T extends readonly string[] }\n ? string extends T[number]\n ? true\n : [Extract<T[number], LiteralsOf<F[\"tags\"]>>] extends [never]\n ? false\n : true\n : true\n : true\n : false;\n\n/**\n * The tools of the router `R` that pass the filter `F`, as `toAgentTools`\n * builds them: named by their `routes` key, with the input the model sends and\n * the output the tool answers. An untyped router (`McpRouter<any>`, what the\n * container answers) gives `AnyAgentTool`, as before.\n */\nexport type McpAgentTool<R extends McpRouter<any>, F = {}> =\n string extends keyof RoutesOf<R>\n ? AnyAgentTool\n : {\n [N in keyof RoutesOf<R> & string]: Passes<N, RoutesOf<R>[N], F> extends true\n ? ToolTypesOf<RoutesOf<R>[N]> extends {\n input: infer I;\n output: infer O;\n progress: infer P;\n }\n ? AgentTool<N, I, O, P>\n : never\n : never;\n }[keyof RoutesOf<R> & string];\n\n/**\n * The client's shapes of the router's tools, as `ToolShapesOf` gives them for\n * an agent holding `toAgentTools(registry, { filter: F })`. For a chat built\n * on its tools alone; an agent mixing them with its own tools gets them from\n * `ToolShapesOf<typeof agent.tools>`.\n */\nexport type McpToolShapesOf<R extends McpRouter<any>, F = {}> = ToolShapesOf<\n McpAgentTool<R, F>[]\n>;\n\n/** What the grouped call answers: namespaces of the tools, and the bare ones. */\ntype McpToolEntry<R extends McpRouter<any>, F> =\n string extends keyof RoutesOf<R>\n ? ToolEntry\n : ToolNamespace<string, readonly McpAgentTool<R, F>[]> | McpAgentTool<R, F>;\n\ntype FilterOf<O> = O extends { filter: infer F } ? F : {};\n\n/** Namespace names are sent to the provider the way tool names are. */\nconst NAMESPACE_NAME = /^[A-Za-z0-9_-]{1,64}$/;\n\n/**\n * The registry's tools as `AgentTool`s, for an agent running in this server —\n * v1's only projection.\n *\n * Build them once and hand them to `Agent.create`. None of them holds a user:\n * the caller is `{ kind: \"local\", req }`, where `req` is the request the run is\n * executing inside, taken when the tool executes, so the same tools run as\n * whichever user's run calls them. That is the reason the caller is not an\n * argument here.\n *\n * AMBIENT, AND ONLY HERE. A run is not given a request (see `AgentContext`),\n * but these tools have no other way to act as a user: the route is dispatched\n * with the initiator's own credentials, and those live on the request. A run\n * started by `AgentController` executes inside its request, which the run holds\n * open until it settles, so the request is there to read. A run started from a\n * job or a script has none, and these tools refuse there with a sentence\n * saying so rather than dispatching as nobody.\n *\n * `requiresApproval` comes from the route's meta, where the app wrote it down;\n * it is never inferred from the verb.\n *\n * A failure the model should read — a 4xx, a missing file, a bad argument —\n * throws a `ToolError` (`McpToolError` is one), whose message is shown, and the agent loop turns a throw into a `tool_error` result the model\n * sees and can correct on its next step.\n *\n * Grouped (#758): with `namespaces`, the tools come back as `ToolNamespace`s\n * by tag, followed by the bare tools left over, ready for `Agent.create`'s\n * `tools`:\n *\n * ```ts\n * toAgentTools(registry, {\n * namespaces: {\n * pages: { description: \"Read and edit the pages of the site\" },\n * files: { description: \"Upload, list and delete files\" },\n * },\n * deferred: true,\n * });\n * ```\n *\n * The second argument is read as options when it has `filter`, `deferred` or\n * `namespaces`, and as a filter otherwise, so `toAgentTools(registry, filter)`\n * is unchanged.\n *\n * Typed (#771): given the app's router type, the tools keep their names,\n * inputs and outputs, so the client's `ToolShapesOf<typeof agent.tools>` types\n * their parts. A literal `filter` narrows them as it narrows the tools:\n *\n * ```ts\n * const registry = app(McpRegistry) as McpRegistry<SiteMcpRouter>;\n * toAgentTools(registry, { filter: { tags: [\"collections\"] } });\n * // AgentTool<\"listCollections\", { page: string | null }, { name: string }[]> | …\n * ```\n *\n * `toAgentTools<SiteMcpRouter>(app(McpRegistry), …)` types them too, but an\n * explicit type argument leaves the filter uninferred: every tool of the\n * router is in the type. An untyped registry answers `AnyAgentTool`s, as\n * before.\n */\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const F extends McpToolFilter = {},\n>(registry: McpRegistry<R> | McpRegistry, filter?: F): McpAgentTool<R, F>[];\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const O extends ToAgentToolsOptions & {\n namespaces: Record<string, McpToolNamespaceOptions>;\n } = ToAgentToolsOptions & { namespaces: Record<string, McpToolNamespaceOptions> },\n>(registry: McpRegistry<R> | McpRegistry, options: O): McpToolEntry<R, FilterOf<O>>[];\nexport function toAgentTools<\n R extends McpRouter<any> = McpRouter<any>,\n const O extends ToAgentToolsOptions & { namespaces?: undefined } = ToAgentToolsOptions & {\n namespaces?: undefined;\n },\n>(registry: McpRegistry<R> | McpRegistry, options: O): McpAgentTool<R, FilterOf<O>>[];\n/** Options whose `namespaces` is not known statically: either shape. */\nexport function toAgentTools<R extends McpRouter<any> = McpRouter<any>>(\n registry: McpRegistry<R> | McpRegistry,\n options: ToAgentToolsOptions,\n): McpToolEntry<R, FilterOf<ToAgentToolsOptions>>[];\nexport function toAgentTools(\n registry: McpRegistry,\n arg?: McpToolFilter | ToAgentToolsOptions,\n): AnyAgentTool[] | ToolEntry[] {\n const options: ToAgentToolsOptions = isOptions(arg) ? arg : { filter: arg };\n const deferred = options.deferred === true;\n const descriptors = registry.descriptors(options.filter);\n\n if (!options.namespaces) {\n return descriptors.map((descriptor) => agentTool(registry, descriptor, deferred));\n }\n\n const declared = Object.entries(options.namespaces);\n const known = new Set(registry.descriptors().flatMap((descriptor) => descriptor.tags));\n for (const [tag, namespace] of declared) {\n if (!NAMESPACE_NAME.test(tag)) {\n throw new Error(\n `toAgentTools: \"${tag}\" is not a valid namespace name. A namespace is named by its tag and sent to the provider as a tool name is — letters, digits, \"_\" and \"-\", at most 64.`,\n );\n }\n if (typeof namespace?.description !== \"string\" || namespace.description.trim() === \"\") {\n throw new Error(\n `toAgentTools: the namespace \"${tag}\" needs a description. It is what the model reads to decide whether to look inside.`,\n );\n }\n // Checked against every tool, not the filtered ones: a filter may leave a\n // namespace empty on purpose, but a tag no tool carries is a typo, and a\n // typo here would silently leave its tools bare.\n if (!known.has(tag)) {\n throw new Error(`toAgentTools: no tool is tagged \"${tag}\", so its namespace would be empty.`);\n }\n }\n\n const grouped = new Map<string, AnyAgentTool[]>(declared.map(([tag]) => [tag, []]));\n const bare: AnyAgentTool[] = [];\n for (const descriptor of descriptors) {\n const tag = declared.find(([name]) => descriptor.tags.includes(name))?.[0];\n if (tag === undefined) {\n bare.push(agentTool(registry, descriptor, deferred));\n } else {\n // Deferral is the namespace's, not the tool's: `ToolNamespace.deferred`\n // covers its members, and a member deferred on its own would stay\n // deferred under a namespace that set `deferred: false`.\n grouped.get(tag)!.push(agentTool(registry, descriptor, false));\n }\n }\n\n const entries: ToolEntry[] = [];\n for (const [tag, namespace] of declared) {\n const tools = grouped.get(tag)!;\n // Emptied by the filter. A namespace with nothing in it is a description\n // the model would search for nothing.\n if (tools.length === 0) continue;\n entries.push(\n ToolNamespace.create({\n name: tag,\n description: namespace.description,\n tools,\n deferred: namespace.deferred ?? deferred,\n }),\n );\n }\n return [...entries, ...bare];\n}\n\nfunction isOptions(arg: unknown): arg is ToAgentToolsOptions {\n return (\n typeof arg === \"object\" &&\n arg !== null &&\n (\"filter\" in arg || \"namespaces\" in arg || \"deferred\" in arg)\n );\n}\n\nfunction agentTool(\n registry: McpRegistry,\n descriptor: McpToolDescriptor,\n deferred: boolean,\n): AnyAgentTool {\n if (descriptor.kind === \"tool\") return nativeAgentTool(registry, descriptor, deferred);\n return AgentTool.create({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: descriptor.inputSchema,\n ...(descriptor.outputSchema ? { outputSchema: descriptor.outputSchema } : {}),\n requiresApproval: descriptor.requiresApproval,\n deferred,\n execute: (input, ctx) => {\n const req = RequestContext.getStore()?.req;\n if (!req) {\n throw new ToolError(\n `\"${descriptor.name}\" calls an api route as the user who started this run, and this run was not started inside a request. Run it from an AgentController, or give this agent tools that do not go through the MCP registry.`,\n );\n }\n return registry.execute({ kind: \"local\", req }, descriptor.name, input, ctx);\n },\n });\n}\n\n/**\n * A native tool (#759), projected back to an `AgentTool` under its `routes`\n * key. Its `execute` hands the run's own `ToolContext` to the registered tool\n * and returns what that returns — so its yields are `tool-progress`, its job\n * handle a background job — with `mcpCallOf(ctx)` naming the local caller.\n *\n * Unlike a route, it needs no request to run: a run started from a job\n * executes it as the agent would have executed the tool directly, with\n * `mcpCallOf(ctx)` answering `undefined`.\n */\nfunction nativeAgentTool(\n registry: McpRegistry,\n descriptor: McpToolDescriptor,\n deferred: boolean,\n): AnyAgentTool {\n const native = registry.nativeTool(descriptor.name);\n return AgentTool.create({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: descriptor.inputSchema,\n ...(descriptor.outputSchema ? { outputSchema: descriptor.outputSchema } : {}),\n requiresApproval: descriptor.requiresApproval,\n deferred,\n ...(native.timeoutMs !== undefined ? { timeoutMs: native.timeoutMs } : {}),\n ...(native.async ? { async: native.async } : {}),\n execute: ((input: unknown, ctx) => {\n const req = RequestContext.getStore()?.req;\n return registry.startNative(req ? { kind: \"local\", req } : undefined, descriptor.name, input, ctx);\n }) as NonNullable<AnyAgentTool[\"execute\"]>,\n });\n}\n",
|
|
18
9
|
"import type { ImageProvider } from \"./ImageProvider\";\nimport type { ImageResponse } from \"./providers/images\";\nimport type { Usage } from \"./types\";\n\n/**\n * A named image model with its settings, the way `Agent` is a named text model\n * with its settings.\n *\n * `ImageModel`, not `Image`, because `Image` is already gemi's `<img>` srcset\n * component (`client/Image.tsx`). Different entrypoints, so nothing collides\n * technically — and a page builder, which is what this feature is for, imports\n * both in the same file.\n *\n * export const banner = ImageModel.create({\n * name: \"banner\",\n * provider: AzureOpenAIImageProvider.model(\"gpt-image-2\"),\n * size: \"1536x1024\",\n * quality: \"high\",\n * });\n *\n * const { image, mimeType } = await banner.generate({ prompt });\n * await Storage.put({ name: `pages/${id}/hero.png`, body: image, contentType: mimeType });\n *\n * Inside an agent tool, call `ctx.generateImage(banner, …)` instead: it memoizes\n * the render against the tool call so a replay does not pay for it twice, and it\n * parks the bytes as an attachment. See `ToolContext.generateImage`.\n */\n\n/**\n * `WIDTHxHEIGHT`, or `auto`.\n *\n * NOT A CLOSED UNION OF THREE LITERALS, which is what the older image models\n * allowed and what a first draft of this type was. `gpt-image-2` takes arbitrary\n * dimensions, and a page builder deriving a size from a layout slot's aspect\n * ratio is precisely the caller that needs them.\n */\nexport type ImageSize = `${number}x${number}` | \"auto\";\nexport type ImageQuality = \"low\" | \"medium\" | \"high\" | \"auto\";\nexport type ImageBackground = \"transparent\" | \"opaque\" | \"auto\";\n\n/**\n * `png` or `jpeg`. Not `webp`, although every source lists it — measured against\n * `gpt-image-2`:\n *\n * 400 Invalid value: 'webp'. Supported values are: 'png' and 'jpeg'.\n * param: output_format\n */\nexport type ImageFormat = \"png\" | \"jpeg\";\n\ntype Settings = {\n size?: ImageSize;\n quality?: ImageQuality;\n background?: ImageBackground;\n format?: ImageFormat;\n /** JPEG quality, 0–100. Ignored by the vendor for PNG. */\n compression?: number;\n};\n\nexport type CreateImageModelParams = Settings & {\n /** For logs and, later, telemetry — the same role `Agent.name` plays. */\n name: string;\n provider: ImageProvider;\n};\n\nexport type GenerateImageParams = Settings & {\n prompt: string;\n /** Aborts the render. Inside a tool, `ctx.generateImage` passes the run's. */\n signal?: AbortSignal;\n};\n\nexport type ImageInput = Blob | File;\n\nexport type EditImageParams = GenerateImageParams & {\n /**\n * The images to edit, at least one. Typed as a non-empty tuple so an empty\n * array is a compile error rather than a paid call that quietly generates from\n * scratch.\n */\n images: [ImageInput, ...ImageInput[]];\n /**\n * A PNG with an alpha channel, the same dimensions as the input. The\n * **transparent** region is the part to replace.\n *\n * MEASURED, and honoured rather than merely accepted: with a transparent\n * centre square and the prompt \"put a yellow star in the masked area\", the\n * centre came back yellow and the surrounding ring kept the original colour,\n * while the same edit without a mask recoloured the whole image.\n */\n mask?: ImageInput;\n};\n\n/**\n * One generated image.\n *\n * NO `revisedPrompt`. It was in the original design, the requesting app asked\n * for it, and `gpt-image-2` does not return one — five successful responses,\n * generations and edits, none carrying `revised_prompt`. A field that is always\n * `undefined` teaches callers to write dead branches; adding it back if a model\n * ever populates it is not a breaking change.\n */\nexport type GeneratedImage = {\n /** The bytes, with `type` set — ready for `Storage.put` or\n * `ctx.attachments.put`, neither of which accepts a `Uint8Array`. */\n image: Blob;\n mimeType: string;\n /**\n * What was actually produced, read off the response and never assumed.\n *\n * MEASURED: an edit sent with no `size` answered `1254x1254` — neither a size\n * anyone asked for nor a multiple of 16. So the divisible-by-16 rule below\n * constrains the *request* and says nothing about the answer.\n */\n size: string;\n usage: Usage;\n};\n\n/** The measured request rules. Each one is a real 400, quoted. */\nfunction assertSize(size: string): void {\n if (size === \"auto\") return;\n\n const match = /^(\\d+)x(\\d+)$/.exec(size);\n if (!match) {\n throw new Error(`An image size is \"WIDTHxHEIGHT\" or \"auto\"; got ${JSON.stringify(size)}.`);\n }\n\n const width = Number(match[1]);\n const height = Number(match[2]);\n\n // 400 Invalid size '1000x1000'. Width and height must both be divisible by 16.\n if (width % 16 !== 0 || height % 16 !== 0) {\n throw new Error(\n `Image size ${size} is not supported: width and height must both be divisible by 16.`,\n );\n }\n\n // 400 Invalid size '1024x256'. The maximum supported aspect ratio is 3:1.\n if (Math.max(width / height, height / width) > 3) {\n throw new Error(\n `Image size ${size} is not supported: the maximum aspect ratio is 3:1, either way up.`,\n );\n }\n}\n\nfunction assertSettings(settings: Settings, where: string): void {\n if (settings.size !== undefined) {\n try {\n assertSize(settings.size);\n } catch (error) {\n throw new Error(`${where}: ${(error as Error).message}`);\n }\n }\n\n // 400 Transparent background is not supported for JPEG output format\n if (settings.background === \"transparent\" && settings.format === \"jpeg\") {\n throw new Error(`${where}: a transparent background needs \"png\"; JPEG has no alpha channel.`);\n }\n\n if (settings.compression !== undefined) {\n const value = settings.compression;\n if (!Number.isInteger(value) || value < 0 || value > 100) {\n throw new Error(`${where}: compression is an integer from 0 to 100; got ${value}.`);\n }\n }\n}\n\nfunction toBlob(input: ImageInput, fallbackName: string): File {\n if (input instanceof File) return input;\n // A Blob built from raw bytes has no name, and the vendor reads the part's\n // filename: an extensionless part is answered with a type error rather than a\n // useful one.\n const type = input.type || \"image/png\";\n const extension = type === \"image/jpeg\" ? \"jpg\" : (type.split(\"/\")[1] ?? \"png\");\n return new File([input], `${fallbackName}.${extension}`, { type });\n}\n\nexport class ImageModel {\n readonly name: string;\n readonly provider: ImageProvider;\n private readonly settings: Settings;\n\n private constructor(params: CreateImageModelParams) {\n const { name, provider, ...settings } = params;\n // Checked here as well as per call, so a bad default fails when the module\n // loads rather than on whichever request first happens to hit it.\n assertSettings(settings, `ImageModel \"${name}\"`);\n this.name = name;\n this.provider = provider;\n this.settings = settings;\n }\n\n static create(params: CreateImageModelParams): ImageModel {\n return new ImageModel(params);\n }\n\n async generate(params: GenerateImageParams): Promise<GeneratedImage> {\n const merged = this.merge(params);\n return present(\n await this.provider.generate({ prompt: params.prompt, ...merged, signal: params.signal }),\n );\n }\n\n /**\n * Edits one or more images.\n *\n * A SEPARATE METHOD, not an `images?` on `generate`. One method would mean an\n * `images` that arrives `undefined` — a mistyped field, a destructure of the\n * wrong object — silently generates a fresh image instead of editing: the\n * wrong picture, no error, on a call that is billed either way. Requiring a\n * non-empty `images` here makes \"edit with nothing to edit\" unspellable.\n */\n async edit(params: EditImageParams): Promise<GeneratedImage> {\n const merged = this.merge(params);\n return present(\n await this.provider.edit({\n prompt: params.prompt,\n ...merged,\n images: params.images.map((image, index) => toBlob(image, `image-${index}`)),\n ...(params.mask ? { mask: toBlob(params.mask, \"mask\") } : {}),\n signal: params.signal,\n }),\n );\n }\n\n /** Per-call params over the model's defaults, validated as one. */\n private merge(params: Settings): Settings {\n const merged: Settings = {\n ...this.settings,\n ...(params.size !== undefined ? { size: params.size } : {}),\n ...(params.quality !== undefined ? { quality: params.quality } : {}),\n ...(params.background !== undefined ? { background: params.background } : {}),\n ...(params.format !== undefined ? { format: params.format } : {}),\n ...(params.compression !== undefined ? { compression: params.compression } : {}),\n };\n // The merged pair is what matters: a model with `background: \"transparent\"`\n // and a call passing `format: \"jpeg\"` is the combination the vendor rejects,\n // and neither half is wrong on its own.\n assertSettings(merged, `ImageModel \"${this.name}\"`);\n return merged;\n }\n}\n\nfunction present(response: ImageResponse): GeneratedImage {\n return {\n image: new Blob([response.bytes as BlobPart], { type: response.mimeType }),\n mimeType: response.mimeType,\n size: response.size,\n usage: response.usage,\n };\n}\n",
|
|
19
10
|
"/**\n * Where a vendor lives, and who we are to it — resolved once, for every kind of\n * call.\n *\n * WHY THIS IS ITS OWN MODULE. The Responses path and the images path differ only\n * in the last segment of the URL. Everything before it — which host, whether the\n * configured endpoint already carried `/openai`, whether the api-version is\n * dated and therefore routes to the older path, whether to send `authorization:\n * Bearer` or `api-key`, whether an Entra token has to be minted again because\n * the last one expired mid-conversation — is identical, and every line of it was\n * worked out by measuring a real resource rather than reading documentation (the\n * transcripts are on `azureBase` below).\n *\n * That is exactly the kind of knowledge that must not be copied. A second copy\n * in an image provider would be correct on the day it was written and would\n * drift on the first fix that only one of them got, and the symptom of the drift\n * is a 404 on every request for whichever apps configured the provider the\n * documented way — which is the bug `azureBase` exists because of.\n *\n * So a provider resolves a `ProviderTarget` and appends its own path. Nothing\n * here knows about Responses, files or images.\n */\n\nexport type ProviderConfig = {\n apiKey?: string;\n baseURL?: string;\n timeoutMs?: number;\n maxRetries?: number;\n headers?: Record<string, string>;\n};\n\nexport type AzureConfig = ProviderConfig & {\n /**\n * The resource host, with or without a trailing `/openai`. Both spellings\n * work — `https://<resource>.cognitiveservices.azure.com` and\n * `https://<resource>.openai.azure.com` — and neither is rewritten, because\n * only one of them exists for a resource that was not created as\n * kind=OpenAI. See `azureBase` for what is done to it.\n */\n endpoint?: string;\n /**\n * Just the resource name, when there is no endpoint to hand. `<name>` is\n * expanded to `https://<name>.cognitiveservices.azure.com/openai`.\n */\n resourceName?: string;\n apiVersion?: string;\n /**\n * The deployment to call, when it is not named after the model. Azure lets\n * whoever ran the template call it anything, and plenty of them are called\n * `prod` — this is the override the class comment promises.\n */\n deployment?: string;\n /**\n * For Entra ID instead of a key. A function, not a token, because these\n * expire mid-conversation.\n */\n getToken?: () => Promise<string>;\n};\n\n/**\n * A resolved vendor, ready for a path to be appended.\n *\n * `base` and `query` are separate because Azure's api-version is a query\n * parameter and a caller appending `/images/generations` must not have to know\n * that it goes *before* the `?`. Every URL is `${base}${path}${query}`.\n */\nexport type ProviderTarget = {\n /** e.g. `https://api.openai.com/v1`, or `https://<host>/openai/v1`. */\n base: string;\n /** e.g. `` or `?api-version=preview`. Already encoded. */\n query: string;\n /** Called per request. See the Azure branch for why that is not an accident. */\n headers: () => Promise<Record<string, string>>;\n timeoutMs: number;\n maxRetries: number;\n};\n\n/** Long enough for a reasoning model to think before it says anything, short\n * enough that a hung connection is not mistaken for a slow one. For a streamed\n * call it only covers getting a response; the stream that follows has no\n * deadline. For a one-shot call it is the whole deadline — which is why the\n * images path sets its own, and why `retryTimeouts` exists. */\nexport const DEFAULT_TIMEOUT_MS = 120_000;\nexport const DEFAULT_MAX_RETRIES = 2;\n\nexport function env(name: string): string | undefined {\n return typeof process === \"undefined\" ? undefined : process.env?.[name];\n}\n\n/**\n * `preview` selects Azure's `/openai/v1` surface, which is the OpenAI-shaped\n * one — same request body, same SSE frames, same `model` field naming the\n * deployment — and it is the only surface the Responses API has that gemi's\n * request builder can talk to unchanged. It takes no dated version: sending\n * `api-version=2025-04-01-preview` to `/openai/v1/responses` answers\n * `400 {\"code\":\"BadRequest\",\"message\":\"API version not supported\"}`.\n *\n * A dated version is still honoured, and routes to the older\n * `/openai/responses` path instead — see `azurePath`. So an app that pinned\n * one keeps working, which is the promise the old comment here made and could\n * not keep once the paths diverged.\n */\nexport const AZURE_API_VERSION = \"preview\";\n\n/**\n * Where an Azure call goes, worked out live rather than from docs.\n *\n * THE PROBLEM THIS SOLVES. `AZURE_OPENAI_ENDPOINT` is conventionally written\n * with `/openai` already on the end, and the old code appended `/openai` again\n * and then a deployment path, producing\n * `…/openai/openai/deployments/<dep>/responses` — a 404 on every request, for\n * every app that configured the provider the documented way. Two separate\n * mistakes were stacked there, and only measuring told them apart.\n *\n * WHAT WAS MEASURED, against a real resource, POSTing a Responses body:\n *\n * 404 {endpoint}/openai/deployments/gpt-5.4/responses?api-version=2025-04-01-preview\n * 404 {host}/openai/deployments/gpt-5.4/responses?api-version=2025-04-01-preview\n * 404 {host}/openai/deployments/gpt-5.4/responses?api-version=preview\n * 400 {host}/openai/v1/responses?api-version=2025-04-01-preview (\"API version not supported\")\n * 200 {host}/openai/v1/responses?api-version=preview\n * 200 {host}/openai/v1/responses (no api-version at all)\n * 200 {host}/openai/responses?api-version=2025-04-01-preview\n *\n * for {host} in BOTH `https://<resource>.cognitiveservices.azure.com` and\n * `https://<resource>.openai.azure.com` — both spellings answered identically,\n * so the host was never the variable. The deployment-in-the-URL path is the\n * Chat Completions shape and the Responses API does not serve it at all; the\n * deployment goes in the body's `model`, which is what `buildResponsesRequest`\n * already puts there.\n *\n * `/openai/v1/files?api-version=preview` and\n * `/openai/files?api-version=2025-04-01-preview` were both checked too (200,\n * empty list), so uploads follow the same fork.\n *\n * And so do images, measured the same way against a `gpt-image-2` deployment:\n *\n * 200 {host}/openai/v1/images/generations?api-version=preview\n * 200 {host}/openai/v1/images/edits?api-version=preview\n *\n * which is the whole reason this function is shared rather than reimplemented.\n */\nexport function azureBase(raw: string): string {\n const trimmed = raw.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return \"\";\n // A configured endpoint may or may not already carry `/openai`, and may even\n // carry `/openai/v1` if someone copied a full URL. Normalize down to the\n // resource base and put exactly one `/openai` back, rather than appending\n // blind — appending blind is the bug.\n const base = trimmed.replace(/\\/openai(?:\\/v1)?$/i, \"\");\n return `${base}/openai`;\n}\n\n/** Dated versions belong to the older path; `preview` (and anything that is not\n * a date) belongs to `/v1`. Both were verified above. */\nexport function azurePath(apiVersion: string): string {\n return /^\\d{4}-\\d{2}-\\d{2}/.test(apiVersion) ? \"\" : \"/v1\";\n}\n\n/** Overrides for a call whose deadline is not a streaming handshake's. */\nexport type TargetDefaults = { timeoutMs?: number };\n\nexport function openAITarget(\n config: ProviderConfig,\n defaults: TargetDefaults = {},\n): ProviderTarget {\n const base = (config.baseURL ?? env(\"OPENAI_BASE_URL\") ?? \"https://api.openai.com/v1\").replace(\n /\\/+$/,\n \"\",\n );\n\n return {\n base,\n query: \"\",\n headers: async () => {\n const apiKey = config.apiKey ?? env(\"OPENAI_API_KEY\");\n return {\n ...(apiKey ? { authorization: `Bearer ${apiKey}` } : {}),\n ...config.headers,\n };\n },\n timeoutMs: config.timeoutMs ?? defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n };\n}\n\n/**\n * The resource base, `<host>/openai`, from whichever of the three ways it was\n * configured. A bare resource name expands to the `cognitiveservices` host\n * rather than the `openai.azure.com` one: both answer for a resource created\n * as kind=OpenAI, only `cognitiveservices` answers for an AI Foundry or\n * multi-service resource, so it is the spelling that is right more often. An\n * app on the other one sets `endpoint` and nothing rewrites it.\n */\nexport function azureResourceBase(config: AzureConfig): string {\n const configured = config.baseURL ?? config.endpoint ?? env(\"AZURE_OPENAI_ENDPOINT\");\n if (configured) return azureBase(configured);\n const resource =\n config.resourceName ?? env(\"AZURE_OPENAI_RESOURCE_NAME\") ?? env(\"AZURE_RESOURCE_NAME\");\n return resource ? azureBase(`https://${resource.trim()}.cognitiveservices.azure.com`) : \"\";\n}\n\nexport function azureTarget(config: AzureConfig, defaults: TargetDefaults = {}): ProviderTarget {\n const apiVersion = config.apiVersion ?? env(\"AZURE_OPENAI_API_VERSION\") ?? AZURE_API_VERSION;\n\n return {\n base: `${azureResourceBase(config)}${azurePath(apiVersion)}`,\n query: `?api-version=${encodeURIComponent(apiVersion)}`,\n headers: async () => {\n // Called per request, not per provider: an Entra token minted when the\n // app booted is expired by the time a long conversation reaches step\n // nine, and that failure looks like a random 401 in the middle of a\n // working feature.\n if (config.getToken) {\n return { authorization: `Bearer ${await config.getToken()}`, ...config.headers };\n }\n const apiKey = config.apiKey ?? env(\"AZURE_OPENAI_API_KEY\");\n return { ...(apiKey ? { \"api-key\": apiKey } : {}), ...config.headers };\n },\n timeoutMs: config.timeoutMs ?? defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n };\n}\n",
|
|
20
11
|
"import { normalizeProviderError, ProviderHttpError, ProviderTimeoutError } from \"./errors\";\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>;\n\nexport type RequestOptions = {\n maxRetries: number;\n timeoutMs: number;\n signal?: AbortSignal;\n /** Injected by the tests. Nothing here should ever need a real socket to be\n * exercised, and a retry policy that is only tested against a live API is\n * one that gets tested during an outage. */\n fetchImpl?: FetchLike;\n /** Takes the caller's signal so the default can clear its timer rather than\n * hold the process open for a backoff nobody is waiting for any more. An\n * injected sleep may ignore it: the wait is raced against the abort either\n * way. */\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n random?: () => number;\n now?: () => number;\n /**\n * Whether a timeout is worth another attempt. Defaults to `true`.\n *\n * THE ANSWER DEPENDS ON WHAT THE TIMER BOUNDS, which is why this is a\n * parameter and not a policy. For a streamed call the timer covers getting a\n * response and is cleared once the headers land (see `requestWithRetry`), so a\n * timeout means the provider never started answering: nothing was generated,\n * nothing was billed, and retrying is both cheap and likely to work.\n *\n * For a call that returns its whole result in one body, the same timer bounds\n * the *work*. A timeout there means the work probably happened and we hung up\n * before hearing about it — so a retry pays for it a second time, at the same\n * latency, and most likely times out again.\n *\n * MEASURED, because the margin is what makes this urgent rather than\n * theoretical. One `gpt-image-2` render at `quality: \"high\"`, `1536x1024`,\n * against a real Azure deployment: **117.8 seconds**, against a\n * `DEFAULT_TIMEOUT_MS` of 120_000. Two seconds of headroom, about 2%. Any\n * variance crosses it, and with retries on, one such request becomes three\n * two-minute renders, six minutes of waiting, three images billed, and a\n * `ProviderTimeoutError` returned to the caller. (For scale: the same model at\n * `low`/1024² answers in 15s, and an edit in 14–20s.)\n *\n * So the image path passes `false` and the streaming path leaves it alone. A\n * 429 or a 5xx is still retried in both cases: those say the request did not\n * run, which is the opposite of what a timeout says here.\n */\n retryTimeouts?: boolean;\n};\n\n/** The floor of the backoff. Doubling from here gives 0.5s, 1s, 2s, 4s — long\n * enough to outlast a rate-limit window, short enough that a user watching a\n * stream does not assume it died. */\nconst BASE_DELAY_MS = 500;\nexport const MAX_DELAY_MS = 20_000;\n\n/**\n * `Retry-After` in either of its two legal forms: seconds, or an HTTP date.\n *\n * Honoured rather than ignored because the server knows when its window\n * reopens and we are guessing. A value in the past clamps to zero; a garbage\n * value falls back to the computed backoff, since a header we cannot read is\n * not a reason to give up on the request.\n *\n * Parsed here, bounded at the call site: this returns what the server said.\n */\nexport function parseRetryAfter(value: string | null | undefined, now: number): number | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) return Math.max(0, Number(trimmed) * 1000);\n const date = Date.parse(trimmed);\n if (Number.isNaN(date)) return undefined;\n return Math.max(0, date - now);\n}\n\n/**\n * Exponential backoff with full jitter. The jitter is the point: without it,\n * every request that got rate limited at the same moment retries at the same\n * moment, and the second wave is the same size as the first.\n */\nexport function backoffDelayMs(attempt: number, random: () => number): number {\n const ceiling = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);\n return Math.round(ceiling * (0.5 + random() * 0.5));\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 429 and the 5xx range. 409 is in here because OpenAI answers it for a\n // request that raced with something on their side, and it succeeds on the\n // second try.\n return status === 429 || status === 408 || status === 409 || status >= 500;\n}\n\n/**\n * One retry policy, not two.\n *\n * The status table alone cannot answer this: a 429 from a spent quota is a 429\n * every time for the rest of the month, and retrying it turns one billing\n * problem into `maxRetries` of them and a much later error message. Only the\n * body says which 429 this is, and `normalizeProviderError` is where that is\n * already read — so it is asked here rather than left to disagree with a table\n * after the retries have happened.\n *\n * It is a veto, not a second opinion: the table decides which statuses are\n * worth another attempt and the normalized verdict can only take one away.\n * That way a future change to the error mapping cannot start retrying 400s.\n */\nfunction shouldRetry(status: number, error: ProviderHttpError): boolean {\n return isRetryableStatus(status) && normalizeProviderError(error).retryable;\n}\n\nfunction abortReason(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\");\n}\n\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n reject(abortReason(signal));\n },\n { once: true },\n );\n });\n}\n\n/**\n * One HTTP call, retried.\n *\n * The timeout covers getting a response, not consuming one. A streamed answer\n * legitimately takes minutes, and a timeout that kept running would cut off\n * long completions at exactly the point where they were most expensive to\n * abandon — so the timer is cleared once the headers land, and only the\n * caller's own signal can end the body.\n */\nexport async function requestWithRetry(\n url: string,\n init: RequestInit,\n options: RequestOptions,\n): Promise<Response> {\n const doFetch = options.fetchImpl ?? ((u: string, i: RequestInit) => fetch(u, i));\n const sleep = options.sleep ?? defaultSleep;\n const random = options.random ?? Math.random;\n const now = options.now ?? Date.now;\n const maxRetries = Math.max(0, options.maxRetries);\n\n /**\n * A backoff nobody can interrupt is a `stop()` that does not stop.\n *\n * The wait is where a retrying request spends nearly all of its time — up to\n * 20 seconds of it — and noticing the abort only at the top of the next\n * iteration means the run holds its state, and the user watches a cancelled\n * stream, for the rest of the window. So the sleep loses a race with the\n * signal, and the abort propagates like any other.\n */\n const wait = async (ms: number): Promise<void> => {\n const signal = options.signal;\n if (!signal) return await sleep(ms);\n signal.throwIfAborted();\n let onAbort: (() => void) | undefined;\n try {\n await Promise.race([\n sleep(ms, signal),\n new Promise<never>((_resolve, reject) => {\n onAbort = () => reject(abortReason(signal));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }),\n ]);\n } finally {\n if (onAbort) signal.removeEventListener(\"abort\", onAbort);\n }\n };\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n options.signal?.throwIfAborted();\n\n const controller = new AbortController();\n const abortOuter = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener(\"abort\", abortOuter, { once: true });\n\n let timedOut = false;\n const timer =\n options.timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs)\n : undefined;\n\n let response: Response;\n try {\n response = await doFetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (timer !== undefined) clearTimeout(timer);\n options.signal?.removeEventListener(\"abort\", abortOuter);\n // The caller's abort wins outright — `stop()` means stop, not \"stop and\n // try three more times\".\n if (options.signal?.aborted) throw error;\n lastError = timedOut ? new ProviderTimeoutError(options.timeoutMs) : error;\n // Checked before the attempt count, because this is not \"no attempts\n // left\" — it is \"another attempt is the wrong thing to do\". See\n // `RequestOptions.retryTimeouts`.\n if (timedOut && options.retryTimeouts === false) throw lastError;\n if (attempt === maxRetries) throw lastError;\n await wait(backoffDelayMs(attempt, random));\n continue;\n }\n\n if (timer !== undefined) clearTimeout(timer);\n\n if (response.ok) {\n // Deliberately left attached: the caller is about to read a stream, and\n // its own signal has to keep reaching it.\n return response;\n }\n\n options.signal?.removeEventListener(\"abort\", abortOuter);\n const body = await readErrorBody(response);\n const error = new ProviderHttpError(\n response.status,\n body,\n response.headers.get(\"x-request-id\") ?? undefined,\n );\n\n if (attempt === maxRetries || !shouldRetry(response.status, error)) throw error;\n\n // Bounded, because `Retry-After` is a number the server chooses and a daily\n // quota answers it in hours. Sleeping through that holds the run open for\n // the whole window; waking early costs one request that gets the same 429\n // and a longer, still-bounded backoff after it.\n const retryAfter = parseRetryAfter(response.headers.get(\"retry-after\"), now());\n await wait(\n retryAfter === undefined\n ? backoffDelayMs(attempt, random)\n : Math.min(retryAfter, MAX_DELAY_MS),\n );\n lastError = error;\n }\n\n // Unreachable: the loop either returns or throws. Kept honest rather than\n // asserted away.\n throw lastError ?? new Error(\"Provider request failed with no response.\");\n}\n\nasync function readErrorBody(response: Response): Promise<unknown> {\n let text: string;\n try {\n text = await response.text();\n } catch {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n",
|
|
@@ -32,12 +23,12 @@
|
|
|
32
23
|
"/**\n * WHO UPLOADED A PROVIDER FILE (#443).\n *\n * A provider's file id (`file-…`) is scoped to the OpenAI/Azure org, not to\n * any user of the app: the vendor will hand the document to whichever request\n * names it. So an id is a bearer token for the file, and ids leak — a shared\n * transcript, a log line, a browser history entry. Before this, a user who\n * learned another user's id could put it in their own `turn.files` and have\n * the model read the other user's document.\n *\n * `AgentController.upload` now records the id with the uploader's owner key\n * (the same `runOwner(req)` that owns a run, #442), and `stream` refuses a\n * turn naming an id recorded for anyone else with a 403.\n *\n * A record is `{ owner, name, mimeType, size, createdAt }`, keyed by the\n * provider's id. `owner: null` is an anonymous upload and is unowned: it\n * answers whoever holds the id, exactly as every id did before this existed.\n */\nexport type FileOwnerRecord = {\n /** `runOwner(req)` at upload: `user:<id>` by default, `null` for anonymous. */\n owner: string | null;\n name?: string;\n mimeType?: string;\n size?: number;\n createdAt: string;\n};\n\n/**\n * Where the records live. Two methods so an app can put them in its own table:\n *\n * class DbFileOwners implements FileOwners {\n * async record(fileId, record) { await db.agentFile.create({ data: { fileId, ...record } }) }\n * async get(fileId) { return db.agentFile.findUnique({ where: { fileId } }) }\n * }\n *\n * `get` answers `null` for an id it has no record of. What the controller does\n * with that is `AgentController.requireKnownFiles`.\n */\nexport interface FileOwners {\n record(fileId: string, record: FileOwnerRecord): Promise<void>;\n get(fileId: string): Promise<FileOwnerRecord | null>;\n}\n\n/**\n * The default: records last as long as the process, like `MemoryAgentStore`\n * and `MemoryAttachmentStore`. Bounded, oldest first, so an upload loop cannot\n * grow it without end; an evicted id reads as unknown.\n *\n * A record is never overwritten: the first owner of an id keeps it, so a\n * second `record` for the same id (which a provider never mints, but a buggy\n * or hostile override could forward) cannot move a file to another user.\n */\nexport class MemoryFileOwners implements FileOwners {\n private readonly records = new Map<string, FileOwnerRecord>();\n\n constructor(private readonly maxEntries = 100_000) {}\n\n async record(fileId: string, record: FileOwnerRecord): Promise<void> {\n if (this.records.has(fileId)) return;\n this.records.set(fileId, { ...record });\n while (this.records.size > this.maxEntries) {\n const oldest = this.records.keys().next().value;\n if (oldest === undefined) break;\n this.records.delete(oldest);\n }\n }\n\n async get(fileId: string): Promise<FileOwnerRecord | null> {\n const record = this.records.get(fileId);\n return record ? { ...record } : null;\n }\n}\n\nexport const defaultFileOwners = new MemoryFileOwners();\n",
|
|
33
24
|
"import { app } from \"../../foundation/app\";\nimport { RedisManager } from \"../../services/redis/RedisManager\";\nimport type { ToolResultPart } from \"../types\";\n\n/**\n * EXECUTION RECEIPTS: what makes an approved tool run at most once (#458).\n *\n * A pending call's signature stops an approval being forged, and its spent\n * nonce (`NonceStore`, #445) stops it being *accepted* twice. Neither records\n * what the approved tool did. So a retried submit whose response was lost, a\n * proxy retry, or an answer that reaches two instances whose nonce stores are\n * not shared, either runs `execute` again for a tool that already charged a\n * card, or is refused and the user is told their approval was not used when\n * it was.\n *\n * A receipt store closes that. Before an approved tool runs, the run claims a\n * deterministic execution id (an HMAC, under its own HKDF-derived key, of the\n * call the signature covers: issuing run, tool call id, tool name, canonical\n * input, nesting path and subject). The claim answers one of three things:\n *\n * claimed — nobody has run it: run it, then `complete` with its result.\n * replay — it already ran: the stored result is returned as the call's\n * result, and the tool is not run.\n * blocked — a claim is held but no result recorded: another instance is\n * running it right now, or the process that was running it died.\n * The call gets a `tool_error` result the model can read, and the\n * tool is not run. Not knowing whether a side effect happened is\n * exactly the case where running it again is wrong.\n *\n * Opt-in: `AgentController.receipts` (or `receipts` on `Agent.stream`). Without\n * a store an approved tool runs exactly as before.\n *\n * Implementations:\n *\n * MemoryReceiptStore — one process, lost on restart.\n * RedisReceiptStore — on the app's Redis; shared and atomic.\n * your own — e.g. a table keyed by the execution id:\n *\n * CREATE TABLE agent_tool_receipts (\n * id text PRIMARY KEY,\n * result jsonb, -- NULL while the call is running\n * expires_at timestamptz NOT NULL\n * );\n *\n * class DbReceiptStore implements ReceiptStore {\n * async claim(id, expiresAt) {\n * const inserted = await db.$executeRaw`\n * INSERT INTO agent_tool_receipts (id, expires_at)\n * VALUES (${id}, ${new Date(expiresAt)})\n * ON CONFLICT (id) DO NOTHING`;\n * if (inserted === 1) return { status: \"claimed\" };\n * const [row] = await db.$queryRaw`\n * SELECT result FROM agent_tool_receipts WHERE id = ${id}`;\n * return row?.result ? { status: \"replay\", result: row.result } : { status: \"blocked\" };\n * }\n * async complete(id, result) {\n * await db.$executeRaw`\n * UPDATE agent_tool_receipts SET result = ${result} WHERE id = ${id}`;\n * }\n * async release(id) {\n * await db.$executeRaw`\n * DELETE FROM agent_tool_receipts WHERE id = ${id} AND result IS NULL`;\n * }\n * }\n * // and, from a cron: DELETE FROM agent_tool_receipts WHERE expires_at < now()\n *\n * A receipt only has to outlive the token it answers: past `expiresAt` the\n * signature fails verification on its own, so the call cannot be presented\n * again and the receipt may be dropped.\n */\nexport interface ReceiptStore {\n /**\n * Claims `executionId` until `expiresAt` (epoch milliseconds), if nobody has.\n * Must be atomic across every process sharing the store: two concurrent\n * claims never both answer `claimed`.\n *\n * A rejection refuses the answer, as a `NonceStore` that throws does: an\n * idempotency guard that runs the tool anyway when its store is down is not\n * a guard.\n */\n claim(executionId: string, expiresAt: number): Promise<ReceiptClaim>;\n /**\n * Records the result of a claimed execution, kept until `expiresAt`. Called\n * once the tool's result is known, which may be after the run that claimed\n * it was stopped. A rejection is logged; the claim then stays held, so a\n * replay is `blocked` rather than run again.\n */\n complete(executionId: string, result: ToolResultPart, expiresAt: number): Promise<void>;\n /**\n * Drops a claim that never ran: the answer was refused after it was claimed\n * (its nonce was already spent). A recorded result is never released.\n */\n release(executionId: string): Promise<void>;\n}\n\nexport type ReceiptClaim =\n | { status: \"claimed\" }\n | { status: \"replay\"; result: ToolResultPart }\n | { status: \"blocked\" };\n\ntype MemoryReceipt = { result?: ToolResultPart; expiresAt: number };\n\n/**\n * The in-process store. Holds each receipt until its token expires, swept\n * amortized O(1) per claim. Results are copied in and out, so a caller that\n * edits the part it was handed cannot change what a replay returns.\n */\nexport class MemoryReceiptStore implements ReceiptStore {\n private readonly receipts = new Map<string, MemoryReceipt>();\n private sweepAt = 1024;\n /** Injectable for tests. */\n constructor(private readonly now: () => number = Date.now) {}\n\n async claim(executionId: string, expiresAt: number): Promise<ReceiptClaim> {\n const now = this.now();\n if (this.receipts.size >= this.sweepAt) this.sweep(now);\n const existing = this.receipts.get(executionId);\n if (existing && existing.expiresAt > now) {\n return existing.result\n ? { status: \"replay\", result: structuredClone(existing.result) }\n : { status: \"blocked\" };\n }\n this.receipts.set(executionId, { expiresAt });\n return { status: \"claimed\" };\n }\n\n async complete(executionId: string, result: ToolResultPart, expiresAt: number): Promise<void> {\n this.receipts.set(executionId, { result: structuredClone(result), expiresAt });\n }\n\n async release(executionId: string): Promise<void> {\n const existing = this.receipts.get(executionId);\n if (existing && !existing.result) this.receipts.delete(executionId);\n }\n\n get size(): number {\n return this.receipts.size;\n }\n\n private sweep(now: number) {\n for (const [id, receipt] of this.receipts) {\n if (receipt.expiresAt <= now) this.receipts.delete(id);\n }\n this.sweepAt = Math.max(1024, this.receipts.size * 2);\n }\n}\n\n/** The slice of Bun's `RedisClient` this store needs: `send(command, args)`. */\nexport interface ReceiptRedisClient {\n send(command: string, args: string[]): Promise<any>;\n}\n\nexport interface RedisReceiptStoreOptions {\n /**\n * Client to run against. Defaults to the app's shared client from\n * `RedisServiceProvider`, resolved on first use.\n */\n client?: ReceiptRedisClient;\n /** Key namespace. Defaults to `gemi:ai:receipt`. */\n prefix?: string;\n}\n\nconst PENDING = \"pending\";\nconst DONE = \"done:\";\n\n/** `SET NX`, and on a miss the value that was there, in one round trip. */\nconst CLAIM_SCRIPT = `\nif redis.call('SET', KEYS[1], ARGV[1], 'PX', ARGV[2], 'NX') then return 'claimed' end\nlocal held = redis.call('GET', KEYS[1])\nif not held then return ARGV[1] end\nreturn held`;\n\n/** Deletes the key only while it is an unfinished claim. */\nconst RELEASE_SCRIPT = `\nif redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end\nreturn 0`;\n\n/**\n * Receipts in Redis, shared by every instance of the app. A claim is a\n * `SET ... NX` run in a script with the read that follows a miss, so claiming\n * is atomic; `PX` drops each key at the token's expiry.\n *\n * ```ts\n * const receipts = new RedisReceiptStore();\n *\n * class ChatController extends AgentController<typeof chat> {\n * agent = chat;\n * receipts = receipts;\n * }\n * ```\n */\nexport class RedisReceiptStore implements ReceiptStore {\n private readonly injectedClient?: ReceiptRedisClient;\n private readonly prefix: string;\n\n constructor(options: RedisReceiptStoreOptions = {}) {\n this.injectedClient = options.client;\n this.prefix = options.prefix ?? \"gemi:ai:receipt\";\n }\n\n async claim(executionId: string, expiresAt: number): Promise<ReceiptClaim> {\n const reply = await this.client.send(\"EVAL\", [\n CLAIM_SCRIPT,\n \"1\",\n this.key(executionId),\n PENDING,\n ttl(expiresAt),\n ]);\n // Anything else the script did not return (a client that maps an odd\n // reply to `null`, say) is `blocked`: never a reason to run the tool.\n if (reply === \"claimed\") return { status: \"claimed\" };\n const held = String(reply ?? \"\");\n if (held.startsWith(DONE)) {\n return { status: \"replay\", result: JSON.parse(held.slice(DONE.length)) as ToolResultPart };\n }\n return { status: \"blocked\" };\n }\n\n async complete(executionId: string, result: ToolResultPart, expiresAt: number): Promise<void> {\n await this.client.send(\"SET\", [\n this.key(executionId),\n DONE + JSON.stringify(result),\n \"PX\",\n ttl(expiresAt),\n ]);\n }\n\n async release(executionId: string): Promise<void> {\n await this.client.send(\"EVAL\", [RELEASE_SCRIPT, \"1\", this.key(executionId), PENDING]);\n }\n\n private key(executionId: string) {\n return `${this.prefix}:${executionId}`;\n }\n\n private get client(): ReceiptRedisClient {\n if (this.injectedClient) return this.injectedClient;\n const container = app();\n const client = container.bound(RedisManager) ? container.make(RedisManager).client : undefined;\n if (!client) {\n throw new Error(\n \"RedisReceiptStore could not reach the Redis client. Register RedisServiceProvider on your application, or pass a client: new RedisReceiptStore({ client }).\",\n );\n }\n return client;\n }\n}\n\n/** At least 1ms: `PX 0` is an error. */\nfunction ttl(expiresAt: number): string {\n return String(Math.max(1, Math.ceil(expiresAt - Date.now())));\n}\n",
|
|
34
25
|
"import type { AgentStore } from \"../AgentController\";\nimport { keepSummary, type ThreadSummary } from \"../contextCompaction\";\nimport type { AgentMessage } from \"../types\";\n\n/** A day. Long enough that a conversation survives a lunch break, short enough\n * that a chat nobody came back to is not still resident a week later. */\nconst DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;\n\n/** How often the map is walked looking for expired threads. */\nconst SWEEP_INTERVAL_MS = 60 * 1000;\n\ntype Thread = {\n messages: AgentMessage[];\n /** `contextWindow.compact`'s summaries of this thread, most recent first. */\n summaries?: ThreadSummary[];\n /** Bumped by every read and every write: a conversation someone is still\n * having must not expire out from under them mid-turn. */\n touchedAt: number;\n};\n\n/**\n * The default store: conversations last as long as the process.\n *\n * It exists so that `threadId` works out of the box, not so that anything is\n * durable — a restart loses every thread, and a second server never had them.\n * That is the honest default for a framework store, and it is why stateless is\n * still the mode an app gets without asking: the client carrying its own\n * history survives a deploy, and this does not.\n *\n * Expiry is swept lazily rather than on a timer. A `setTimeout` per thread is a\n * timer per conversation and a reference the GC cannot collect, and an interval\n * running forever keeps a process alive that has nothing else to do — so the\n * sweep happens on access, at most once a minute, and an untouched process\n * simply stops sweeping.\n *\n * A thread the store does not have is `null` from `loadThread` and an error\n * from `appendMessages`, never an empty conversation. It used to be the other\n * way, and the three ways a thread goes missing — it expired, the id was\n * mistyped, it lived on an instance that was scaled in — all read as a fresh\n * chat: the history was gone with no signal, and the next turn was persisted\n * under the dead id as though it were the first. `clientOwnedIds` is the one\n * setup where an unknown id is not a lost thread, because the client minted it.\n */\nexport class MemoryAgentStore implements AgentStore {\n readonly ttlMs: number;\n /** The ids come from the client, not from `createThread`, so an id this\n * store has never seen is a conversation starting rather than one lost. */\n readonly clientOwnedIds: boolean;\n\n private threads = new Map<string, Thread>();\n private lastSweep = 0;\n\n constructor(params: { ttlMs?: number; clientOwnedIds?: boolean } = {}) {\n this.ttlMs = params.ttlMs ?? DEFAULT_TTL_MS;\n this.clientOwnedIds = params.clientOwnedIds ?? false;\n }\n\n async createThread(params: { userId?: string | number }): Promise<{ threadId: string }> {\n // The user id is not part of the id and not stored: this store cannot\n // authorize anything, and an id that looked like a key would invite an app\n // to treat it as one. Ownership belongs to the app's own table.\n void params;\n const threadId = crypto.randomUUID();\n this.threads.set(threadId, { messages: [], touchedAt: Date.now() });\n this.sweep();\n return { threadId };\n }\n\n async loadThread(threadId: string): Promise<AgentMessage[] | null> {\n this.sweep();\n const thread = this.threads.get(threadId);\n if (!thread) {\n // With client-owned ids the first turn arrives before anything has been\n // written under it, so unknown is empty. Otherwise unknown is a thread\n // that expired or never existed, and the controller has to be able to\n // tell: `[]` here is the silent fresh conversation this store used to\n // hand out in place of the user's history.\n return this.clientOwnedIds ? [] : null;\n }\n thread.touchedAt = Date.now();\n // Copied, so a caller that sorts or splices the result does not edit the\n // stored history in place.\n return thread.messages.slice();\n }\n\n async appendMessages(threadId: string, messages: AgentMessage[]): Promise<void> {\n this.sweep();\n let thread = this.threads.get(threadId);\n if (!thread) {\n if (!this.clientOwnedIds) {\n // Creating the thread here would persist a turn under an id the client\n // believes holds a longer conversation, and hide from the app that the\n // conversation is gone. The controller checks before the run and never\n // reaches this; a store-level caller that does gets told.\n throw new Error(`Thread ${threadId} does not exist here, or has expired.`);\n }\n // The client owns the id, so an append to one the store has never seen is\n // the first turn, and refusing it would lose a turn that already happened.\n thread = { messages: [], touchedAt: Date.now() };\n this.threads.set(threadId, thread);\n }\n // Upsert, not push. A turn that resolves a pending call hands back the\n // assistant message that made the call under the id it already had, now\n // with the result attached; pushing it would leave the thread holding both\n // versions, and the model would read the same call twice on every turn\n // that follows. Replacing in place keeps the message where the\n // conversation put it.\n for (const message of messages) {\n const at = thread.messages.findIndex((held) => held.id === message.id);\n if (at === -1) {\n thread.messages.push(message);\n } else {\n thread.messages[at] = message;\n }\n }\n thread.touchedAt = Date.now();\n }\n\n async removeMessages(threadId: string, messageIds: string[]): Promise<void> {\n this.sweep();\n const thread = this.threads.get(threadId);\n if (!thread) return;\n const drop = new Set(messageIds);\n thread.messages = thread.messages.filter((message) => !drop.has(message.id));\n thread.touchedAt = Date.now();\n }\n\n async loadSummaries(threadId: string): Promise<ThreadSummary[]> {\n const thread = this.threads.get(threadId);\n return thread?.summaries?.slice() ?? [];\n }\n\n async saveSummary(threadId: string, summary: ThreadSummary): Promise<void> {\n // A thread that is gone has nothing to summarise; the summary goes with it.\n const thread = this.threads.get(threadId);\n if (!thread) return;\n thread.summaries = keepSummary(thread.summaries ?? [], summary);\n }\n\n /** Test seam, and a way for an app to drop a conversation on request. */\n delete(threadId: string): void {\n this.threads.delete(threadId);\n }\n\n get size(): number {\n return this.threads.size;\n }\n\n sweep(now = Date.now()): void {\n if (now - this.lastSweep < SWEEP_INTERVAL_MS) {\n return;\n }\n this.lastSweep = now;\n for (const [threadId, thread] of this.threads) {\n if (now - thread.touchedAt > this.ttlMs) {\n this.threads.delete(threadId);\n }\n }\n }\n}\n\n/**\n * The process-wide default every `AgentController` uses unless it is given\n * another.\n *\n * It has to be a shared instance, not a field initializer. A gemi controller is\n * constructed per request — `RouteHandler.run()` does `new Controller()` every\n * time — so `store = new MemoryAgentStore()` written in a controller field is a\n * brand new, empty store on every turn, and a threaded conversation would read\n * back nothing while looking like it was configured correctly. Anything\n * process-lived that a controller holds has to be created outside it.\n */\nexport const defaultAgentStore = new MemoryAgentStore();\n",
|
|
35
|
-
"import type {\n AgentContentPart,\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n AgentStreamFrame,\n FinishReason,\n NestedRun,\n PendingToolCall,\n ToolCallPart,\n ToolShapes,\n Usage,\n} from \"../types\";\n\n/**\n * Frames to a message list.\n *\n * The rule the whole file is built around: **a client may be handed any\n * suffix of a run, and may be handed the same frame twice.** An attached\n * stream starts mid-message, a reconnect replays from a cursor, and a proxy\n * that retries is entitled to deliver a frame again. So nothing here tracks\n * \"the current message\" — every event that touches a message names it, and a\n * message the list has never heard of is created on the spot rather than\n * dropped.\n *\n * The two mechanisms that make that work:\n *\n * - `seq` guards replay. A frame at or below the state's cursor is a no-op,\n * and `applyFrame` returns the *same object* so a caller can tell nothing\n * happened. Without it a redelivered `text-delta` would append its text a\n * second time — a bug that looks fine until someone refreshes.\n * - a finished message is closed to further deltas. `seq` catches a redelivery\n * within a run, but not a server that replays a run from zero to a client\n * that already has the transcript; `message-end` is terminal, so a delta for\n * a message that already carries a finish reason is replay by definition.\n * - every mutation is either an append that the seq guard already protects,\n * or an upsert keyed by an id. Tool calls and tool results arrive more than\n * once (a call re-streams as its arguments grow), so those are keyed by\n * `toolCallId`, never pushed blindly.\n *\n * A sub-agent's transcript is built by this same function calling itself. A\n * `nested-event` is unwrapped onto the `NestedRun` hanging off its parent's\n * tool-call part and handed to `reduce` again, so every rule above holds inside\n * a nested run for free — a nested `message-start` that never arrived, a\n * nested delta after a nested `message-end`, a nested `run-end` closing off a\n * message that never ended. Two levels of nesting cost this file nothing over\n * one, which is the whole reason the wire has a `nested-event` rather than a\n * second reducer.\n */\n\nexport type ChatState<T extends ToolShapes = ToolShapes, O = unknown> = {\n messages: AgentMessage<T, O>[];\n /** Non-empty exactly while the conversation is holding a question. */\n pending: PendingToolCall<T>[];\n error: AgentError | null;\n runId?: string;\n threadId?: string;\n /**\n * The highest frame applied. This is the cursor `/attach` is asked to resume\n * from, which is why it lives in the state a client keeps rather than in the\n * stream reader that dies with the connection.\n */\n seq: number;\n /**\n * Which run `seq` counts within.\n *\n * Separate from `runId`, which is cleared when the run ends because a UI asks\n * it whether anything is live. The cursor outlives the run it belongs to: a\n * frame from run_1 redelivered after run_1 finished is still a duplicate, and\n * without somewhere to remember that, replaying a finished run would look\n * exactly like the start of a new one.\n */\n cursorRunId?: string;\n /**\n * The messages the run in hand has touched, oldest first.\n *\n * `run-end` and `markAborted` both have to finish off a message whose\n * `message-end` never arrived, and \"every assistant message with no finish\n * reason\" is the wrong set to do it over: a superseded turn from an earlier\n * run is sitting in exactly that state, and stamping it with *this* run's\n * reason would relabel an interrupted answer as a clean completion. So the\n * reducer remembers which messages this run actually wrote to, and finishes\n * off only those. Reset by `run-start`; on a mid-run attach it simply fills\n * up from the first frame that names a message, which is the same set.\n */\n runMessageIds: string[];\n /**\n * The deferred tools the model has pulled in during this run, as a set.\n *\n * Not a message part, because a `tool-search` names no tool call and no\n * message — it happens *before* any call, which is exactly what makes it\n * worth showing (\"looking for the right tool\" instead of an unexplained\n * pause). So unlike `tool-progress` and `nested-event`, which now have a home\n * on the tool-call part, this one had nowhere in `AgentMessage` to go that\n * would not have meant inventing a content part in a frozen contract.\n *\n * A set, not a log: union is the only accumulation that survives redelivery\n * without a guard, and a client attached mid-run and handed a `tool-search`\n * it has already applied must not show the same tool twice. Run-scoped and\n * reset by `run-start` — it describes a run in progress, so it is deliberately\n * not something `initialChatState` restores.\n */\n loadedTools: string[];\n finishReason?: FinishReason;\n /**\n * The run's total usage so far, from its `usage` frames: every step plus what\n * its tools spent. Run-scoped and reset by `run-start`, like `loadedTools`.\n * Each assistant message's own share is on `AgentMessage.usage` (#467).\n */\n usage?: Usage;\n};\n\nexport function initialChatState<T extends ToolShapes = ToolShapes, O = unknown>(\n init: {\n messages?: AgentMessage<T, O>[];\n pending?: PendingToolCall<T>[];\n threadId?: string;\n /** Where a restored client left off. `-1` means \"I have seen nothing\". */\n seq?: number;\n /**\n * Which run that `seq` counts within. A cursor without it is a number with\n * no units — frames number from zero in every run, so `seq: 10` means\n * nothing until you know whether the live run is the one that reached 10.\n */\n cursorRunId?: string;\n } = {},\n): ChatState<T, O> {\n return {\n messages: init.messages ? [...init.messages] : [],\n pending: init.pending ? [...init.pending] : [],\n error: null,\n threadId: init.threadId,\n seq: init.seq ?? -1,\n cursorRunId: init.cursorRunId,\n runMessageIds: [],\n loadedTools: [],\n };\n}\n\n/**\n * Apply one frame.\n *\n * `now` is an argument rather than a `Date.now()` call so the reducer stays a\n * pure function of its inputs — it is only ever read when a frame arrives for a\n * message the list has not seen, which is precisely the mid-run-attach path a\n * test needs to pin down.\n */\nexport function applyFrame<T extends ToolShapes = ToolShapes, O = unknown>(\n state: ChatState<T, O>,\n frame: AgentStreamFrame<T, O>,\n now: string = new Date().toISOString(),\n): ChatState<T, O> {\n // A `seq` is a position within *one* run, so the second turn of a\n // conversation numbers its frames from zero again and the cursor left over\n // from the first would silently swallow the whole answer. `run-start` naming\n // a run this state has not seen is the one frame entitled to drop the cursor.\n const startsNewRun = frame.event.type === \"run-start\" && frame.event.runId !== state.cursorRunId;\n // Identity, not a copy: the hook reads `next === prev` as \"already applied\"\n // and skips the callbacks that would otherwise fire twice.\n if (!startsNewRun && frame.seq <= state.seq) return state;\n return { ...reduce(state, frame.event, now), seq: frame.seq };\n}\n\nfunction reduce<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n event: AgentStreamFrame<T, O>[\"event\"],\n now: string,\n): ChatState<T, O> {\n switch (event.type) {\n case \"run-start\":\n return {\n ...state,\n // A run's in-progress copies, emptied so the replay that starts here\n // rebuilds them (#778). A thread read while a run is going holds what\n // the controller stored of it so far (`AgentMessage.runId`, no\n // `finishReason`), and a client that shows that read and then attaches\n // gets the run from its first frame: appending the replayed deltas to\n // the stored text printed it twice. `run-start` is frame 0, so\n // everything the copy held is on its way again. Kept in place rather\n // than dropped, so the transcript's order does not change under it.\n messages: resetInProgress(state.messages, event.runId),\n runId: event.runId,\n cursorRunId: event.runId,\n threadId: event.threadId ?? state.threadId,\n runMessageIds: [],\n loadedTools: [],\n finishReason: undefined,\n usage: undefined,\n };\n\n case \"message-start\":\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n role: event.role,\n }));\n\n // The two additive cases, and the only two that can double text. `seq`\n // catches an ordinary redelivery, but a client resuming with a cursor the\n // server ignores — or asked for the whole run when it already had the\n // transcript — gets frames it cannot recognise as duplicates. A finished\n // message is the one thing it can: `message-end` is terminal, so a delta\n // arriving for a message that already carries a finish reason is replay by\n // definition and appending it would show the answer twice.\n case \"text-delta\":\n if (isFinished(state, event.messageId)) return state;\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: appendText(message.content, event.delta),\n }));\n\n case \"reasoning-delta\":\n if (isFinished(state, event.messageId)) return state;\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: appendReasoning(message.content, event.delta, event.id),\n }));\n\n case \"output-delta\":\n // `snapshot` is the whole object so far, not an increment, so the raw\n // `delta` text is dropped here on purpose: replacing beats accumulating\n // when a client may have missed the first half of the JSON.\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: upsert(\n message.content,\n { type: \"output\", value: event.snapshot as O, partial: true },\n (part) => part.type === \"output\",\n ),\n }));\n\n case \"tool-call\":\n // Keyed, because the same call re-streams as its arguments fill in — and\n // *merged* rather than replaced, which the plain upsert below cannot do.\n //\n // A `tool-call` frame is the model's half of the part. `progress` and\n // `nested` are the execution's half, and they arrive on events that name\n // no message, so a part that loses them cannot rebuild them from anything\n // later in the stream. Replacing wholesale is exactly how a run replayed\n // onto a transcript that already holds it drops a sub-agent's entire\n // transcript while appearing to converge.\n return withMessage(state, event.messageId, now, (message) => {\n const index = message.content.findIndex(\n (part) => part.type === \"tool-call\" && part.toolCallId === event.part.toolCallId,\n );\n const existing = index === -1 ? undefined : (message.content[index] as ToolCallPart<T>);\n // The frame wins where it says anything — a server that persists the\n // nested transcript and re-sends it is more authoritative than what this\n // client accumulated — and the part is kept where it does not.\n const progress = event.part.progress ?? existing?.progress;\n const nested = event.part.nested ?? existing?.nested;\n // `attachments` is kept for the same reason and with a sharper\n // consequence: it is the memo `ctx.attachments.put` replays from, so a\n // stateless client that dropped it posts back a history in which the\n // tool call never attached anything — and a re-entered tool stores the\n // bytes again, uploads them again, and shows the model a second copy of\n // its own output. Losing `progress` costs a log; losing this costs\n // money and confuses the model.\n const attachments = event.part.attachments ?? existing?.attachments;\n const part = {\n ...event.part,\n ...(progress ? { progress } : {}),\n ...(nested ? { nested } : {}),\n ...(attachments ? { attachments } : {}),\n };\n const content = message.content.slice();\n if (index === -1) content.push(part);\n else content[index] = part;\n return { ...message, content };\n });\n\n case \"tool-search\": {\n // Accumulated as a set. Every other additive event in this file leans on\n // `seq` to survive redelivery; this one cannot, because a `tool-search`\n // carries no id at all — there is nothing to key an upsert on and nothing\n // to tell a second delivery from a second search. Union is what makes the\n // question moot: applying the same frame again is the same set, and two\n // genuinely different searches that both loaded `refundOrder` are, for a\n // UI naming the tools in play, the same fact twice.\n const loaded = event.loaded.filter((name) => !state.loadedTools.includes(name));\n if (loaded.length === 0) return state;\n return { ...state, loadedTools: [...state.loadedTools, ...loaded] };\n }\n\n case \"tool-progress\":\n // Append-only, exactly like a text delta, and protected the same two\n // ways: `seq` for redelivery within a run, and the finished-message check\n // inside `withToolCall` for a run replayed onto a transcript that already\n // holds it. The tool loop emits every yield before the message it belongs\n // to is finalised, so a progress datum for a finished message is replay\n // by definition — the same argument `text-delta` makes, and with the same\n // carve-out for a message the run parked on.\n //\n // Unbounded on purpose: a tool decides how often it yields, and truncating\n // its log here would lose data the UI asked for. What is bounded is the\n // *wire* — `useChat.send` strips `progress` from the history it posts, so\n // a tool that yields ten thousand times costs ten thousand entries in this\n // tab and nothing at all on every later turn. See `forWire`.\n return withToolCall(state, event.toolCallId, (part) => ({\n ...part,\n progress: [...(part.progress ?? []), event.data],\n }));\n\n case \"nested-event\": {\n // The recursion. The sub-run's transcript is an ordinary message list, so\n // it is reduced by this function rather than by a parallel one — which is\n // why an arbitrarily deep nesting is not a case handled here at all: an\n // inner `nested-event` simply lands back in this branch, one message list\n // further down.\n const nestedEvent = event as NestedEvent;\n return withToolCall(state, event.toolCallId, (part) => {\n const runs = part.nested ?? [];\n const index = runs.findIndex((run) => run.runId === nestedEvent.runId);\n // Created on the spot when unknown, for the same reason `withMessage`\n // creates a message it never saw start: a client attached mid-run gets\n // the sub-run's tail and no `run-start`, and dropping it would leave a\n // tool call that visibly does something looking like one that hangs.\n const run: NestedRun = runs[index] ?? {\n runId: nestedEvent.runId,\n agent: nestedEvent.agent,\n messages: [],\n };\n const next = applyNested(run, nestedEvent, now);\n const nested =\n index === -1 ? [...runs, next] : runs.map((r, i) => (i === index ? next : r));\n return { ...part, nested };\n });\n }\n\n case \"tool-result\": {\n const next = withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: upsert(\n message.content,\n event.part,\n (part) => part.type === \"tool-result\" && part.toolCallId === event.part.toolCallId,\n ),\n }));\n // A result is the answer to a pending call, whoever produced it — the\n // human here, or the server after an approval. Either way it is no longer\n // pending, and leaving it in the list would keep the UI asking.\n return {\n ...next,\n pending: next.pending.filter((call) => call.toolCallId !== event.part.toolCallId),\n };\n }\n\n case \"message\": {\n // A whole message, replaced or appended by id.\n //\n // The wholesale replace the `tool-call` branch above argues against is\n // right here, and the difference is authorship. A tool-call part is\n // assembled from two sources — the model's half on this frame, the\n // execution's half on events that name no message — so a client that\n // replaces it drops what only it was holding. This message has one\n // author, the server, and is complete before it is ever sent; there is no\n // client-accumulated half to lose, so a second delivery is the same value\n // written twice.\n //\n // Appended at the end when unknown, which is where it belongs: the run\n // emits it the moment it appends it to its own history, so stream order\n // and transcript order are the same order. Not routed through\n // `withMessage`, which would create the message as `assistant` — the role\n // is on the frame and it is `user`.\n const index = state.messages.findIndex((message) => message.id === event.message.id);\n const messages = state.messages.slice();\n if (index === -1) messages.push(event.message);\n else messages[index] = event.message;\n const runMessageIds = state.runMessageIds.includes(event.message.id)\n ? state.runMessageIds\n : [...state.runMessageIds, event.message.id];\n return { ...state, messages, runMessageIds };\n }\n\n case \"message-id\": {\n // The client's own copy of its turn, renamed to the id the server stored\n // it under (#466). Only the id: the copy is what the user typed and is\n // already on screen, and the server never sends the turn itself.\n //\n // A no-op when nothing is under `localId` — a replay after the rename,\n // or a client attached from elsewhere that never held the copy. If the\n // server's id is somehow already there too, the local copy is the\n // duplicate and goes. Not added to `runMessageIds`: a user message is\n // complete when it is sent, and `run-end` has nothing to close on it.\n const index = state.messages.findIndex((message) => message.id === event.localId);\n if (index === -1) {\n // Not this client's turn: a client attached to a run another one\n // started (#778). The server sends the stored turn along for exactly\n // this, and it goes where the run put it, before the answer. Already\n // here under the server's id (a thread read, or a replay) it is left\n // alone.\n if (!event.message || state.messages.some((m) => m.id === event.messageId)) return state;\n return { ...state, messages: [...state.messages, event.message] };\n }\n const messages = state.messages.some((message) => message.id === event.messageId)\n ? state.messages.filter((_, i) => i !== index)\n : state.messages.map((message, i) =>\n i === index ? { ...message, id: event.messageId } : message,\n );\n return { ...state, messages };\n }\n\n case \"awaiting-input\":\n return { ...state, runId: event.runId, pending: [...event.pending] };\n\n case \"message-end\":\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n finishReason: event.finishReason,\n // Kept, not merely acted on. Dropping the partial output leaves a UI\n // unable to tell a cut-off answer from a message that never had one, and\n // the finish reason cannot say which — see `AgentMessage.outputTruncated`.\n ...(event.outputTruncated ? { outputTruncated: true as const } : {}),\n // This message's own model call (#467). An assignment, so a replay is\n // harmless; absent on the frame, the message keeps whatever it had.\n ...(event.usage ? { usage: event.usage } : {}),\n content:\n // A run cut off by the output ceiling has no answer, and the partial\n // output part is dropped rather than completed.\n //\n // `snapshot` is `bestEffortParse` of the text so far, which closes\n // whatever brackets are open — so the last partial looks like a whole\n // document, and stamping it `partial: false` here presented a\n // half-written object as the finished one. The server already\n // withholds the output part on `length` for that reason; without this\n // the two disagreed, and the client held the more convincing lie.\n // `outputTruncated` first: it is the fact, and the finish reason is\n // not it — a step that hit the ceiling and also called a tool ends the\n // message `awaiting-input` or `max-steps`. `length` is still honoured\n // for a server that predates the field.\n event.outputTruncated || event.finishReason === \"length\"\n ? message.content.filter((part) => !(part.type === \"output\" && part.partial))\n : message.content.map((part) =>\n part.type === \"output\" && part.partial ? { ...part, partial: false } : part,\n ),\n }));\n\n case \"usage\":\n // The run's total, not any message's (#467). It used to be put on the\n // last assistant message, so a three-step run showed every token on step\n // three and nothing on the first two — and a run whose tools spent\n // through `generate()` or a sub-run billed that to a message that never\n // made the call. Each message now gets its own from `message-end`; this\n // is the turn's, on the state. An assignment, so a replay is harmless.\n return { ...state, usage: event.usage };\n\n case \"error\":\n // Clearing `pending` here is what keeps \"pending is non-empty exactly\n // when the UI is awaiting input\" true: a run that errored is not holding\n // a question any more, it is holding a failure.\n return { ...state, error: event.error, pending: [] };\n\n case \"run-end\":\n return {\n ...state,\n runId: undefined,\n finishReason: event.finishReason,\n // A safety net for the client that attached late and never saw a\n // `message-end`: once the run is over nothing is still streaming, so a\n // message left without a finish reason would show a cursor forever.\n //\n // Scoped to this run's own messages. A turn superseded by a second send\n // is also sitting there unfinished, and it was *not* finished by this\n // run — stamping it \"stop\" would tell the user, and the model on the\n // next stateless turn, that an answer cut off mid-sentence ended\n // cleanly.\n messages: finishUnended(state, event.finishReason),\n };\n\n // Every event in the union is handled above, so this is reached only by a\n // server that speaks a newer protocol than this client. Kept as a silent\n // no-op rather than an exhaustiveness assertion for that reason: an old tab\n // meeting a new event must keep rendering the rest of the stream, and the\n // seq still advances so its cursor stays right.\n default:\n return state;\n }\n}\n\n/**\n * The interrupted turn, kept.\n *\n * `stop()` calls this before the server has said anything, because the point of\n * stopping is that the UI reacts now. Whatever the assistant had produced stays\n * in the list marked `aborted` — dropping it would lose text the user already\n * read, and would leave the transcript unable to say it was cut short.\n *\n * `pending` is untouched: a question the conversation is holding survives a\n * stopped run, and clearing it would silently discard the answer the user still\n * owes.\n */\nexport function markAborted<T extends ToolShapes = ToolShapes, O = unknown>(\n state: ChatState<T, O>,\n): ChatState<T, O> {\n return {\n ...state,\n runId: undefined,\n finishReason: \"aborted\",\n // This run's messages only, for the same reason `run-end` is scoped: an\n // older turn that was already cut short is not cut short again by this one,\n // and a restored transcript may legitimately carry an unfinished message\n // that has nothing to do with the run being stopped.\n messages: finishUnended(state, \"aborted\"),\n };\n}\n\n// --- helpers -------------------------------------------------------------\n\n/**\n * The stored in-progress copies of `runId`'s messages, emptied for a replay.\n *\n * Only a message that says it is that run's and unfinished: a finished one is\n * closed to deltas already, and anything without the run's id is not this\n * run's to touch. The id goes too, since the copy is now the client's own\n * live message, the shape a streamed message has. Identity when there is\n * nothing to reset, which is every `run-start` a client streams itself.\n */\nfunction resetInProgress<T extends ToolShapes, O>(\n messages: AgentMessage<T, O>[],\n runId: string,\n): AgentMessage<T, O>[] {\n if (!messages.some((m) => m.runId === runId && m.finishReason === undefined)) return messages;\n return messages.map((message) => {\n if (message.runId !== runId || message.finishReason !== undefined) return message;\n const { runId: _runId, ...rest } = message;\n return { ...rest, content: [] };\n });\n}\n\n/**\n * The messages this run wrote, finished off with `reason` if they never ended —\n * and, inside them, the sub-runs this run left mid-sentence.\n *\n * The nesting descent is not an extra: a `NestedRun` renders with the component\n * that renders `messages`, so a nested message with no `finishReason` draws a\n * live cursor inside a block that will never receive another frame. The parent\n * ending is the last word anything will say about it, and for `markAborted`\n * there is no other word available at all — `stop()` marks the transcript\n * optimistically, before the server has answered, so no forwarded nested\n * `run-end` can arrive in time.\n *\n * It recurses through `closeRun`, which builds a `ChatState` around the sub-run\n * and calls back here, so a sub-sub-run is closed by the same three lines that\n * close the top level — the same trick `applyNested` plays on the way in.\n */\nfunction finishUnended<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n reason: FinishReason,\n): AgentMessage<T, O>[] {\n return state.messages.map((message) =>\n message.role === \"assistant\" && state.runMessageIds.includes(message.id)\n ? closeMessage(message, reason)\n : message,\n );\n}\n\n/**\n * One message of this run, and the sub-runs hanging off its tool calls.\n *\n * The message's own finish reason is only filled in when it is missing, but the\n * descent happens either way: the message a run parks on is *finished* while the\n * sub-run underneath it is still live, and that is the case where the block\n * stuck streaming is easiest to hit.\n */\nfunction closeMessage<T extends ToolShapes, O>(\n message: AgentMessage<T, O>,\n reason: FinishReason,\n): AgentMessage<T, O> {\n const content = message.content.map((part) =>\n part.type === \"tool-call\" && part.nested?.some((run) => run.finishReason === undefined)\n ? {\n ...part,\n nested: part.nested.map((run) =>\n run.finishReason === undefined ? closeRun(run, reason) : run,\n ),\n }\n : part,\n );\n if (message.finishReason === undefined) return { ...message, finishReason: reason, content };\n // Identity where nothing changed, so `run-end` on a settled transcript keeps\n // the parts a UI may be memoising on.\n const changed = content.some((part, index) => part !== message.content[index]);\n return changed ? { ...message, content } : message;\n}\n\n/** A sub-run the parent outlived, stamped with the parent's reason, recursively. */\nfunction closeRun(run: NestedRun, reason: FinishReason): NestedRun {\n const sub: ChatState = {\n messages: run.messages,\n pending: [],\n error: null,\n seq: -1,\n // Every message in the transcript, for the reason `applyNested` gives: a\n // `NestedRun` is keyed by `runId` and only ever written by events carrying\n // it, so there is no other run's work in here to protect.\n runMessageIds: run.messages.map((message) => message.id),\n loadedTools: [],\n };\n return { ...run, finishReason: reason, messages: finishUnended(sub, reason) };\n}\n\ntype NestedEvent = Extract<AgentStreamEvent, { type: \"nested-event\" }>;\n\n/**\n * Run one update over the tool-call part with this id, wherever it lives.\n *\n * `tool-progress` and `nested-event` are the only events that name a tool call\n * without naming a message, so the message has to be found rather than told —\n * a scan from the newest end, because the call being worked on is the one that\n * just arrived.\n *\n * **A frame for a tool call this transcript does not have is dropped.** That is\n * the mid-run `/attach` case the whole file is written for, and it is the one\n * place the usual answer — create it on the spot — is the wrong one: a\n * `ToolCallPart` needs a tool `name` and an `input`, and neither is on these\n * events. Inventing them would put a tool call the model never made into the\n * transcript, under a name that is not a key of the agent's tools, which breaks\n * the narrowing that is the reason the shapes are carried into the browser at\n * all. So the progress is lost and the transcript stays true, rather than the\n * other way round.\n *\n * In practice a client that has the cursor has the part: `useChat` documents\n * `cursor` and `initialMessages` as things to persist together, and a client\n * that persisted one without the other is already the case that doubles text.\n * Parking the orphans until their tool call shows up was considered and is not\n * worth it — the call is *earlier* in the stream, never later, so nothing would\n * ever drain the parking lot.\n */\nfunction withToolCall<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n toolCallId: string,\n update: (part: ToolCallPart<T>) => ToolCallPart<T>,\n): ChatState<T, O> {\n for (let i = state.messages.length - 1; i >= 0; i--) {\n const message = state.messages[i]!;\n const index = message.content.findIndex(\n (part) => part.type === \"tool-call\" && part.toolCallId === toolCallId,\n );\n if (index === -1) continue;\n // The replay guard, and the same one the deltas use — with the one carve-out\n // a delta does not need.\n //\n // Within a run the tool loop runs every tool before it finalises the message\n // the calls sit in, so a frame for a call inside a finished message is that\n // run being replayed onto a transcript that already has it, and appending\n // would show the progress log twice.\n //\n // But a message the run *parked* on is not a closed message. `Agent.loop`\n // finalises it with `\"awaiting-input\"` **before** emitting `awaiting-input`,\n // and the very next turn re-enters that same tool call — `resolveAnswer`\n // calls `executeTool` against the call it found in the history — so its\n // `tool-progress` and `nested-event` frames arrive after their message\n // carries a finish reason. Treating those as replay dropped every frame of\n // the resumed execution while the `tool-result` (which goes through\n // `withMessage`, unguarded) still landed: the call went silent and then\n // produced an answer, which is the bug nesting exists to fix. Worse, in\n // stateless mode the nested transcript is what the next turn replays the\n // sub-run from, so the client posted back a sub-run frozen at the question.\n //\n // The carve-out is as narrow as the case: parked, *and* the call still open.\n // Once its result has landed nothing legitimately appends to it again, so a\n // replay of a parked run is still refused for every call it answered.\n if (message.finishReason !== undefined && !isReenterable(state, message, toolCallId)) {\n return state;\n }\n const content = message.content.slice();\n content[index] = update(content[index] as ToolCallPart<T>);\n const messages = state.messages.slice();\n messages[i] = { ...message, content };\n // Counted as a message this run touched, like every event that names one\n // directly — a client whose only frames for this message were nested ones\n // still needs `run-end` to close it, or it shows a cursor forever.\n const runMessageIds = state.runMessageIds.includes(message.id)\n ? state.runMessageIds\n : [...state.runMessageIds, message.id];\n return { ...state, runMessageIds, messages };\n }\n return state;\n}\n\n/**\n * One sub-run event, applied to the sub-run's own transcript.\n *\n * The sub-state is built and thrown away per event rather than kept, because\n * there is nowhere to keep it: `NestedRun` is a wire type and holds a\n * transcript, not a reducer state. Everything the inner `reduce` needs is\n * derivable from it.\n *\n * - `seq` is `-1` and this calls `reduce`, not `applyFrame`. A nested event\n * has no sequence of its own; it is numbered in the *parent's* stream, and\n * the parent's cursor has already refused the duplicates.\n * - `runMessageIds` is every message in the transcript, which for a nested\n * run is exactly right and needs none of the parent's care. The parent\n * scopes it because its list mixes runs; a `NestedRun` is keyed by `runId`\n * and only ever written by events carrying that id, so every message in it\n * belongs to the run that is ending.\n * - `pending` is dropped. An escalated question reaches the user on the\n * *parent's* `awaiting-input`, carrying the path that says which tool to\n * re-enter; the copy inside the sub-run's own stream carries no path, so\n * surfacing it would show the question twice and make one of them\n * unanswerable.\n */\nfunction applyNested(run: NestedRun, event: NestedEvent, now: string): NestedRun {\n const sub: ChatState = {\n messages: run.messages,\n pending: [],\n error: null,\n seq: -1,\n runMessageIds: run.messages.map((message) => message.id),\n loadedTools: [],\n finishReason: run.finishReason,\n };\n const next = reduce(sub, event.event, now);\n return {\n ...run,\n // A late label is still a label: `/attach` may deliver the sub-run's tail,\n // and every nested frame carries it.\n ...(event.label !== undefined ? { label: event.label } : {}),\n messages: next.messages,\n ...(next.finishReason !== undefined ? { finishReason: next.finishReason } : {}),\n // The sub-run's own total, lifted so a UI can price the block it is\n // rendering without walking its messages — which carry only their own\n // steps' usage, not what the sub-run's tools spent. An assignment, so\n // redelivery is harmless.\n ...(next.usage !== undefined ? { usage: next.usage } : {}),\n };\n}\n\n/**\n * Whether a finished message's tool call can still be written to.\n *\n * Exactly one message can say yes: the one a run parked on, holding a call\n * nobody has answered yet. That is the resume turn — the tool is re-entered\n * from the top and streams progress and sub-run events against a message that\n * closed on the previous turn.\n *\n * \"Open\" is the server's own test, `Agent.openCalls`: a tool call with no\n * `tool-result` for it anywhere in the transcript. The result is the thing that\n * says the re-entry finished, and it always arrives *after* the frames this\n * guards — `attachToHistory` emits it once `executeTool` returns.\n */\nfunction isReenterable<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n message: AgentMessage<T, O>,\n toolCallId: string,\n) {\n if (message.finishReason !== \"awaiting-input\") return false;\n return !state.messages.some((candidate) =>\n candidate.content.some((part) => part.type === \"tool-result\" && part.toolCallId === toolCallId),\n );\n}\n\nfunction isFinished<T extends ToolShapes, O>(state: ChatState<T, O>, messageId: string) {\n const message = state.messages.find((candidate) => candidate.id === messageId);\n return message !== undefined && message.finishReason !== undefined;\n}\n\nfunction withMessage<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n messageId: string,\n now: string,\n update: (message: AgentMessage<T, O>) => AgentMessage<T, O>,\n): ChatState<T, O> {\n const index = state.messages.findIndex((message) => message.id === messageId);\n // Every id-carrying event marks its message as one this run touched, which is\n // what `run-end` and `markAborted` read to know whose loose ends are theirs.\n const runMessageIds = state.runMessageIds.includes(messageId)\n ? state.runMessageIds\n : [...state.runMessageIds, messageId];\n if (index === -1) {\n // The mid-stream attach. Every id-carrying event describes an assistant\n // message — `message-start` is the only event that declares a role and it\n // declares that one — so a placeholder is enough to hang the tail on.\n const blank: AgentMessage<T, O> = {\n id: messageId,\n role: \"assistant\",\n content: [],\n createdAt: now,\n };\n return { ...state, runMessageIds, messages: [...state.messages, update(blank)] };\n }\n const messages = state.messages.slice();\n messages[index] = update(messages[index]!);\n return { ...state, runMessageIds, messages };\n}\n\nfunction appendText<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n delta: string,\n): AgentContentPart<T, O>[] {\n const last = content[content.length - 1];\n // Coalesced into the trailing text part, but only if it *is* trailing: a\n // delta after a tool call opens a new part, which is what lets a UI render\n // \"thinking / call / answer\" in the order it happened.\n if (last && last.type === \"text\") {\n return [...content.slice(0, -1), { type: \"text\", text: last.text + delta }];\n }\n return [...content, { type: \"text\", text: delta }];\n}\n\n/**\n * Mirrors `appendReasoning` in Agent.ts, including its merge rule: deltas join\n * the last part only when the reasoning-item id matches, so a step that\n * produced two items stays two parts instead of flattening into one under the\n * wrong id. The two implementations have to agree, because a stateless client\n * posts this content straight back and the provider matches on that id.\n */\nfunction appendReasoning<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n delta: string,\n id?: string,\n): AgentContentPart<T, O>[] {\n const last = content[content.length - 1];\n if (last && last.type === \"reasoning\" && last.id === id) {\n return [...content.slice(0, -1), { ...last, text: (last.text ?? \"\") + delta }];\n }\n return [\n ...content,\n id ? { type: \"reasoning\", id, text: delta } : { type: \"reasoning\", text: delta },\n ];\n}\n\nfunction upsert<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n part: AgentContentPart<T, O>,\n match: (part: AgentContentPart<T, O>) => boolean,\n): AgentContentPart<T, O>[] {\n const index = content.findIndex(match);\n if (index === -1) return [...content, part];\n const next = content.slice();\n next[index] = part;\n return next;\n}\n",
|
|
26
|
+
"import type {\n AgentContentPart,\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n AgentStreamFrame,\n FinishReason,\n NestedRun,\n PendingToolCall,\n ToolCallPart,\n ToolShapes,\n Usage,\n} from \"../types\";\n\n/**\n * Frames to a message list.\n *\n * The rule the whole file is built around: **a client may be handed any\n * suffix of a run, and may be handed the same frame twice.** An attached\n * stream starts mid-message, a reconnect replays from a cursor, and a proxy\n * that retries is entitled to deliver a frame again. So nothing here tracks\n * \"the current message\" — every event that touches a message names it, and a\n * message the list has never heard of is created on the spot rather than\n * dropped.\n *\n * The two mechanisms that make that work:\n *\n * - `seq` guards replay. A frame at or below the state's cursor is a no-op,\n * and `applyFrame` returns the *same object* so a caller can tell nothing\n * happened. Without it a redelivered `text-delta` would append its text a\n * second time — a bug that looks fine until someone refreshes.\n * - a finished message is closed to further deltas. `seq` catches a redelivery\n * within a run, but not a server that replays a run from zero to a client\n * that already has the transcript; `message-end` is terminal, so a delta for\n * a message that already carries a finish reason is replay by definition.\n * - every mutation is either an append that the seq guard already protects,\n * or an upsert keyed by an id. Tool calls and tool results arrive more than\n * once (a call re-streams as its arguments grow), so those are keyed by\n * `toolCallId`, never pushed blindly.\n *\n * A sub-agent's transcript is built by this same function calling itself. A\n * `nested-event` is unwrapped onto the `NestedRun` hanging off its parent's\n * tool-call part and handed to `reduce` again, so every rule above holds inside\n * a nested run for free — a nested `message-start` that never arrived, a\n * nested delta after a nested `message-end`, a nested `run-end` closing off a\n * message that never ended. Two levels of nesting cost this file nothing over\n * one, which is the whole reason the wire has a `nested-event` rather than a\n * second reducer.\n */\n\nexport type ChatState<T extends ToolShapes = ToolShapes, O = unknown> = {\n messages: AgentMessage<T, O>[];\n /** Non-empty exactly while the conversation is holding a question. */\n pending: PendingToolCall<T>[];\n error: AgentError | null;\n runId?: string;\n threadId?: string;\n /**\n * The highest frame applied. This is the cursor `/attach` is asked to resume\n * from, which is why it lives in the state a client keeps rather than in the\n * stream reader that dies with the connection.\n */\n seq: number;\n /**\n * Which run `seq` counts within.\n *\n * Separate from `runId`, which is cleared when the run ends because a UI asks\n * it whether anything is live. The cursor outlives the run it belongs to: a\n * frame from run_1 redelivered after run_1 finished is still a duplicate, and\n * without somewhere to remember that, replaying a finished run would look\n * exactly like the start of a new one.\n */\n cursorRunId?: string;\n /**\n * The messages the run in hand has touched, oldest first.\n *\n * `run-end` and `markAborted` both have to finish off a message whose\n * `message-end` never arrived, and \"every assistant message with no finish\n * reason\" is the wrong set to do it over: a superseded turn from an earlier\n * run is sitting in exactly that state, and stamping it with *this* run's\n * reason would relabel an interrupted answer as a clean completion. So the\n * reducer remembers which messages this run actually wrote to, and finishes\n * off only those. Reset by `run-start`; on a mid-run attach it simply fills\n * up from the first frame that names a message, which is the same set.\n */\n runMessageIds: string[];\n /**\n * The deferred tools the model has pulled in during this run, as a set.\n *\n * Not a message part, because a `tool-search` names no tool call and no\n * message — it happens *before* any call, which is exactly what makes it\n * worth showing (\"looking for the right tool\" instead of an unexplained\n * pause). So unlike `tool-progress` and `nested-event`, which now have a home\n * on the tool-call part, this one had nowhere in `AgentMessage` to go that\n * would not have meant inventing a content part in a frozen contract.\n *\n * A set, not a log: union is the only accumulation that survives redelivery\n * without a guard, and a client attached mid-run and handed a `tool-search`\n * it has already applied must not show the same tool twice. Run-scoped and\n * reset by `run-start` — it describes a run in progress, so it is deliberately\n * not something `initialChatState` restores.\n */\n loadedTools: string[];\n finishReason?: FinishReason;\n /**\n * The run's total usage so far, from its `usage` frames: every step plus what\n * its tools spent. Run-scoped and reset by `run-start`, like `loadedTools`.\n * Each assistant message's own share is on `AgentMessage.usage` (#467).\n */\n usage?: Usage;\n};\n\nexport function initialChatState<T extends ToolShapes = ToolShapes, O = unknown>(\n init: {\n messages?: AgentMessage<T, O>[];\n pending?: PendingToolCall<T>[];\n threadId?: string;\n /** Where a restored client left off. `-1` means \"I have seen nothing\". */\n seq?: number;\n /**\n * Which run that `seq` counts within. A cursor without it is a number with\n * no units — frames number from zero in every run, so `seq: 10` means\n * nothing until you know whether the live run is the one that reached 10.\n */\n cursorRunId?: string;\n } = {},\n): ChatState<T, O> {\n return {\n messages: init.messages ? [...init.messages] : [],\n pending: init.pending ? [...init.pending] : [],\n error: null,\n threadId: init.threadId,\n seq: init.seq ?? -1,\n cursorRunId: init.cursorRunId,\n runMessageIds: [],\n loadedTools: [],\n };\n}\n\n/**\n * Apply one frame.\n *\n * `now` is an argument rather than a `Date.now()` call so the reducer stays a\n * pure function of its inputs — it is only ever read when a frame arrives for a\n * message the list has not seen, which is precisely the mid-run-attach path a\n * test needs to pin down.\n */\nexport function applyFrame<T extends ToolShapes = ToolShapes, O = unknown>(\n state: ChatState<T, O>,\n frame: AgentStreamFrame<T, O>,\n now: string = new Date().toISOString(),\n): ChatState<T, O> {\n // A `seq` is a position within *one* run, so the second turn of a\n // conversation numbers its frames from zero again and the cursor left over\n // from the first would silently swallow the whole answer. `run-start` naming\n // a run this state has not seen is the one frame entitled to drop the cursor.\n const startsNewRun = frame.event.type === \"run-start\" && frame.event.runId !== state.cursorRunId;\n // Identity, not a copy: the hook reads `next === prev` as \"already applied\"\n // and skips the callbacks that would otherwise fire twice.\n if (!startsNewRun && frame.seq <= state.seq) return state;\n return { ...reduce(state, frame.event, now), seq: frame.seq };\n}\n\nfunction reduce<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n event: AgentStreamFrame<T, O>[\"event\"],\n now: string,\n): ChatState<T, O> {\n switch (event.type) {\n case \"run-start\":\n return {\n ...state,\n // A run's in-progress copies, emptied so the replay that starts here\n // rebuilds them (#778). A thread read while a run is going holds what\n // the controller stored of it so far (`AgentMessage.runId`, no\n // `finishReason`), and a client that shows that read and then attaches\n // gets the run from its first frame: appending the replayed deltas to\n // the stored text printed it twice. `run-start` is frame 0, so\n // everything the copy held is on its way again. Kept in place rather\n // than dropped, so the transcript's order does not change under it.\n messages: resetInProgress(state.messages, event.runId),\n runId: event.runId,\n cursorRunId: event.runId,\n threadId: event.threadId ?? state.threadId,\n runMessageIds: [],\n loadedTools: [],\n finishReason: undefined,\n usage: undefined,\n };\n\n case \"message-start\":\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n role: event.role,\n }));\n\n // The two additive cases, and the only two that can double text. `seq`\n // catches an ordinary redelivery, but a client resuming with a cursor the\n // server ignores — or asked for the whole run when it already had the\n // transcript — gets frames it cannot recognise as duplicates. A finished\n // message is the one thing it can: `message-end` is terminal, so a delta\n // arriving for a message that already carries a finish reason is replay by\n // definition and appending it would show the answer twice.\n case \"text-delta\":\n if (isFinished(state, event.messageId)) return state;\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: appendText(message.content, event.delta),\n }));\n\n case \"reasoning-delta\":\n if (isFinished(state, event.messageId)) return state;\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: appendReasoning(message.content, event.delta, event.id),\n }));\n\n case \"output-delta\":\n // `snapshot` is the whole object so far, not an increment, so the raw\n // `delta` text is dropped here on purpose: replacing beats accumulating\n // when a client may have missed the first half of the JSON.\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: upsert(\n message.content,\n { type: \"output\", value: event.snapshot as O, partial: true },\n (part) => part.type === \"output\",\n ),\n }));\n\n case \"tool-call\":\n // Keyed, because the same call re-streams as its arguments fill in — and\n // *merged* rather than replaced, which the plain upsert below cannot do.\n //\n // A `tool-call` frame is the model's half of the part. `progress` and\n // `nested` are the execution's half, and they arrive on events that name\n // no message, so a part that loses them cannot rebuild them from anything\n // later in the stream. Replacing wholesale is exactly how a run replayed\n // onto a transcript that already holds it drops a sub-agent's entire\n // transcript while appearing to converge.\n return withMessage(state, event.messageId, now, (message) => {\n const index = message.content.findIndex(\n (part) => part.type === \"tool-call\" && part.toolCallId === event.part.toolCallId,\n );\n const existing = index === -1 ? undefined : (message.content[index] as ToolCallPart<T>);\n // The frame wins where it says anything — a server that persists the\n // nested transcript and re-sends it is more authoritative than what this\n // client accumulated — and the part is kept where it does not.\n const progress = event.part.progress ?? existing?.progress;\n const nested = event.part.nested ?? existing?.nested;\n // `attachments` is kept for the same reason and with a sharper\n // consequence: it is the memo `ctx.attachments.put` replays from, so a\n // stateless client that dropped it posts back a history in which the\n // tool call never attached anything — and a re-entered tool stores the\n // bytes again, uploads them again, and shows the model a second copy of\n // its own output. Losing `progress` costs a log; losing this costs\n // money and confuses the model.\n const attachments = event.part.attachments ?? existing?.attachments;\n const part = {\n ...event.part,\n ...(progress ? { progress } : {}),\n ...(nested ? { nested } : {}),\n ...(attachments ? { attachments } : {}),\n };\n const content = message.content.slice();\n if (index === -1) content.push(part);\n else content[index] = part;\n return { ...message, content };\n });\n\n case \"tool-search\": {\n // Accumulated as a set. Every other additive event in this file leans on\n // `seq` to survive redelivery; this one cannot, because a `tool-search`\n // carries no id at all — there is nothing to key an upsert on and nothing\n // to tell a second delivery from a second search. Union is what makes the\n // question moot: applying the same frame again is the same set, and two\n // genuinely different searches that both loaded `refundOrder` are, for a\n // UI naming the tools in play, the same fact twice.\n const loaded = event.loaded.filter((name) => !state.loadedTools.includes(name));\n if (loaded.length === 0) return state;\n return { ...state, loadedTools: [...state.loadedTools, ...loaded] };\n }\n\n case \"tool-progress\":\n // Append-only, exactly like a text delta, and protected the same two\n // ways: `seq` for redelivery within a run, and the finished-message check\n // inside `withToolCall` for a run replayed onto a transcript that already\n // holds it. The tool loop emits every yield before the message it belongs\n // to is finalised, so a progress datum for a finished message is replay\n // by definition — the same argument `text-delta` makes, and with the same\n // carve-out for a message the run parked on.\n //\n // Unbounded on purpose: a tool decides how often it yields, and truncating\n // its log here would lose data the UI asked for. What is bounded is the\n // *wire* — `useChat.send` strips `progress` from the history it posts, so\n // a tool that yields ten thousand times costs ten thousand entries in this\n // tab and nothing at all on every later turn. See `forWire`.\n return withToolCall(state, event.toolCallId, (part) => ({\n ...part,\n progress: [...(part.progress ?? []), event.data],\n }));\n\n case \"nested-event\": {\n // The recursion. The sub-run's transcript is an ordinary message list, so\n // it is reduced by this function rather than by a parallel one — which is\n // why an arbitrarily deep nesting is not a case handled here at all: an\n // inner `nested-event` simply lands back in this branch, one message list\n // further down.\n const nestedEvent = event as NestedEvent;\n return withToolCall(state, event.toolCallId, (part) => {\n const runs = part.nested ?? [];\n const index = runs.findIndex((run) => run.runId === nestedEvent.runId);\n // Created on the spot when unknown, for the same reason `withMessage`\n // creates a message it never saw start: a client attached mid-run gets\n // the sub-run's tail and no `run-start`, and dropping it would leave a\n // tool call that visibly does something looking like one that hangs.\n const run: NestedRun = runs[index] ?? {\n runId: nestedEvent.runId,\n agent: nestedEvent.agent,\n messages: [],\n };\n const next = applyNested(run, nestedEvent, now);\n const nested =\n index === -1 ? [...runs, next] : runs.map((r, i) => (i === index ? next : r));\n return { ...part, nested };\n });\n }\n\n case \"tool-result\": {\n const next = withMessage(state, event.messageId, now, (message) => ({\n ...message,\n content: upsert(\n message.content,\n event.part,\n (part) => part.type === \"tool-result\" && part.toolCallId === event.part.toolCallId,\n ),\n }));\n // A result is the answer to a pending call, whoever produced it — the\n // human here, or the server after an approval. Either way it is no longer\n // pending, and leaving it in the list would keep the UI asking.\n return {\n ...next,\n pending: next.pending.filter((call) => call.toolCallId !== event.part.toolCallId),\n };\n }\n\n case \"message\": {\n // A whole message, replaced or appended by id.\n //\n // The wholesale replace the `tool-call` branch above argues against is\n // right here, and the difference is authorship. A tool-call part is\n // assembled from two sources — the model's half on this frame, the\n // execution's half on events that name no message — so a client that\n // replaces it drops what only it was holding. This message has one\n // author, the server, and is complete before it is ever sent; there is no\n // client-accumulated half to lose, so a second delivery is the same value\n // written twice.\n //\n // Appended at the end when unknown, which is where it belongs: the run\n // emits it the moment it appends it to its own history, so stream order\n // and transcript order are the same order. Not routed through\n // `withMessage`, which would create the message as `assistant` — the role\n // is on the frame and it is `user`.\n const index = state.messages.findIndex((message) => message.id === event.message.id);\n const messages = state.messages.slice();\n if (index === -1) messages.push(event.message);\n else messages[index] = event.message;\n const runMessageIds = state.runMessageIds.includes(event.message.id)\n ? state.runMessageIds\n : [...state.runMessageIds, event.message.id];\n return { ...state, messages, runMessageIds };\n }\n\n case \"message-id\": {\n // The client's own copy of its turn, renamed to the id the server stored\n // it under (#466). Only the id changes: the copy is what the user typed\n // and is already on screen, and the server never sends the turn itself.\n // The client's key for it stays (#818): `localId` is what a UI keys the\n // element by, and the rename must not remount it.\n //\n // A no-op when nothing is under `localId` — a replay after the rename,\n // or a client attached from elsewhere that never held the copy. If the\n // server's id is somehow already there too, the local copy is the\n // duplicate and goes. Not added to `runMessageIds`: a user message is\n // complete when it is sent, and `run-end` has nothing to close on it.\n const index = state.messages.findIndex((message) => message.id === event.localId);\n if (index === -1) {\n // Not this client's turn: a client attached to a run another one\n // started (#778). The server sends the stored turn along for exactly\n // this, and it goes where the run put it, before the answer. Already\n // here under the server's id (a thread read, or a replay) it is left\n // alone.\n if (!event.message || state.messages.some((m) => m.id === event.messageId)) return state;\n return { ...state, messages: [...state.messages, event.message] };\n }\n // When the server's copy is already here and the local one goes, the key\n // and the app's `metadata` move onto the copy that stays, so the element\n // the user is looking at is still the one it was.\n const local = state.messages[index]!;\n const kept = {\n localId: local.localId ?? local.id,\n ...(local.metadata ? { metadata: local.metadata } : {}),\n };\n const messages = state.messages.some((message) => message.id === event.messageId)\n ? state.messages\n .filter((_, i) => i !== index)\n .map((message) => (message.id === event.messageId ? { ...message, ...kept } : message))\n : state.messages.map((message, i) =>\n i === index ? { ...message, ...kept, id: event.messageId } : message,\n );\n return { ...state, messages };\n }\n\n case \"awaiting-input\":\n return { ...state, runId: event.runId, pending: [...event.pending] };\n\n case \"message-end\":\n return withMessage(state, event.messageId, now, (message) => ({\n ...message,\n finishReason: event.finishReason,\n // Kept, not merely acted on. Dropping the partial output leaves a UI\n // unable to tell a cut-off answer from a message that never had one, and\n // the finish reason cannot say which — see `AgentMessage.outputTruncated`.\n ...(event.outputTruncated ? { outputTruncated: true as const } : {}),\n // This message's own model call (#467). An assignment, so a replay is\n // harmless; absent on the frame, the message keeps whatever it had.\n ...(event.usage ? { usage: event.usage } : {}),\n content:\n // A run cut off by the output ceiling has no answer, and the partial\n // output part is dropped rather than completed.\n //\n // `snapshot` is `bestEffortParse` of the text so far, which closes\n // whatever brackets are open — so the last partial looks like a whole\n // document, and stamping it `partial: false` here presented a\n // half-written object as the finished one. The server already\n // withholds the output part on `length` for that reason; without this\n // the two disagreed, and the client held the more convincing lie.\n // `outputTruncated` first: it is the fact, and the finish reason is\n // not it — a step that hit the ceiling and also called a tool ends the\n // message `awaiting-input` or `max-steps`. `length` is still honoured\n // for a server that predates the field.\n event.outputTruncated || event.finishReason === \"length\"\n ? message.content.filter((part) => !(part.type === \"output\" && part.partial))\n : message.content.map((part) =>\n part.type === \"output\" && part.partial ? { ...part, partial: false } : part,\n ),\n }));\n\n case \"usage\":\n // The run's total, not any message's (#467). It used to be put on the\n // last assistant message, so a three-step run showed every token on step\n // three and nothing on the first two — and a run whose tools spent\n // through `generate()` or a sub-run billed that to a message that never\n // made the call. Each message now gets its own from `message-end`; this\n // is the turn's, on the state. An assignment, so a replay is harmless.\n return { ...state, usage: event.usage };\n\n case \"error\":\n // Clearing `pending` here is what keeps \"pending is non-empty exactly\n // when the UI is awaiting input\" true: a run that errored is not holding\n // a question any more, it is holding a failure.\n return { ...state, error: event.error, pending: [] };\n\n case \"run-end\":\n return {\n ...state,\n runId: undefined,\n finishReason: event.finishReason,\n // A safety net for the client that attached late and never saw a\n // `message-end`: once the run is over nothing is still streaming, so a\n // message left without a finish reason would show a cursor forever.\n //\n // Scoped to this run's own messages. A turn superseded by a second send\n // is also sitting there unfinished, and it was *not* finished by this\n // run — stamping it \"stop\" would tell the user, and the model on the\n // next stateless turn, that an answer cut off mid-sentence ended\n // cleanly.\n messages: finishUnended(state, event.finishReason),\n };\n\n // Every event in the union is handled above, so this is reached only by a\n // server that speaks a newer protocol than this client. Kept as a silent\n // no-op rather than an exhaustiveness assertion for that reason: an old tab\n // meeting a new event must keep rendering the rest of the stream, and the\n // seq still advances so its cursor stays right.\n default:\n return state;\n }\n}\n\n/**\n * The interrupted turn, kept.\n *\n * `stop()` calls this before the server has said anything, because the point of\n * stopping is that the UI reacts now. Whatever the assistant had produced stays\n * in the list marked `aborted` — dropping it would lose text the user already\n * read, and would leave the transcript unable to say it was cut short.\n *\n * `pending` is untouched: a question the conversation is holding survives a\n * stopped run, and clearing it would silently discard the answer the user still\n * owes.\n */\nexport function markAborted<T extends ToolShapes = ToolShapes, O = unknown>(\n state: ChatState<T, O>,\n): ChatState<T, O> {\n return {\n ...state,\n runId: undefined,\n finishReason: \"aborted\",\n // This run's messages only, for the same reason `run-end` is scoped: an\n // older turn that was already cut short is not cut short again by this one,\n // and a restored transcript may legitimately carry an unfinished message\n // that has nothing to do with the run being stopped.\n messages: finishUnended(state, \"aborted\"),\n };\n}\n\n// --- helpers -------------------------------------------------------------\n\n/**\n * The stored in-progress copies of `runId`'s messages, emptied for a replay.\n *\n * Only a message that says it is that run's and unfinished: a finished one is\n * closed to deltas already, and anything without the run's id is not this\n * run's to touch. The id goes too, since the copy is now the client's own\n * live message, the shape a streamed message has. Identity when there is\n * nothing to reset, which is every `run-start` a client streams itself.\n */\nfunction resetInProgress<T extends ToolShapes, O>(\n messages: AgentMessage<T, O>[],\n runId: string,\n): AgentMessage<T, O>[] {\n if (!messages.some((m) => m.runId === runId && m.finishReason === undefined)) return messages;\n return messages.map((message) => {\n if (message.runId !== runId || message.finishReason !== undefined) return message;\n const { runId: _runId, ...rest } = message;\n return { ...rest, content: [] };\n });\n}\n\n/**\n * The messages this run wrote, finished off with `reason` if they never ended —\n * and, inside them, the sub-runs this run left mid-sentence.\n *\n * The nesting descent is not an extra: a `NestedRun` renders with the component\n * that renders `messages`, so a nested message with no `finishReason` draws a\n * live cursor inside a block that will never receive another frame. The parent\n * ending is the last word anything will say about it, and for `markAborted`\n * there is no other word available at all — `stop()` marks the transcript\n * optimistically, before the server has answered, so no forwarded nested\n * `run-end` can arrive in time.\n *\n * It recurses through `closeRun`, which builds a `ChatState` around the sub-run\n * and calls back here, so a sub-sub-run is closed by the same three lines that\n * close the top level — the same trick `applyNested` plays on the way in.\n */\nfunction finishUnended<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n reason: FinishReason,\n): AgentMessage<T, O>[] {\n return state.messages.map((message) =>\n message.role === \"assistant\" && state.runMessageIds.includes(message.id)\n ? closeMessage(message, reason)\n : message,\n );\n}\n\n/**\n * One message of this run, and the sub-runs hanging off its tool calls.\n *\n * The message's own finish reason is only filled in when it is missing, but the\n * descent happens either way: the message a run parks on is *finished* while the\n * sub-run underneath it is still live, and that is the case where the block\n * stuck streaming is easiest to hit.\n */\nfunction closeMessage<T extends ToolShapes, O>(\n message: AgentMessage<T, O>,\n reason: FinishReason,\n): AgentMessage<T, O> {\n const content = message.content.map((part) =>\n part.type === \"tool-call\" && part.nested?.some((run) => run.finishReason === undefined)\n ? {\n ...part,\n nested: part.nested.map((run) =>\n run.finishReason === undefined ? closeRun(run, reason) : run,\n ),\n }\n : part,\n );\n if (message.finishReason === undefined) return { ...message, finishReason: reason, content };\n // Identity where nothing changed, so `run-end` on a settled transcript keeps\n // the parts a UI may be memoising on.\n const changed = content.some((part, index) => part !== message.content[index]);\n return changed ? { ...message, content } : message;\n}\n\n/** A sub-run the parent outlived, stamped with the parent's reason, recursively. */\nfunction closeRun(run: NestedRun, reason: FinishReason): NestedRun {\n const sub: ChatState = {\n messages: run.messages,\n pending: [],\n error: null,\n seq: -1,\n // Every message in the transcript, for the reason `applyNested` gives: a\n // `NestedRun` is keyed by `runId` and only ever written by events carrying\n // it, so there is no other run's work in here to protect.\n runMessageIds: run.messages.map((message) => message.id),\n loadedTools: [],\n };\n return { ...run, finishReason: reason, messages: finishUnended(sub, reason) };\n}\n\ntype NestedEvent = Extract<AgentStreamEvent, { type: \"nested-event\" }>;\n\n/**\n * Run one update over the tool-call part with this id, wherever it lives.\n *\n * `tool-progress` and `nested-event` are the only events that name a tool call\n * without naming a message, so the message has to be found rather than told —\n * a scan from the newest end, because the call being worked on is the one that\n * just arrived.\n *\n * **A frame for a tool call this transcript does not have is dropped.** That is\n * the mid-run `/attach` case the whole file is written for, and it is the one\n * place the usual answer — create it on the spot — is the wrong one: a\n * `ToolCallPart` needs a tool `name` and an `input`, and neither is on these\n * events. Inventing them would put a tool call the model never made into the\n * transcript, under a name that is not a key of the agent's tools, which breaks\n * the narrowing that is the reason the shapes are carried into the browser at\n * all. So the progress is lost and the transcript stays true, rather than the\n * other way round.\n *\n * In practice a client that has the cursor has the part: `useChat` documents\n * `cursor` and `initialMessages` as things to persist together, and a client\n * that persisted one without the other is already the case that doubles text.\n * Parking the orphans until their tool call shows up was considered and is not\n * worth it — the call is *earlier* in the stream, never later, so nothing would\n * ever drain the parking lot.\n */\nfunction withToolCall<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n toolCallId: string,\n update: (part: ToolCallPart<T>) => ToolCallPart<T>,\n): ChatState<T, O> {\n for (let i = state.messages.length - 1; i >= 0; i--) {\n const message = state.messages[i]!;\n const index = message.content.findIndex(\n (part) => part.type === \"tool-call\" && part.toolCallId === toolCallId,\n );\n if (index === -1) continue;\n // The replay guard, and the same one the deltas use — with the one carve-out\n // a delta does not need.\n //\n // Within a run the tool loop runs every tool before it finalises the message\n // the calls sit in, so a frame for a call inside a finished message is that\n // run being replayed onto a transcript that already has it, and appending\n // would show the progress log twice.\n //\n // But a message the run *parked* on is not a closed message. `Agent.loop`\n // finalises it with `\"awaiting-input\"` **before** emitting `awaiting-input`,\n // and the very next turn re-enters that same tool call — `resolveAnswer`\n // calls `executeTool` against the call it found in the history — so its\n // `tool-progress` and `nested-event` frames arrive after their message\n // carries a finish reason. Treating those as replay dropped every frame of\n // the resumed execution while the `tool-result` (which goes through\n // `withMessage`, unguarded) still landed: the call went silent and then\n // produced an answer, which is the bug nesting exists to fix. Worse, in\n // stateless mode the nested transcript is what the next turn replays the\n // sub-run from, so the client posted back a sub-run frozen at the question.\n //\n // The carve-out is as narrow as the case: parked, *and* the call still open.\n // Once its result has landed nothing legitimately appends to it again, so a\n // replay of a parked run is still refused for every call it answered.\n if (message.finishReason !== undefined && !isReenterable(state, message, toolCallId)) {\n return state;\n }\n const content = message.content.slice();\n content[index] = update(content[index] as ToolCallPart<T>);\n const messages = state.messages.slice();\n messages[i] = { ...message, content };\n // Counted as a message this run touched, like every event that names one\n // directly — a client whose only frames for this message were nested ones\n // still needs `run-end` to close it, or it shows a cursor forever.\n const runMessageIds = state.runMessageIds.includes(message.id)\n ? state.runMessageIds\n : [...state.runMessageIds, message.id];\n return { ...state, runMessageIds, messages };\n }\n return state;\n}\n\n/**\n * One sub-run event, applied to the sub-run's own transcript.\n *\n * The sub-state is built and thrown away per event rather than kept, because\n * there is nowhere to keep it: `NestedRun` is a wire type and holds a\n * transcript, not a reducer state. Everything the inner `reduce` needs is\n * derivable from it.\n *\n * - `seq` is `-1` and this calls `reduce`, not `applyFrame`. A nested event\n * has no sequence of its own; it is numbered in the *parent's* stream, and\n * the parent's cursor has already refused the duplicates.\n * - `runMessageIds` is every message in the transcript, which for a nested\n * run is exactly right and needs none of the parent's care. The parent\n * scopes it because its list mixes runs; a `NestedRun` is keyed by `runId`\n * and only ever written by events carrying that id, so every message in it\n * belongs to the run that is ending.\n * - `pending` is dropped. An escalated question reaches the user on the\n * *parent's* `awaiting-input`, carrying the path that says which tool to\n * re-enter; the copy inside the sub-run's own stream carries no path, so\n * surfacing it would show the question twice and make one of them\n * unanswerable.\n */\nfunction applyNested(run: NestedRun, event: NestedEvent, now: string): NestedRun {\n const sub: ChatState = {\n messages: run.messages,\n pending: [],\n error: null,\n seq: -1,\n runMessageIds: run.messages.map((message) => message.id),\n loadedTools: [],\n finishReason: run.finishReason,\n };\n const next = reduce(sub, event.event, now);\n return {\n ...run,\n // A late label is still a label: `/attach` may deliver the sub-run's tail,\n // and every nested frame carries it.\n ...(event.label !== undefined ? { label: event.label } : {}),\n messages: next.messages,\n ...(next.finishReason !== undefined ? { finishReason: next.finishReason } : {}),\n // The sub-run's own total, lifted so a UI can price the block it is\n // rendering without walking its messages — which carry only their own\n // steps' usage, not what the sub-run's tools spent. An assignment, so\n // redelivery is harmless.\n ...(next.usage !== undefined ? { usage: next.usage } : {}),\n };\n}\n\n/**\n * Whether a finished message's tool call can still be written to.\n *\n * Exactly one message can say yes: the one a run parked on, holding a call\n * nobody has answered yet. That is the resume turn — the tool is re-entered\n * from the top and streams progress and sub-run events against a message that\n * closed on the previous turn.\n *\n * \"Open\" is the server's own test, `Agent.openCalls`: a tool call with no\n * `tool-result` for it anywhere in the transcript. The result is the thing that\n * says the re-entry finished, and it always arrives *after* the frames this\n * guards — `attachToHistory` emits it once `executeTool` returns.\n */\nfunction isReenterable<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n message: AgentMessage<T, O>,\n toolCallId: string,\n) {\n if (message.finishReason !== \"awaiting-input\") return false;\n return !state.messages.some((candidate) =>\n candidate.content.some((part) => part.type === \"tool-result\" && part.toolCallId === toolCallId),\n );\n}\n\nfunction isFinished<T extends ToolShapes, O>(state: ChatState<T, O>, messageId: string) {\n const message = state.messages.find((candidate) => candidate.id === messageId);\n return message !== undefined && message.finishReason !== undefined;\n}\n\nfunction withMessage<T extends ToolShapes, O>(\n state: ChatState<T, O>,\n messageId: string,\n now: string,\n update: (message: AgentMessage<T, O>) => AgentMessage<T, O>,\n): ChatState<T, O> {\n const index = state.messages.findIndex((message) => message.id === messageId);\n // Every id-carrying event marks its message as one this run touched, which is\n // what `run-end` and `markAborted` read to know whose loose ends are theirs.\n const runMessageIds = state.runMessageIds.includes(messageId)\n ? state.runMessageIds\n : [...state.runMessageIds, messageId];\n if (index === -1) {\n // The mid-stream attach. Every id-carrying event describes an assistant\n // message — `message-start` is the only event that declares a role and it\n // declares that one — so a placeholder is enough to hang the tail on.\n const blank: AgentMessage<T, O> = {\n id: messageId,\n role: \"assistant\",\n content: [],\n createdAt: now,\n };\n return { ...state, runMessageIds, messages: [...state.messages, update(blank)] };\n }\n const messages = state.messages.slice();\n messages[index] = update(messages[index]!);\n return { ...state, runMessageIds, messages };\n}\n\nfunction appendText<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n delta: string,\n): AgentContentPart<T, O>[] {\n const last = content[content.length - 1];\n // Coalesced into the trailing text part, but only if it *is* trailing: a\n // delta after a tool call opens a new part, which is what lets a UI render\n // \"thinking / call / answer\" in the order it happened.\n if (last && last.type === \"text\") {\n return [...content.slice(0, -1), { type: \"text\", text: last.text + delta }];\n }\n return [...content, { type: \"text\", text: delta }];\n}\n\n/**\n * Mirrors `appendReasoning` in Agent.ts, including its merge rule: deltas join\n * the last part only when the reasoning-item id matches, so a step that\n * produced two items stays two parts instead of flattening into one under the\n * wrong id. The two implementations have to agree, because a stateless client\n * posts this content straight back and the provider matches on that id.\n */\nfunction appendReasoning<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n delta: string,\n id?: string,\n): AgentContentPart<T, O>[] {\n const last = content[content.length - 1];\n if (last && last.type === \"reasoning\" && last.id === id) {\n return [...content.slice(0, -1), { ...last, text: (last.text ?? \"\") + delta }];\n }\n return [\n ...content,\n id ? { type: \"reasoning\", id, text: delta } : { type: \"reasoning\", text: delta },\n ];\n}\n\nfunction upsert<T extends ToolShapes, O>(\n content: AgentContentPart<T, O>[],\n part: AgentContentPart<T, O>,\n match: (part: AgentContentPart<T, O>) => boolean,\n): AgentContentPart<T, O>[] {\n const index = content.findIndex(match);\n if (index === -1) return [...content, part];\n const next = content.slice();\n next[index] = part;\n return next;\n}\n",
|
|
36
27
|
"import type { AgentStore } from \"../AgentController\";\nimport { applyFrame, type ChatState, initialChatState } from \"../client/reducer\";\nimport type {\n AgentMessage,\n AgentStreamFrame,\n NestedRun,\n ToolCallPart,\n ToolResultPart,\n} from \"../types\";\n\n/**\n * A threaded turn, written to the store while it runs (#617).\n *\n * The controller used to store a turn once, when its run ended. A process that\n * died mid-run (a restart, a crash, a deploy) left the thread without the turn\n * at all, not even the user's message, while the run's tools may already have\n * written durable changes. Neither the app nor the model could tell a turn that\n * never happened from one that was lost.\n *\n * So a turn is now written as it goes, through the store's own upsert:\n *\n * - **Finished messages** (`finish`), as the run reports them: the user's turn\n * before the model is asked anything, each assistant message as it closes,\n * an earlier message a turn amended. The run's own objects, so they are\n * exactly what the end-of-run write stores.\n * - **The message in progress** (`frame`), at the points worth keeping: when it\n * opens, when a tool call's arguments are complete, when a tool result\n * lands, and a whole message the run injected. It is assembled from the\n * run's frames by the client reducer (the code every client already renders\n * a live run with) and stored with no `finishReason` and the run's id in\n * `runId`, which is what lets a later reader see that its run is gone.\n * Text deltas are not a checkpoint: a store write per token is not worth\n * the text a crash would lose.\n *\n * Every write is an upsert by message id, so writing a message twice, or a\n * retried start writing the same turn again, leaves one copy. Writes go out one\n * at a time and in order, off the run's path: a slow store does not slow the\n * model, and a message's in-progress copy can never land after its finished\n * one. A write that fails is reported and the run carries on, as a hook\n * failure does; the end-of-run write stores everything again anyway.\n */\nexport class TurnJournal {\n private chain: Promise<void> = Promise.resolve();\n /** Ids whose finished copy has been queued. An in-progress copy of one of\n * these is stale by definition and is never written after it. */\n private readonly done = new Set<string>();\n private closed = false;\n private state: ChatState;\n private runId: string | undefined;\n\n constructor(\n private readonly store: AgentStore,\n private readonly threadId: string,\n /** The history the run starts from, so a tool result that lands on an\n * earlier turn's message checkpoints the whole message, not a stub of it. */\n history: AgentMessage[],\n private readonly report: (error: unknown) => void,\n ) {\n this.state = initialChatState({ messages: history });\n }\n\n /** A message the run has finished. Queued as it is, and final. */\n finish(message: AgentMessage): void {\n if (this.closed) return;\n this.done.add(message.id);\n this.write(() => [snapshot(message)]);\n }\n\n /** One frame of the run, in order. Writes the message it touched when the\n * frame is a checkpoint. */\n frame(frame: AgentStreamFrame): void {\n if (this.closed) return;\n const event = frame.event;\n if (event.type === \"run-start\") this.runId = event.runId;\n this.state = applyFrame(this.state, frame);\n\n switch (event.type) {\n case \"message\":\n // Complete when it is made (see the event), so it is written whole. Not\n // marked done: the run reports it again once the message above it\n // closes, and that copy is the one that stays.\n this.write(() => [snapshot(event.message)]);\n return;\n case \"tool-call\":\n if (event.part.partial) return;\n this.checkpoint(event.messageId);\n return;\n case \"message-start\":\n case \"tool-result\":\n this.checkpoint(event.messageId);\n return;\n default:\n return;\n }\n }\n\n /**\n * The run is over and its transcript is about to be written whole: nothing\n * more is queued after this. `messages` are the ones that write will hold,\n * so a frame still on its way cannot put an in-progress copy of one of them\n * back.\n */\n close(messages: AgentMessage[] = []): void {\n this.closed = true;\n for (const message of messages) this.done.add(message.id);\n }\n\n /** Settles once every queued write has. Never rejects. */\n settled(): Promise<void> {\n return this.chain;\n }\n\n private checkpoint(messageId: string): void {\n if (this.done.has(messageId)) return;\n const message = this.state.messages.find((held) => held.id === messageId);\n if (!message) return;\n const runId = this.runId;\n this.write(() => {\n const copy = snapshot(message);\n // Stamped only on a message still being written: the run's id is the\n // thing a reader checks for liveness, and a finished message has nothing\n // to check.\n if (copy.finishReason === undefined && runId) copy.runId = runId;\n return [copy];\n });\n }\n\n /**\n * Queues one write. The copy is taken now, before anything else can change\n * the message, and a copy that fails (a tool output that is not plain data)\n * costs that one write, not the journal: the end-of-run write still stores\n * the message.\n */\n private write(copy: () => AgentMessage[]): void {\n let messages: AgentMessage[];\n try {\n messages = copy();\n } catch (error) {\n this.report(error);\n return;\n }\n this.chain = this.chain\n .then(() => this.store.appendMessages(this.threadId, messages))\n .catch((error) => this.report(error));\n }\n}\n\n/**\n * A copy the run cannot change under the store. The run keeps writing to its\n * own objects (a tool result onto the message that made the call), and a store\n * that holds references, as `MemoryAgentStore` does, would otherwise show a\n * reader a message that changes after it was written.\n */\nfunction snapshot(message: AgentMessage): AgentMessage {\n return structuredClone(message);\n}\n\n/**\n * The thread as it stands, with every message a dead run left unfinished\n * marked as such.\n *\n * An assistant message with no `finishReason` is either still being written or\n * was being written by a run that is gone. `isLive` tells the two apart by the\n * message's `runId`; a message without one belongs to no run and is gone too.\n * Each gone one is closed as `interrupted`:\n *\n * - its own `finishReason`, so a UI shows \"cut off\" rather than a cursor that\n * never stops;\n * - a `denied` result with `cause: \"interrupted\"` for every tool call it left\n * without one, so the history stays valid for the provider (a call with no\n * output is a 400) and the model reads what happened to it;\n * - the same reason on any sub-run under its tool calls that never finished,\n * which would otherwise draw a cursor of its own.\n *\n * `settled` is the messages that changed, for the caller to write back. Running\n * this again on its own output changes nothing, which is what makes it safe to\n * run on every read.\n */\nexport async function settleInterrupted(\n messages: AgentMessage[],\n isLive: (runId: string) => boolean | Promise<boolean>,\n): Promise<{ messages: AgentMessage[]; settled: AgentMessage[] }> {\n const settled: AgentMessage[] = [];\n let resolved: Set<string> | null = null;\n const out = messages.slice();\n\n for (let at = 0; at < out.length; at++) {\n const message = out[at]!;\n if (message.role !== \"assistant\" || message.finishReason !== undefined) continue;\n if (message.runId && (await isLive(message.runId))) continue;\n\n // Computed once, and only for a thread that has something to settle,\n // which is almost never.\n resolved ??= new Set(\n messages.flatMap((held) =>\n held.content.flatMap((part) => (part.type === \"tool-result\" ? [part.toolCallId] : [])),\n ),\n );\n\n const content = message.content.map((part) =>\n part.type === \"tool-call\" ? closeCall(part as ToolCallPart) : part,\n );\n for (const part of message.content) {\n if (part.type !== \"tool-call\" || resolved.has(part.toolCallId)) continue;\n const result: ToolResultPart = {\n type: \"tool-result\",\n toolCallId: part.toolCallId,\n name: part.name,\n status: \"denied\",\n cause: \"interrupted\",\n };\n content.push(result);\n }\n const closed: AgentMessage = { ...message, content, finishReason: \"interrupted\" };\n out[at] = closed;\n settled.push(closed);\n }\n\n return { messages: out, settled };\n}\n\n/** A call as a dead run left it: its arguments are all there will ever be,\n * and a sub-run under it that never finished is interrupted too. */\nfunction closeCall(part: ToolCallPart): ToolCallPart {\n const { partial: _partial, ...call } = part;\n if (!call.nested?.some((run) => run.finishReason === undefined)) return call as ToolCallPart;\n return { ...call, nested: call.nested.map(closeRun) } as ToolCallPart;\n}\n\nfunction closeRun(run: NestedRun): NestedRun {\n if (run.finishReason !== undefined) return run;\n return {\n ...run,\n finishReason: \"interrupted\",\n messages: run.messages.map((message) =>\n message.role === \"assistant\" && message.finishReason === undefined\n ? {\n ...message,\n finishReason: \"interrupted\" as const,\n content: message.content.map((part) =>\n part.type === \"tool-call\" ? closeCall(part as ToolCallPart) : part,\n ),\n }\n : message,\n ),\n };\n}\n",
|
|
37
28
|
"import type { Schema } from \"../Schema\";\nimport type { AgentJobRef, AgentMessage, ToolResultPart } from \"../types\";\nimport { clockOf, expire } from \"./AgentJob\";\nimport type { AgentJobRecord, AgentJobState, AgentJobStore } from \"./AgentJobStore\";\n\n/** How many of a thread's newest jobs are checked for orphans on each load. */\nconst ORPHAN_SCAN = 50;\n\nconst ANY_STATE: AgentJobState[] = [\"running\", \"ok\", \"error\"];\n\n/**\n * The thread with each background job's current state rendered over the tool\n * result that points at it (#461).\n *\n * A tool that returned a `JobHandle` left a `running` result in the thread.\n * The job settles later, into the job store, and never into the messages: a\n * live run writes whole messages, and a settle racing those writes would be\n * overwritten by the run's stale copy. So the messages are brought up to date\n * here, when the thread is loaded, which `AgentController` does under the\n * thread's lock before a turn and without writing for `readThread`.\n *\n * - A `running` result whose job settled becomes the job's `ok` or `error`\n * result, in place, with the job still named on it (`job`).\n * - A `running` result whose job is still running is left exactly as it is,\n * so the request stays byte-identical, and the prompt cache with it, until\n * the job settles.\n * - A `running` result whose job the store does not have becomes an `error`:\n * the record was lost (a memory store across a restart), and the work may or\n * may not have happened.\n *\n * `settled` is the messages that changed, for the caller to write back, so\n * the store converges and a job settled long ago costs nothing on later loads.\n *\n * `orphans` are jobs whose tool result never reached the thread: the run died\n * between starting the job and storing the result. They are found among the\n * thread's newest jobs, only once the run that started them is gone, and only\n * the ones not marked yet; the caller marks them (`orphaned`).\n */\nexport async function overlayJobs(\n messages: AgentMessage[],\n params: {\n threadId: string;\n store: AgentJobStore;\n isRunLive: (runId: string) => boolean | Promise<boolean>;\n /** The tool's output schema, to check a settled output against. */\n outputSchemaFor?: (toolName: string) => Schema<any> | undefined;\n /** How many of the thread's newest jobs to read. At least 50. */\n scan?: number;\n },\n): Promise<{\n messages: AgentMessage[];\n settled: AgentMessage[];\n orphans: AgentJobRecord[];\n /** The thread's newest jobs, as they stand after this pass: for the `<jobs>` block. */\n jobs: AgentJobRecord[];\n}> {\n const { store, threadId } = params;\n const scan = Math.max(ORPHAN_SCAN, params.scan ?? 0);\n const recent = await store.listForThread(threadId, { limit: scan });\n\n // The lazy half of the deadline sweep: a running job past its deadline is\n // failed here, so an app with no cron still sees it fail.\n let now: number | undefined;\n const current = async (record: AgentJobRecord): Promise<AgentJobRecord> => {\n if (record.state !== \"running\") return record;\n now ??= await clockOf(store);\n if (record.deadlineAt > now) return record;\n await expire(store, record);\n return (await store.get(record.id)) ?? record;\n };\n for (let index = 0; index < recent.length; index++) {\n recent[index] = await current(recent[index]!);\n }\n const known = new Map(recent.map((record) => [record.id, record]));\n\n const out = messages.slice();\n const settled: AgentMessage[] = [];\n const calls = new Set<string>();\n\n for (let at = 0; at < out.length; at++) {\n const message = out[at]!;\n let content: AgentMessage[\"content\"] | null = null;\n for (let index = 0; index < message.content.length; index++) {\n const part = message.content[index]!;\n if (part.type === \"tool-call\") calls.add(part.toolCallId);\n if (part.type !== \"tool-result\" || part.status !== \"running\") continue;\n\n const id = part.job?.id;\n let record = id ? known.get(id) : undefined;\n if (id && record === undefined) {\n const found = await store.get(id);\n record = found ? await current(found) : undefined;\n if (record) known.set(id, record);\n }\n if (record?.state === \"running\") continue;\n\n content ??= message.content.slice();\n content[index] = settledResult(part, record, params.outputSchemaFor);\n }\n if (content) {\n const changed: AgentMessage = { ...message, content };\n out[at] = changed;\n settled.push(changed);\n }\n }\n\n const orphans: AgentJobRecord[] = [];\n for (const record of recent) {\n if (record.orphaned || calls.has(record.toolCallId)) continue;\n if (await params.isRunLive(record.runId)) continue;\n orphans.push(record);\n }\n\n return { messages: out, settled, orphans, jobs: recent };\n}\n\n/** Marks orphans found by `overlayJobs`. Never throws: it is bookkeeping. */\nexport async function markOrphans(\n store: AgentJobStore,\n orphans: AgentJobRecord[],\n report: (error: unknown) => void,\n): Promise<void> {\n for (const record of orphans) {\n try {\n await store.transition(record.id, ANY_STATE, { orphaned: true });\n } catch (error) {\n report(error);\n }\n }\n}\n\nfunction settledResult(\n part: Extract<ToolResultPart, { status: \"running\" }>,\n record: AgentJobRecord | undefined,\n outputSchemaFor: ((toolName: string) => Schema<any> | undefined) | undefined,\n): ToolResultPart {\n const base = { type: \"tool-result\" as const, toolCallId: part.toolCallId, name: part.name };\n if (!record) {\n return {\n ...base,\n status: \"error\",\n job: part.job,\n error: {\n code: \"tool_error\",\n message: `The background job for \"${String(part.name)}\" can no longer be found, so its result was lost. It may have run in part or in full: check its effects before repeating it.`,\n toolCallId: part.toolCallId,\n retryable: true,\n },\n };\n }\n\n const job: AgentJobRef = {\n id: record.id,\n ...(record.summary !== undefined ? { summary: record.summary } : {}),\n ...(record.usage ? { usage: record.usage } : {}),\n };\n if (record.state === \"error\") {\n return {\n ...base,\n status: \"error\",\n job,\n error: record.error ?? {\n code: \"tool_error\",\n message: `The background job for \"${String(part.name)}\" failed.`,\n toolCallId: part.toolCallId,\n retryable: true,\n },\n };\n }\n\n const schema = outputSchemaFor?.(String(part.name));\n if (schema) {\n const parsed = schema.safeParse(record.output);\n if (parsed.ok === false) {\n return {\n ...base,\n status: \"error\",\n job,\n error: {\n code: \"invalid_tool_result\",\n message: `The background job for \"${String(part.name)}\" finished with an output that does not match the tool's output schema: ${parsed.errors.join(\", \")}`,\n toolCallId: part.toolCallId,\n retryable: true,\n },\n };\n }\n return { ...base, status: \"ok\", job, output: parsed.value };\n }\n return { ...base, status: \"ok\", job, output: record.output };\n}\n",
|
|
38
|
-
"import { Storage } from \"../facades/Storage\";\nimport { Controller } from \"../http/Controller\";\nimport { refusal, RequestBreakerError } from \"../http/Error\";\nimport { HttpRequest } from \"../http/HttpRequest\";\nimport { mediaType } from \"../http/mediaType\";\nimport { refusalKindForStatus } from \"../http/refusal\";\nimport type { MiddlewareInput } from \"../http/middlewareList\";\nimport type { AgentResource } from \"../http/ResourcePolicy\";\nimport type {\n AgentContext,\n AgentRun,\n AgentRunResult,\n AnyAgent,\n PrepareStepContext,\n PrepareStepResult,\n ToolShapesOf,\n} from \"./Agent\";\nimport type { ContextWindowOptions } from \"./contextWindow\";\nimport { isSummaryStore, type ThreadSummary } from \"./contextCompaction\";\nimport { injectedMessageIds } from \"./Agent\";\nimport {\n type Attachment,\n ATTACHMENT_ID_PREFIX,\n type AttachmentDestination,\n attachmentObjectName,\n type AttachmentScope,\n type AttachmentStorage,\n type AttachmentStore,\n defaultAttachmentStore,\n newAttachmentId,\n ScopedAttachments,\n} from \"./store/Attachments\";\nimport {\n FrameCursorEvictedError,\n liveRuns as defaultLiveRuns,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n} from \"./store/LiveRuns\";\nimport {\n defaultFileOwners,\n type FileOwnerRecord,\n type FileOwners,\n MemoryFileOwners,\n} from \"./store/FileOwners\";\nimport {\n defaultNonceStore,\n MemoryNonceStore,\n type NonceRedisClient,\n type NonceStore,\n RedisNonceStore,\n type RedisNonceStoreOptions,\n} from \"./store/Nonces\";\nimport {\n MemoryReceiptStore,\n type ReceiptClaim,\n type ReceiptRedisClient,\n type ReceiptStore,\n RedisReceiptStore,\n type RedisReceiptStoreOptions,\n} from \"./store/Receipts\";\nimport { defaultAgentStore, MemoryAgentStore } from \"./store/MemoryAgentStore\";\nimport { normalizeProviderError, ProviderHttpError } from \"./providers/errors\";\nimport { redactError, unredactedError } from \"./redact\";\nimport type { ErrorRedactionInfo } from \"./redact\";\nimport { sseResponse } from \"./store/sse\";\nimport { settleInterrupted, TurnJournal } from \"./store/TurnJournal\";\nimport { AgentJobs } from \"./jobs/AgentJob\";\nimport { markOrphans, overlayJobs } from \"./jobs/overlay\";\nimport { DEFAULT_JOBS_CONTEXT_MAX, renderJobsBlock } from \"./jobs/contextBlock\";\nimport type { AgentJobRecord } from \"./jobs/AgentJobStore\";\nimport type { Schema } from \"./Schema\";\nimport type {\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n ClientTurn,\n PendingToolCall,\n ToolShapes,\n} from \"./types\";\n\n// --- storage -------------------------------------------------------------\n\n/**\n * Where conversations live.\n *\n * Stateless is the default and nothing here is required to hold a conversation:\n * the client can carry its own history, and a pending approval travels in it\n * safely because the server signed it. What a store buys is a conversation that\n * survives the browser — and, with `/attach`, one whose interrupted turn is\n * still there after a refresh.\n */\nexport interface AgentStore {\n /**\n * Where a `threadId` comes from. `ApiRouter.agent()` mounts no route for\n * this: the app writes one, calls it here, and hands the id to `useChat` —\n * the mount is the app's because it is where ownership gets recorded, and a\n * store that holds no user cannot do that for it. An id that did not come out\n * of here is `null` from `loadThread` and a 404 from the controller, unless\n * the store's ids are the client's by design (`MemoryAgentStore`'s\n * `clientOwnedIds`).\n */\n createThread(params: { userId?: string | number }): Promise<{ threadId: string }>;\n /**\n * The history, or `null` for a thread the store does not have.\n *\n * `null` and `[]` are different answers and the controller acts on the\n * difference: an empty array is a conversation with nothing in it yet, and a\n * turn on it runs; `null` is a 404 before anything runs. A store that answers\n * `[]` for an id it has never seen turns an expired or mistyped thread into a\n * fresh conversation with no signal, and persists the next turn under the\n * dead id. Only a store whose ids are minted by the client should do that,\n * and then on purpose — see `MemoryAgentStore`'s `clientOwnedIds`.\n */\n loadThread(threadId: string): Promise<AgentMessage[] | null>;\n /**\n * Upsert by message id: replace a message the thread already holds, append\n * one it does not, and keep the order the thread had. Called with a thread\n * `loadThread` just found; must not create one.\n *\n * The name says append because that is what almost every call is, but a\n * turn that resolves a pending call reports the earlier assistant message\n * again — same id, now with the result attached — and a store that only\n * appends ends up with both versions. A table keyed by message id has the\n * lookup already but still needs an insert-or-update rather than a plain\n * insert, which would fail on the key; a store that is a list has to look\n * before it pushes.\n *\n * It is also called while a turn runs, not only when it ends (#617): with the\n * user's message as the run starts, with the assistant message in progress\n * (no `finishReason`, the run's id in `runId`) as it opens and at each tool\n * call and result, and with each message again once it is finished. The\n * same message arrives several times, and the last write is the one to\n * keep. Calls for one run never overlap: each waits for the one before.\n */\n appendMessages(threadId: string, messages: AgentMessage[]): Promise<void>;\n /**\n * Delete these messages from the thread; ids it does not hold are ignored.\n *\n * What a threaded `regenerate` needs (#451): the server owns the history,\n * so the answer being replaced has to leave the store, or the model reads\n * `user: X, assistant: A, user: X` and writes a follow-up instead of a new\n * answer. The controller calls it under the thread's lock with the last user\n * turn and everything after it, then runs that turn again.\n *\n * Optional so a store written before it still compiles; without it a turn\n * with `regenerate: true` on a thread is a 501 `regenerate_unsupported`.\n */\n removeMessages?(threadId: string, messageIds: string[]): Promise<void>;\n /**\n * Optional: where `contextWindow.compact` keeps the thread's summaries\n * (#782), so they live, and are deleted, with the thread. Implement both to\n * opt in; without them summaries go to `defaultSummaryStore`, in memory.\n * Same contract as `SummaryStore`.\n */\n loadSummaries?(threadId: string): Promise<ThreadSummary[]>;\n saveSummary?(threadId: string, summary: ThreadSummary): Promise<void>;\n /** Optional cross-process lock for one cut. See `SummaryStore.lockSummary`. */\n lockSummary?(\n threadId: string,\n cutMessageId: string,\n ttlMs: number,\n ): Promise<(() => Promise<void>) | null>;\n}\n\n/** The default: conversations last as long as the process. */\nexport { defaultAgentStore, MemoryAgentStore };\n\n/** The attachment half of the same story. See `store/Attachments.ts`. */\nexport {\n type Attachment,\n type AttachmentDestination,\n AttachmentNotFoundError,\n type AttachmentScope,\n type AttachmentStorage,\n type AttachmentStore,\n defaultAttachmentStore,\n InvalidAttachmentScopeError,\n MemoryAttachmentStore,\n type PutAttachmentParams,\n ScopedAttachments,\n type ToolAttachmentPut,\n type ToolAttachmentRecord,\n type ToolAttachments,\n} from \"./store/Attachments\";\n\n/**\n * The runs currently in flight, and their frames.\n *\n * A run outlives the request that started it, so something has to hold it while\n * no one is listening, and hold what it emitted meanwhile so a returning client\n * can catch up rather than start over. That is all this is: a per-process map\n * plus a bounded buffer.\n *\n * Per-process is not an implementation shortcut that a better store fixes — a\n * running generator lives in one process, and a second server cannot attach to\n * it. Reattachment therefore needs the request to land where the run is: one\n * server, sticky routing, or a proxy that forwards by `runId`. Worth saying out\n * loud, because the failure mode behind a round-robin load balancer is a\n * refresh that usually works.\n *\n * This is the read side, which is all `attach` and `stop` need. Registering a\n * run and replaying its buffer are on `MemoryLiveRuns`, the only implementation\n * there can be — see the note there for why a second one would not help.\n */\nexport interface LiveRuns {\n /** What the client asks after a refresh: is anything still going here? */\n find(params: { threadId: string }): Promise<{ runId: string; seq: number } | null>;\n get(runId: string): AgentRun | null;\n /** Kept for a short while after `run-end`, so a refresh a second late still\n * sees the tail instead of an empty screen. */\n ttlMs: number;\n}\n\nexport {\n FrameCursorEvictedError,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n defaultLiveRuns as liveRuns,\n};\n\n/** Who uploaded each provider file id (#443). See `store/FileOwners.ts`. */\nexport { defaultFileOwners, type FileOwnerRecord, type FileOwners, MemoryFileOwners };\n/** Where approved tools' executions are recorded (#458). See `store/Receipts.ts`. */\nexport {\n MemoryReceiptStore,\n type ReceiptClaim,\n type ReceiptRedisClient,\n type ReceiptStore,\n RedisReceiptStore,\n type RedisReceiptStoreOptions,\n};\n/** Where answered calls' nonces are spent (#445). See `store/Nonces.ts`. */\nexport {\n defaultNonceStore,\n MemoryNonceStore,\n type NonceRedisClient,\n type NonceStore,\n RedisNonceStore,\n type RedisNonceStoreOptions,\n};\n\n// --- controller ----------------------------------------------------------\n\nexport type AgentHookContext = {\n req: HttpRequest<any, any>;\n runId: string;\n threadId?: string;\n};\n\n/** What `AgentController.attachmentLimits` answers. Both optional. */\nexport type AttachmentLimits = {\n /** The largest file accepted, in bytes. */\n maxBytes?: number;\n /** `<input accept>` entries: `\".pdf\"`, `\"image/*\"`, `\"text/csv\"`. */\n accept?: string[];\n};\n\n/**\n * What `POST /<path>/files` answers.\n *\n * TWO IDS, AND THEY ARE NOT INTERCHANGEABLE. `fileId` is the *provider's* id and\n * means exactly what it always meant — the value a `FilePart` carries so the\n * model can see the file. `attachmentId` is *gemi's*, and is the handle a tool\n * resolves through `ScopedAttachments` to get the bytes back. A file can have\n * both, and usually does.\n *\n * `fileId` stays first and stays named that on purpose: `useChat.uploadFile`\n * already reads it, apps already put it in a `FilePart`, and renaming it or\n * folding the two into one id would break vision for every existing app while\n * looking like a tidier API. The two ids exist because there are two systems\n * holding the file.\n *\n * Both are optional, and `destination` says which to expect: `provider` has no\n * `attachmentId` (nothing was kept), `storage` has no `fileId` (the provider\n * never saw it, so there is nothing for a `FilePart` to point at), `both` has\n * both.\n *\n * `destination` ALONE IS NOT ENOUGH TO SAY WHY AN ID IS MISSING, which is why\n * `downgraded` is here. An upload that reached a route with no authentication\n * and no `threadId` answers `destination: \"provider\"` — truthfully, that is\n * where the bytes went — and so does a controller that deliberately returns\n * `\"provider\"` from `attachmentDestination`. Those two answers were byte\n * identical, and they are the opposite situations: one is the app's policy\n * working, the other is the app's policy silently not applying because the\n * server could not tell who was calling. The server logs the second one once\n * per process; the client saw nothing at all. `downgraded` is the difference,\n * carried in the answer so a client — or an integration test — can assert on\n * it.\n */\nexport type UploadResult = {\n /** The provider's id, for a `FilePart`. Absent when the file never went there. */\n fileId?: string;\n /** gemi's id, for a tool. Absent when nothing was kept — see `attachmentScope`. */\n attachmentId?: string;\n name: string;\n mimeType: string;\n size: number;\n destination: AttachmentDestination;\n /**\n * Set only when the app's policy asked for a copy and the request had no\n * subject to file it under, so the upload fell back to the provider alone.\n * Absent when `destination` is what the app actually chose.\n *\n * A string rather than `true` because there is exactly one reason today and\n * there will be more (a store that refused the write, say), and a boolean\n * that later needs a reason beside it is two fields where one would have\n * done.\n */\n downgraded?: \"no_scope\";\n};\n\n/**\n * `Controller.kind` is typed as the literal `\"controller\"`, so a subclass that\n * declares a `kind` of its own fails the static-side check (TS2417). Widening\n * it belongs in `http/Controller.ts`, which this slice does not own; erasing\n * the static side of the base here is the smaller change and costs nothing —\n * `Controller.kind` has no reader, in this package or out of it.\n */\nconst ControllerBase = Controller as new () => Controller;\n\n/**\n * The thread a `stream` is setting up on, to the setup ahead of it. Module\n * level because the controller is constructed per request, so nothing on it\n * can be seen by the next request; keyed by thread rather than held on\n * `liveRuns` because it guards the controller's protocol, not the frames. An\n * entry is removed once the last setup queued on it releases.\n */\nconst threadLocks = new Map<string, Promise<void>>();\n\n/**\n * Each run to the promise that its transcript has been stored. Weak, so a run\n * the map has evicted is not kept alive here for a promise nobody will ask for.\n */\nconst persisted = new WeakMap<AgentRun, Promise<void>>();\n\n/**\n * Turns read but not yet registered, by the client's name for them.\n *\n * A run can be stopped from `register` on, and named from `run-start` on. What\n * `/stop` could not reach was a turn still waiting its place on the thread —\n * which is where a user who sent twice and thought better of it presses stop,\n * and the wait is now as long as the old run's unwind. Falling through to\n * `threadId` there found the old run, already stopping, said `stopped: true`,\n * and the queued turn started anyway: unwatched, billing, and with no handle\n * left on the client that had let go of it. The entry is marked rather than\n * removed, because the turn itself is what answers once its wait is over.\n */\nconst pendingTurns = new Map<string, { cancelled: boolean; owner: string | null }>();\n\n// --- limits (#444) -------------------------------------------------------\n\n/** `AgentController.maxBodyBytes`'s default. */\nexport const DEFAULT_MAX_BODY_BYTES = 4 * 1024 * 1024;\n/** `AgentController.maxHistoryMessages`'s default. */\nexport const DEFAULT_MAX_HISTORY_MESSAGES = 1000;\n/** `AgentController.maxConcurrentRuns`'s default. */\nexport const DEFAULT_MAX_CONCURRENT_RUNS = 5;\n/** The cap on `attach` and `stop` bodies, which carry ids and nothing else. */\nconst SMALL_BODY_BYTES = 64 * 1024;\n\nconst noop = () => {};\n\n/**\n * The runs each `runLimitKey` has going, by lane: a thread is one lane however\n * many turns are queued or superseding on it, and a stateless turn is a lane\n * of its own. A lane is held from the moment its turn is admitted until its\n * last run ends.\n */\nclass RunSlots {\n private byKey = new Map<string, Map<string, number>>();\n\n /**\n * Admits a turn in `lane` for `key`, or answers `null` when `key` already\n * holds `limit` other lanes. Synchronous, so two turns arriving together\n * cannot both see the last free slot. The function it returns frees the\n * turn's hold; calling it twice is harmless.\n */\n take(key: string, lane: string, limit: number): (() => void) | null {\n let lanes = this.byKey.get(key);\n if (!lanes?.has(lane) && (lanes?.size ?? 0) >= limit) {\n return null;\n }\n if (!lanes) {\n lanes = new Map();\n this.byKey.set(key, lanes);\n }\n lanes.set(lane, (lanes.get(lane) ?? 0) + 1);\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = this.byKey.get(key);\n const count = (current?.get(lane) ?? 1) - 1;\n if (!current) return;\n if (count > 0) {\n current.set(lane, count);\n } else {\n current.delete(lane);\n if (current.size === 0) this.byKey.delete(key);\n }\n };\n }\n}\n\n/**\n * Slots are counted per `liveRuns` registry rather than per process: the\n * registry is what holds the runs being counted, and an app (or a test) with\n * two registries has two sets of runs.\n */\nconst runSlots = new WeakMap<object, RunSlots>();\nfunction runSlotsFor(liveRuns: object): RunSlots {\n let slots = runSlots.get(liveRuns);\n if (!slots) {\n slots = new RunSlots();\n runSlots.set(liveRuns, slots);\n }\n return slots;\n}\n\n/**\n * The key that carries `Body` on the instance type.\n *\n * A `declare const` unique symbol, so it exists only in the type layer — the\n * same device `Schema.ts` uses for its output type, and for the same reason: a\n * real property would be one an app could see, serialise or depend on.\n */\ndeclare const BODY: unique symbol;\n\n/**\n * What `authorizeRequest` is told about the request, per route.\n *\n * A union on `route` because `body` exists on only two of them: `stream` and\n * `upload` carry the client's `body` option, `attach` and `stop` carry none.\n * Typing it optional everywhere would make every reader of `body.pageId` on\n * `stream` write a check for a case that cannot happen there; narrowing on\n * `route` says which case it is. An override written against the older\n * `{ route; threadId? }` shape still accepts every member.\n */\nexport type AuthorizeRequestParams<Body extends object = Record<string, unknown>> =\n | { route: \"stream\" | \"upload\"; threadId?: string; body: Body }\n | { route: \"attach\" | \"stop\"; threadId?: string; body?: undefined };\n\nexport abstract class AgentController<\n A extends AnyAgent = AnyAgent,\n /**\n * The extra fields `useChat`'s `body` option sends with every turn, as they\n * arrive in `instructions()` and on `ctx.body`.\n *\n * Declaring it also types the client: `useChat` reads it back off the route\n * through `AgentRouteRPC`, so a `body` the controller does not expect is a\n * compile error at the call site rather than an `undefined` three layers\n * into a tool. It types the shape, not the contents — see `instructions`.\n *\n * Constrained to `object`, not `Record<string, unknown>`: an `interface` gets\n * no implicit index signature, so the tighter bound refused\n * `interface PageBody { pageId: string }` with a `TS2344` that names the\n * constraint and not the reason. An interface is how most apps write a request\n * shape, and turning that into a puzzle about `type` versus `interface` is a\n * poor first impression of the feature.\n */\n Body extends object = Record<string, unknown>,\n> extends ControllerBase {\n static kind = \"agent-controller\" as const;\n\n /**\n * `Body`, in a position nothing can shorten away.\n *\n * It has to appear on the instance type for `AgentRouteRPC` to infer it, and\n * `instructions`'s second parameter is not a safe place to leave that job:\n * TypeScript's parameter-wise inference stops at the shorter signature, so a\n * controller overriding `instructions(req)` — which is every override written\n * before this existed, since that was the only signature — supplied no\n * candidate and silently fell back to the open record. The client-side\n * checking then vanished on the most ordinary upgrade path, with nothing to\n * read.\n *\n * `declare` so it emits no field: there is no value here, only a type for\n * `infer B` to find. Optional and never assigned, so no subclass has to\n * mention it.\n */\n declare readonly [BODY]?: Body;\n\n /** The agent this controller serves. A property rather than a constructor\n * argument so `Router.agent(ChatController)` can take the class, matching how\n * every other controller is mounted. */\n abstract agent: A;\n\n /**\n * Defaults to the process-wide `MemoryAgentStore`.\n *\n * Whatever you put here, make it something that outlives the request: this\n * controller is constructed fresh for every call, so `store = new\n * MemoryAgentStore()` written here is an empty store on every turn and a\n * threaded conversation silently reads back nothing. Assign a module-level\n * instance, or a store whose state is somewhere else entirely.\n */\n store: AgentStore = defaultAgentStore;\n\n /**\n * Defaults to the process-wide map. Overridable so a test — or an app running\n * two agents that must not see each other's runs — can hold its own; not so\n * that it can be moved off the process, which is not a thing that can be\n * done. See `MemoryLiveRuns`.\n */\n liveRuns: MemoryLiveRuns = defaultLiveRuns;\n\n /**\n * Where attachment *records* live — the row that says which bytes, whose, and\n * under what id. Defaults to the process-wide `MemoryAttachmentStore`, with\n * the same warning `store` carries: assign something that outlives the\n * request, because this controller is constructed per call.\n */\n attachments: AttachmentStore = defaultAttachmentStore;\n\n /**\n * Where an attachment's *bytes* live. Defaults to the app's configured\n * `FileStorage` through the `Storage` facade, which resolves the driver per\n * call out of the container — so an app that configured S3 gets S3 here\n * without saying so twice.\n *\n * Overridable mostly for tests and for an app that keeps user uploads in a\n * different bucket from everything else.\n */\n attachmentStorage: AttachmentStorage = Storage;\n\n /**\n * Who uploaded each provider file id (#443). `upload` records the id under\n * `runOwner(req)`, and `stream` refuses a turn whose files name an id\n * recorded for another owner with a 403 `{ error: { kind: \"permission\",\n * message, status } }`. Defaults to the process-wide `MemoryFileOwners`; the\n * same warning as `store` applies — assign something that outlives the\n * request. An app with several processes, or that wants the binding to\n * survive a restart, gives it a table (see `FileOwners`).\n */\n fileOwners: FileOwners = defaultFileOwners;\n\n /**\n * Where the nonce of each answered approval or question is spent, which is\n * what makes a signed answer single-use (#445). On a stateless chat the\n * client carries its history and can rewind it to before a result existed;\n * the spent nonce is then the only thing that refuses the replayed answer.\n *\n * Defaults to the process-wide `MemoryNonceStore`, which is exact for one\n * instance and forgets on restart. An app running several instances (or\n * behind a load balancer whose affinity is best effort) assigns a shared\n * store, built once at module scope like `store`:\n *\n * const nonces = new RedisNonceStore();\n * class ChatController extends AgentController<typeof chat> {\n * nonces = nonces;\n * }\n *\n * or its own `NonceStore` over a table keyed by the nonce. In production a\n * stateless turn served with the in-memory default logs a warning once.\n */\n nonces: NonceStore = defaultNonceStore;\n\n /**\n * Where approved tools' executions are claimed and their results recorded,\n * so that an approval runs its tool at most once (#458). Off by default.\n *\n * The nonce makes an answer single-use; it does not remember what the tool\n * did. So a retried submit whose response was lost is refused (\"already\n * used\") although the tool acted, and an answer that reaches two instances\n * with unshared nonce stores runs the tool twice. With a receipt store the\n * first presentation claims the execution and records its result; a later\n * one gets that result back without running anything, and one that arrives\n * while the first is still running gets a `tool_error` result for the model.\n *\n * Assign one built at module scope, like `nonces`, shared by every instance:\n *\n * const receipts = new RedisReceiptStore();\n * class ChatController extends AgentController<typeof chat> {\n * receipts = receipts;\n * }\n *\n * or your own `ReceiptStore` over a table (see `store/Receipts.ts`).\n * `MemoryReceiptStore` is exact for one instance only.\n */\n receipts?: ReceiptStore;\n\n /**\n * Whether a turn may name a provider file id that `fileOwners` has no record\n * of. `false` by default, which is what keeps the change additive: an id\n * uploaded before the upgrade, before a restart (with the in-memory default),\n * on another process, or by the app outside `upload` still works, as every id\n * did before. An id that IS recorded for someone else is refused either way.\n *\n * Set it to `true` once `fileOwners` is durable and shared, to make the\n * binding complete: then an id is usable only by the owner it was recorded\n * for, or by anyone when it was recorded as anonymous. On a stateless chat\n * the client carries its history, so this also refuses a file a tool attached\n * earlier in the conversation; a strict app keeps its chats on a thread.\n */\n protected requireKnownFiles = false;\n\n /**\n * How long the request that started a run is held open for its hooks, in\n * milliseconds, once the run has settled. The run itself is not bounded\n * here — the request is held for as long as it runs — only the app's code\n * still going after it, from `onMessage` to an `onAwaitingInput` queued\n * behind a slow `onToolCall`.\n *\n * The hooks read the user from that request (`ctx.req.ctx().user`,\n * `Auth.user()`, a policied query), so the request stays open until they are\n * done; but a hook that never settles — a `fetch` with no timeout — would\n * then hold the store, the user and `onRequestEnd` forever, one per turn. Past\n * this the request ends anyway: `onRequestEnd` runs, the user is released,\n * and the hook runs on without one. Thirty seconds is far past a healthy\n * write or notification, so a hook that reaches it is hung rather than slow.\n * Raise it for a hook that is legitimately longer; `Infinity` holds the\n * request until the hooks are done, however long that is.\n */\n protected hookHoldMs = 30_000;\n\n /**\n * Appended to the agent's static instructions for this request — the user's\n * name, tenant, today's date.\n *\n * `body` is what `useChat`'s `body` option sent, with the four keys the wire\n * format owns removed. It is the only way to read it here: this controller\n * consumes the request body itself, so `await req.input()` answers `Body\n * already used` and takes the whole turn down with it.\n *\n * It is client-controlled, exactly like any request body. `Body` types what\n * arrives, it does not check it — a client can send anything, and a tenant id\n * read from here is the client's claim about which tenant it wants, not the\n * middleware's finding about who it is.\n */\n instructions(req: HttpRequest<any, any>, extra: { body: Body }): string | Promise<string> | void {\n void req;\n void extra;\n }\n\n /**\n * What every tool of this turn's run gets as `ctx.context` — the user, the\n * tenant, functions the tools call back into. See `AgentContext`.\n *\n * The run is not given the request, so this is where the request's facts\n * become the run's: read the user the middleware authenticated here, and a\n * tool reads it from `ctx.context` instead of reaching for `req`. Runs after\n * `authorizeRequest()`, once per turn, and before anything is asked of the\n * model.\n *\n * The default is `{}`. An app that gives `AgentContext` a required field must\n * override this: the type of the default cannot see the app's declaration,\n * so forgetting is a tool that finds the field missing, not a compile error.\n *\n * Values from `body` are the client's claim, exactly as in `instructions()`;\n * putting one here does not make it any more trustworthy, only easier to\n * mistake for something the server decided.\n */\n context(req: HttpRequest<any, any>, extra: { body: Body }): AgentContext | Promise<AgentContext> {\n void req;\n void extra;\n return {} as AgentContext;\n }\n\n /**\n * Refuse a turn that arrives without a `threadId`, with a 400\n * `thread_required`, before anything runs.\n *\n * A stateless turn is otherwise open to any caller the route's middleware\n * lets through: the client carries the history, so the model runs, and is\n * billed, as a general-purpose chat. An app whose tools resolve their subject\n * from the thread can make them refuse such a turn, but the model has still\n * been paid for by then.\n *\n * It governs `stream` only. `upload` can still reach the provider without a\n * thread (a `provider` destination); refuse that in `authorizeRequest`.\n */\n protected requireThread = false;\n\n /**\n * The largest JSON body `stream` reads, in bytes (#444). Default 4 MB.\n *\n * A turn is a few kilobytes; even a long stateless chat carrying its whole\n * history is well under a megabyte, since files travel by id and not inline.\n * Without a cap the route read whatever arrived (the production server\n * accepts up to 10 GB), parsed it, and sent it to the provider at the app's\n * expense. A body over it is refused with a 413 `{ error: { kind, message,\n * status, code: \"body_too_large\" } }` before it is parsed, and before\n * `authorizeRequest`. Checked against `Content-Length` when there is one and\n * against the bytes read otherwise, so a chunked body cannot get past it.\n * `attach` and `stop` carry only ids and are held to 64 KB. `Infinity` turns\n * it off.\n */\n protected maxBodyBytes = DEFAULT_MAX_BODY_BYTES;\n\n /**\n * The most messages a stateless turn's client-carried history may hold\n * (#444). Default 1000. A longer one is a 413 `history_too_long` before\n * anything runs. Only `body.messages` counts: a threaded turn reads its\n * history from the store, which the client does not write. Every message is\n * sent to the model on every step, so this bounds what one turn can be billed\n * for as much as `maxBodyBytes` does. `Infinity` turns it off.\n */\n protected maxHistoryMessages = DEFAULT_MAX_HISTORY_MESSAGES;\n\n /**\n * Bounds what each model call of this controller's turns is sent (#473):\n * the latest turns of the thread that fit, cut at a turn start, the cut\n * moving `step` turns at a time so the prompt cache keeps hitting. See\n * `ContextWindowOptions`. `undefined` (the default) uses the agent's own\n * `contextWindow`, if it has one; `false` sends the whole history.\n *\n * The store is untouched: `loadThread` still answers the whole thread, every\n * message is still appended, and `readThread` shows all of it. Unlike\n * `maxHistoryMessages`, which refuses a stateless turn, this applies to\n * threaded and stateless turns alike and refuses nothing.\n *\n * protected contextWindow = { maxTurns: 40, maxTokens: 100_000 };\n */\n protected contextWindow: ContextWindowOptions | false | undefined = undefined;\n\n /**\n * Called before every model call of a turn's run, after the agent's own\n * `prepareStep`, with the request it hands over (`step.messages`,\n * `step.instructions`) and the turn's hook context. Answer `{ messages }`\n * or `{ instructions }` to send something else for that call alone; nothing\n * answered is stored. Not called for a sub-agent's model calls.\n *\n * protected prepareStep(step: PrepareStepContext) {\n * return { messages: windowMessages(step.history, { maxTurns: 20 }).messages };\n * }\n */\n protected prepareStep(\n step: PrepareStepContext,\n ctx: AgentHookContext,\n ): PrepareStepResult | void | Promise<PrepareStepResult | void> {\n void step;\n void ctx;\n }\n\n /**\n * How many runs one caller may have going at once in this process (#444).\n * Default 5. A run outlives the request that started it (so `attach` can\n * find it), which means a client can post a turn and disconnect and the run\n * still bills up to `maxSteps` model calls; without a cap, a thousand posts\n * were a thousand runs.\n *\n * Counted per `runLimitKey` (by default `runOwner`, the authenticated user),\n * and per conversation rather than per request: every turn on one thread is\n * one slot, because a thread holds one run at a time and a new turn there\n * supersedes the old one rather than adding to it. So a user resending\n * mid-answer is never refused; a user with five chats answering at once and\n * starting a sixth is, with a 429 `{ error: { kind: \"rate_limit\", message,\n * status, code: \"too_many_runs\" } }`, after `authorizeRequest` and before the\n * model is asked anything. A slot is freed when the run ends (stopped, timed\n * out, or finished). `Infinity` turns it off.\n */\n protected maxConcurrentRuns = DEFAULT_MAX_CONCURRENT_RUNS;\n\n /**\n * Who `maxConcurrentRuns` counts a turn against (#444). The default is\n * `runOwner`'s answer, the authenticated user; `null` is not counted.\n *\n * An anonymous turn is therefore not limited by default, because there is\n * nothing sound to count it under: a client address is the proxy's unless\n * `GEMI_TRUST_PROXY` is set, which would put every visitor in one bucket, and\n * the session cookie is the visitor's to drop. An app that serves anonymous\n * chats returns its own key here (`ip:${clientIp(req)}` behind a trusted\n * proxy, say), sets `requireThread`, or puts `RateLimitMiddleware` on the\n * route.\n */\n protected runLimitKey(\n req: HttpRequest<any, any>,\n params: { owner: string | null; threadId?: string },\n ): string | null | Promise<string | null> {\n void req;\n return params.owner;\n }\n\n /**\n * Decides whether this caller may use this route, on every one of the four:\n * `stream`, `attach`, `stop` and `upload` (#542). Throw a request breaker\n * (`InsufficientPermissionsError`, say) to refuse; return to let it through.\n *\n * It runs before the route does any work of its own: on `stream`, ahead of\n * the thread's lock and load, `instructions()` and the provider, so a refused\n * turn is not charged for, waits behind no run and does not learn whether its\n * thread exists; on `attach`, before a live run's frames are read.\n *\n * `threadId` is the one the client sent, taken on trust and not yet checked\n * against the store — which is what makes this the place to check that the\n * caller owns it. A thread-scoped app that checks it here on every route\n * keeps a thread's live answer, its stop button and its attachments to its\n * owner. It is `undefined` when the request names no thread: a stateless\n * turn, an upload without one, a stop by `runId` or `clientRunId`.\n *\n * `body` is the client's `body` option — the same object `instructions()`,\n * `context()` and `attachmentScope()` get — on the two routes that carry it,\n * `stream` and `upload` (#603). A chat with no thread and no user names its\n * subject there (a page id, say), and this is where to check that the caller\n * may touch it. `attach` and `stop` carry no body, so it is absent on them;\n * narrow on `route` to read it. Like `threadId` it is the client's claim,\n * unchecked.\n *\n * THE DEFAULT CHECKS `resource`, when there is one, and lets everything\n * through otherwise. An override that also wants it calls\n * `super.authorizeRequest(req, params)`.\n */\n protected authorizeRequest(\n req: HttpRequest<any, any>,\n params: AuthorizeRequestParams<Body>,\n ): void | Promise<void> {\n return this.resource?.authorize(req, params);\n }\n\n /**\n * THE RESOURCE THIS CHAT IS ABOUT, checked on every route by the default\n * `authorizeRequest` (#726): a resource policy's `forAgent`, which names the\n * resource's id in the `body` and the resource a thread belongs to.\n *\n * ```ts\n * resource = PagePolicy.forAgent({\n * body: (body: PageBody) => body.pageId,\n * thread: (threadId) => ChatThread.pageIdOf(threadId),\n * });\n * ```\n *\n * `stream` and `upload` are refused unless the caller may use the resource\n * the body names, and, when they name a thread, unless it is that\n * resource's. `attach` and `stop` are refused unless the caller may use the\n * thread's resource. A refusal is the policy's (a 404 by default), the same\n * for a resource or thread that does not exist. A live run still answers\n * only its `runOwner`.\n */\n protected resource?: AgentResource<Body>;\n\n /**\n * WHO OWNS A RUN THIS REQUEST STARTS, and who a request to `attach` or `stop`\n * one is (#442). An opaque key, compared with `===`; `null` is nobody.\n *\n * `stream` records it on the run, and from then on the run answers only that\n * key: `attach` to it, `stop` of it (by `runId`, `threadId` or `clientRunId`,\n * including a turn still waiting its place), and a turn on its thread that\n * would supersede it while it is still going are each refused with a 403\n * `{ error: { kind: \"permission\", message, status } }` for any other caller.\n * That holds whatever `authorizeRequest` says, which is the point: every\n * handle on a run is one a third party can come to hold (a shared link, a\n * log line, a guessable `clientRunId`), and none of them says whose it is.\n *\n * THE DEFAULT IS THE AUTHENTICATED USER, `user:<id>`, and `null` without one.\n * A `null` owner records an unowned run, which answers whoever holds a\n * handle — exactly what every run did before this existed. So:\n *\n * - an anonymous turn starts an unowned run; its `threadId` stays the\n * capability. `sessionId()` is not used as a fallback: it is a cookie the\n * visitor writes, it can be minted between the turn and the reattach (a\n * view visited in between), and a mismatch would lock a visitor out of\n * their own run. An app with its own anonymous identity returns it here.\n * - a run started by an authenticated user cannot be read or stopped by an\n * anonymous request, nor by another user.\n * - a run the server starts itself (registered on `liveRuns` with no\n * `owner`) is unowned.\n *\n * Override it for anything wider than a user — a thread shared by a team\n * returns `team:<id>` (from the user, never from the body) — or `null` to\n * turn the check off. Whatever it reads must be present on all of `stream`,\n * `attach` and `stop`, the same rule `attachmentScope` states: guard the three\n * routes with the same middleware.\n *\n * It is also the `subject` every pending call of the run is signed for\n * (#447): an approval or answer is accepted only on a turn whose `runOwner`\n * is the one the question was asked of. So it must answer the same on the\n * turn that asks and the turn that answers.\n */\n protected runOwner(req: HttpRequest<any, any>): string | null | Promise<string | null> {\n const user = req.ctx?.()?.user;\n const userId = user?.id ?? user?.publicId;\n if (userId !== undefined && userId !== null && String(userId) !== \"\") {\n return `user:${String(userId)}`;\n }\n return null;\n }\n\n /**\n * `POST /<path>` — one route for every client turn. A first message, an\n * approval, an answer to a question and a client tool's result are all just\n * the next turn, so none of them gets an endpoint of its own.\n */\n async stream(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req, this.maxBodyBytes);\n if (parsed.error) {\n // Before anything is registered or charged for. A run started off a body\n // we could not read would answer nothing, at the user's expense.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId = typeof body.threadId === \"string\" ? body.threadId : undefined;\n const parsedTurn = toClientTurn(body);\n if (parsedTurn.error) {\n return invalidRequest({ body: {}, error: parsedTurn.error });\n }\n // Reassigned by a regenerate: the turn run again is the one the store holds.\n let turn = parsedTurn.turn;\n // Replace the thread's last answer rather than answer after it (#451). Only\n // meaningful on a thread: a stateless client trims its own history.\n const regenerate = threadId !== undefined && body.regenerate === true;\n const clientRunId = typeof body.clientRunId === \"string\" ? body.clientRunId : undefined;\n // The app's fields, separated once and handed to every method that reads\n // them — `authorizeRequest`, `instructions`, `context`, `attachmentScope` —\n // so none of them can disagree about what the client sent. They cannot read\n // it themselves: `readJsonBody` has consumed the request's body by now.\n const extraBody = appBody<Body>(body);\n\n // Before `pendingTurns`, so a refused turn leaves nothing for `/stop` to\n // find. It does not yield, unlike `authorizeRequest` below.\n if (this.requireThread && !threadId) {\n return jsonResponse(400, {\n code: \"thread_required\",\n message: \"This agent takes a turn only on a thread: send a threadId.\",\n });\n }\n\n if (regenerate && !this.store.removeMessages) {\n return jsonResponse(501, {\n code: \"regenerate_unsupported\",\n message:\n \"This agent's store cannot remove messages, so a thread's answer cannot be regenerated. Implement `removeMessages` on the AgentStore.\",\n });\n }\n\n // The client's history is the only part of a stateless turn whose size the\n // client chooses and the model is billed for on every step (#444). A\n // threaded turn's `messages` are ignored, so they are not counted.\n if (\n !threadId &&\n Array.isArray(body.messages) &&\n body.messages.length > this.maxHistoryMessages\n ) {\n return limitResponse(\n 413,\n \"history_too_long\",\n `The conversation has ${body.messages.length} messages; this agent takes at most ${this.maxHistoryMessages}.`,\n );\n }\n\n // Who this run will belong to. Read before `pending` exists, so a stop that\n // finds the pending turn can already be checked against it. See `runOwner`.\n const owner = await this.runOwner(req);\n\n // From here until `register`, the only thing `/stop` can find this turn by.\n // See `pendingTurns`.\n const pending = clientRunId ? { cancelled: false, owner } : null;\n if (pending) {\n pendingTurns.set(clientRunId, pending);\n }\n\n // The whole of the stateless/threaded difference, in one expression: with a\n // thread the server owns the history, without one the client carries it.\n // Nothing else below branches on it, which is why stateless keeps working\n // even for an app that never configures a store.\n //\n // The `threadId` is the client's, and nothing here checks that this caller\n // owns it — `AgentStore` cannot, since it holds no user. A `threadId` is\n // therefore a capability and has to be unguessable (`createThread` mints a\n // uuid) and, for anything that matters, checked: override `authorizeRequest()`\n // or give it a `store` that scopes by `req.user`. The framework's job is to make\n // sure the route is behind the router's middleware in the first place,\n // which `ApiRouter.agent()` now does.\n //\n // Everything from the load on happens inside `start`, which on a thread\n // runs under the thread's lock once the previous run's transcript is in the\n // store — the load has to come after that, or it reads a history the old\n // answer is missing from. `instructions()` follows the load in there rather\n // than running ahead of the lock, so that a dead thread is still a 404\n // before the app's own work is spent on it; the cost is that a turn queued\n // behind this one waits for `instructions()` as well.\n // The run `start` registered, if it got that far: its end is what frees\n // this turn's `maxConcurrentRuns` slot.\n let started: AgentRun | null = null;\n // What a regenerate took out of the thread, kept until the run replacing\n // it has started.\n let removed: AgentMessage[] = [];\n const start = async (): Promise<Response> => {\n try {\n return await startRun();\n } finally {\n // A regenerate that never started its run — stopped while it waited,\n // or a throw from the app's hooks — puts back what it took out, since\n // no new answer is coming to replace it. Still under the thread's lock,\n // and appended at the end, which is where it was: it was the tail.\n if (threadId && removed.length > 0 && (started as AgentRun | null) === null) {\n await this.store\n .appendMessages(threadId, removed)\n .catch((err) => this.reportHookFailure(err));\n }\n }\n };\n const startRun = async (): Promise<Response> => {\n let messages: AgentMessage[];\n // The `<jobs>` block for this turn's system prompt (#461), on a thread\n // that has background jobs.\n let jobsBlock: string | null = null;\n if (threadId) {\n const history = await this.store.loadThread(threadId);\n if (!history) {\n // Before `instructions()` and before the run: nothing has been\n // charged for, and the client has to learn that its thread is gone —\n // expired, mistyped, or on an instance that no longer exists — rather\n // than see it answered as an empty conversation and have this turn\n // persisted under the dead id.\n //\n // That ordering is deliberate. An ownership check belongs in\n // `authorizeRequest()`, which has already run; one left in\n // `instructions()` has not, so a caller holding a uuid learns whether\n // it is live here without the app's say. The id is unguessable, so\n // the load stays above `instructions()`, whose own work (a database\n // read, typically) would otherwise be spent on a thread that is gone.\n // Move it below and that work is spent on every dead id instead.\n return jsonResponse(404, {\n code: \"thread_not_found\",\n message: `Thread ${threadId} does not exist here, or has expired.`,\n });\n }\n // A message a dead run left unfinished is closed here, and written\n // back, before the run is handed the history: the model then reads it\n // as interrupted, and its open calls have results. Under the thread's\n // lock and after the previous run's transcript is stored, so the only\n // unfinished message left is one no run in this process owns.\n const thread = await this.settleThread(threadId, history, { write: true });\n messages = thread.messages;\n jobsBlock = this.jobsBlock(thread.jobs);\n if (regenerate) {\n const cut = regenerationCut(messages);\n if (!cut) {\n return jsonResponse(409, {\n code: \"nothing_to_regenerate\",\n message: `Thread ${threadId} has no user turn to answer again.`,\n });\n }\n // The last user turn and everything after it leave the store, and the\n // turn is run again from what the store held — not from the client's\n // copy, which may be stale or carry local ids. The user message comes\n // back under a new id when the run reports it. Under the thread's\n // lock and after the previous run's transcript is stored, so nothing\n // writes the removed answer back. Each removed message takes its\n // `usage` with it: the thread never holds both answers' costs.\n removed = messages.slice(cut.index);\n await this.store.removeMessages!(\n threadId,\n removed.map((message) => message.id),\n );\n messages = messages.slice(0, cut.index);\n // The stored turn, under the client's `localId` for it: the message\n // is minted again, and the client has to be told the new id (#466).\n turn = turn?.localId ? { ...cut.turn, localId: turn.localId } : cut.turn;\n }\n } else {\n messages = Array.isArray(body.messages) ? (body.messages as AgentMessage[]) : [];\n warnInMemoryNonces(this.nonces);\n }\n\n const instructions =\n [(await this.instructions(req, { body: extraBody })) || undefined, jobsBlock ?? undefined]\n .filter(Boolean)\n .join(\"\\n\\n\") || undefined;\n const context = await this.context(req, { body: extraBody });\n // Above the cancel check, not below it, and that placement is the whole\n // reason this is a separate statement rather than an argument on the call\n // below: the comment on that check says nothing yields between it and\n // `register`, and an `await` for the app's `attachmentScope()` — a\n // database read, in any app that has one — is exactly the yield a stop\n // would land in and be missed.\n const attachments = await this.attachmentsFor(req, threadId, { body: extraBody });\n\n if (pending?.cancelled) {\n // Stopped while it waited. Nothing has been asked of the model and\n // nothing registered, so there is no run to end and nothing charged\n // for. Checked after the last `await` above, so that a stop landing\n // during it is not missed: from here to `register` nothing yields.\n return stoppedBeforeStart();\n }\n\n // Only a threaded turn has anywhere to be written as it runs. See\n // `TurnJournal`.\n const journal = threadId\n ? new TurnJournal(this.store, threadId, messages, (err) => this.reportHookFailure(err))\n : null;\n\n // Chosen here rather than by the run, so the hook context exists before\n // the run does: `redactError` below is handed it, and the run may call\n // it for its first frame.\n const runId = `run_${crypto.randomUUID()}`;\n const ctx: AgentHookContext = { req, runId, threadId };\n\n // The app's `onMessage` for the turn's user message, called while the\n // run goes rather than after it (#806). See `EarlyTurn`.\n const early: EarlyTurn = { id: null, notified: Promise.resolve() };\n\n const run = this.agent.stream({\n runId,\n messages,\n turn,\n threadId,\n // The run reports each message as it finishes it, the user's turn\n // first and before the model is asked anything. Only the store hears\n // about most of them here: the app's `onMessage` runs after the run,\n // in `notifyRun`, except for the turn's own message (below).\n ...(journal ? { onMessage: (message: AgentMessage) => journal.finish(message) } : {}),\n // The turn's user message, once the journal has written it: the app's\n // `onMessage` for it is called now, so whatever the app keeps beside\n // a stored message (where it was sent from, say) is there for a read\n // of the thread while the run is still going (#806). Off the run's\n // path, as the journal is: neither the store nor the hook holds up\n // the model. `notifyRun` waits for it and does not call it again.\n onTurn: (message: AgentMessage) => {\n if (early.id !== null) return;\n early.id = message.id;\n const written = journal ? journal.settled() : Promise.resolve();\n early.notified = written.then(() => this.safely(() => this.onMessage(message, ctx)));\n },\n instructions,\n // Built from this request once, here, and the only thing the run knows\n // about who asked. The run has no request of its own — see\n // `AgentContext` — so a tool that needs the user reads it from this.\n context,\n // Resolved once, above, and handed to every tool of the run as\n // `ctx.attachments`. It is derived from the request — the user the\n // middleware authenticated, or the thread — and never from anything the\n // model can write, which is the property that makes an attachment id\n // safe to give a model at all. `null` for a request with no subject:\n // tools still get an object, and it throws with a sentence naming\n // `attachmentScope()`.\n attachments,\n // The same object `instructions()` was handed, so the two cannot\n // disagree about what the client sent — and carried on the run\n // because a run outlives the request that started it. By the time a\n // tool executes, the body is long gone.\n // Cast because `Body` is constrained to `object` so an `interface` can be\n // used, and an interface has no index signature to satisfy\n // `Record<string, unknown>`. The value is a parsed JSON object either\n // way; the constraint is about what an app may declare, not about what\n // arrives.\n body: extraBody as Record<string, unknown>,\n // What the client, and for a tool's exception the model, is told about\n // a failure. See `redactError`.\n redactError: (error, info) => this.redactError(error, info, ctx),\n // Where answers' nonces are spent. See `nonces`.\n nonces: this.nonces,\n // Where approved tools' executions are recorded. See `receipts`.\n receipts: this.receipts,\n // The principal its pending calls are bound to (#447): an answer is\n // only accepted from the same `runOwner` the question was asked of.\n subject: owner,\n // Background jobs (#461) settle into the thread, so only a threaded\n // turn can start one. The job records who started it.\n ...(threadId ? { jobs: { owner } } : {}),\n // What each model call is sent (#473). Only the request: the store\n // still gets every message through `journal` above.\n ...(this.contextWindow !== undefined ? { contextWindow: this.contextWindow } : {}),\n // Where `contextWindow.compact` keeps this thread's summaries, when\n // the store holds them (#782).\n ...(threadId && isSummaryStore(this.store) ? { summaryStore: this.store } : {}),\n // Only when overridden, so a controller without one adds no call.\n ...(this.prepareStep !== AgentController.prototype.prepareStep\n ? { prepareStep: (step: PrepareStepContext) => this.prepareStep(step, ctx) }\n : {}),\n }) as AgentRun;\n\n // Registered before the response is built: the run is now owned by the\n // process rather than by this request, which is the property `/attach`\n // depends on and the reason a dropped connection no longer cancels\n // anything.\n const eventHooks = this.liveRuns.register(run, {\n threadId,\n // Who may attach to it and stop it from now on. See `runOwner`.\n owner,\n // The client's handle on a run it started, which is the only one that\n // exists before `run-start` reaches it. See `RegisterParams`.\n clientRunId,\n onEvent: (event) => this.dispatchEvent(event, ctx),\n onInternalError: (err) => this.reportHookFailure(err),\n // So the registry's age ceiling never cuts short a run its agent\n // allowed to be longer. See `MemoryLiveRuns.maxAgeMs`.\n maxRunDurationMs: this.agent.maxRunDurationMs,\n });\n\n started = run;\n if (journal) this.follow(run, journal);\n\n // Kept, not just fired: the next turn on this thread has to know when\n // this one's transcript is in the store. See `withThread`. The request\n // waits for more than the thread does — the hooks as well — so that\n // `onMessage` still finds the user who sent the message; the thread\n // waits only for the store, so a slow hook is not a slow next turn.\n const { stored, hooks } = this.persistRun(run, ctx, eventHooks, journal, early);\n persisted.set(run, stored);\n // Registered now, while the request is certainly open: `waitUntil` is\n // ignored once it has ended, and the run settling can end it before a\n // single hook has been called.\n req.ctx?.()?.waitUntil(hooks);\n\n return run.toResponse();\n };\n\n try {\n // After `pending` is registered, not before: the app's check is a yield —\n // a database read, typically — and a stop pressed during it has to find\n // this turn. Before the thread's lock, which ends the thread's previous\n // run, so a refused or stopped turn does not end it either.\n await this.authorizeRequest(req, { route: \"stream\", threadId, body: extraBody });\n // After the app's check, so a caller it refuses does not learn which ids\n // are someone's; before the thread's lock, so a refused turn supersedes\n // nothing. The client's history only counts without a thread: with one,\n // `body.messages` is ignored and the history comes from the store.\n const foreign = await this.foreignFile(\n [...(turn?.files ?? []), ...(threadId ? [] : clientHistoryFiles(body.messages))],\n owner,\n );\n if (foreign) {\n return foreign;\n }\n if (pending?.cancelled) {\n return stoppedBeforeStart();\n }\n // After the app's check, so a refused caller spends no slot; before the\n // thread's lock, so a turn over the limit waits behind nothing. No yield\n // between the count and the take: see `RunSlots.take`.\n const limitKey = await this.runLimitKey(req, { owner, threadId });\n const release =\n limitKey === null\n ? noop\n : runSlotsFor(this.liveRuns).take(\n limitKey,\n threadId ? `thread:${threadId}` : `run:${crypto.randomUUID()}`,\n this.maxConcurrentRuns,\n );\n if (!release) {\n return limitResponse(\n 429,\n \"too_many_runs\",\n `You already have ${this.maxConcurrentRuns} conversations answering. Wait for one to finish, or stop it, and send again.`,\n );\n }\n try {\n return threadId ? await this.withThread(threadId, owner, start) : await start();\n } finally {\n // A turn that never started a run (a dead thread, stopped while it\n // waited, a throw) frees its slot now; one that did, when the run ends.\n const run = started as AgentRun | null;\n if (run) {\n run.result().then(release, release);\n } else {\n release();\n }\n }\n } finally {\n if (pending && pendingTurns.get(clientRunId) === pending) {\n pendingTurns.delete(clientRunId);\n }\n }\n }\n\n /**\n * A thread holds one run at a time; a new turn on it ends the old one first.\n *\n * Since a dropped connection no longer stops a run, a user who sends again\n * mid-answer used to leave the first run going. It could not see the new\n * turn, the new run's `loadThread` could not see its answer, and both\n * appended when they finished — in whichever order the model returned them,\n * so the thread read `user2, assistant2, user1, assistant1`. `byThread` then\n * named the second run while the first was still live and unstoppable by\n * `threadId`.\n *\n * Stopping the old run and waiting for its transcript to land is chosen over\n * refusing the new turn with a 409, because sending again *is* the stop: it\n * is what `useChat.send` means, and a client that has to poll `/stop` until\n * the run is really gone before it may post the turn it has already shown is\n * a worse client for no better thread. The cost is that the new turn waits\n * for the old run to unwind, which is as long as its slowest tool in flight —\n * and that wait is the thing that puts `assistant1` before `user2`.\n *\n * The wait is on `persistRun`'s `stored`, not on `run.result()`. `result()`\n * settling is the transcript being final, not stored: `appendMessages` runs\n * after it, and a `loadThread` in that gap reads a history the old answer is\n * missing from, which is the original bug by a shorter route. It is also\n * *only* that: `stored` settles once the transcript is stored, and the app's\n * hooks run on in `hooks`, which holds the old run's request and not the\n * thread, so a slow `onMessage` is not a slow thread and a hung one is not a\n * hung thread.\n *\n * The lock around it is what makes a *third* turn wait for the second rather\n * than for the first. Two turns arriving together both see the same live\n * run, both stop it, both wait for it, and both start — the same race, one\n * message later. Under the lock the later one finds the earlier one\n * registered and stops that instead. Per process, like `LiveRuns`, and for\n * the same reason: the run it guards lives here.\n */\n private async withThread(\n threadId: string,\n owner: string | null,\n fn: () => Promise<Response>,\n ): Promise<Response> {\n const previous = threadLocks.get(threadId) ?? Promise.resolve();\n let release!: () => void;\n const held = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => held);\n threadLocks.set(threadId, tail);\n await previous;\n try {\n const live = await this.liveRuns.find({ threadId });\n if (\n live &&\n this.liveRuns.isRunning(live.runId) &&\n !this.liveRuns.mayAccess(live.runId, owner)\n ) {\n // Superseding is a stop, and someone else's run is not this caller's to\n // stop (#442). Only while it is still going: an ended run is kept for\n // `ttlMs` but a turn after it touches nothing of it. Whether this caller\n // may post on the thread at all is `authorizeRequest`'s question.\n return notYourRun();\n }\n const run = live ? this.liveRuns.get(live.runId) : null;\n if (run) {\n // A run that already ended is still `find`-able for `ttlMs`; stopping\n // it is a no-op and waiting on it is the append it may still be doing.\n run.stop({ reason: \"superseded by a later turn on this thread\" });\n await persisted.get(run);\n }\n return await fn();\n } finally {\n release();\n if (threadLocks.get(threadId) === tail) {\n threadLocks.delete(threadId);\n }\n }\n }\n\n /**\n * `POST /<path>/attach` — subscribe to a run already in progress, from a\n * cursor. This is a read of a live run, not a continuation of a stopped one:\n * the work never paused, the listener changed.\n *\n * The cursor is `from`, else the client's `cursor`, else `Last-Event-ID`,\n * else the oldest frame still buffered — and it is honoured only for the run\n * the client's `runId` names. A cursor the buffer has dropped is a 410 naming\n * what survives; *no* cursor is the tail, because a page reattaching on mount\n * has no transcript to leave a hole in. See `resolveCursor`.\n */\n async attach(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req, SMALL_BODY_BYTES);\n if (parsed.error) {\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId =\n typeof body.threadId === \"string\" ? body.threadId : searchParam(req, \"threadId\");\n\n if (!threadId) {\n return jsonResponse(400, {\n code: \"invalid_request\",\n message: \"attach needs a threadId: it is the handle that survives a refresh.\",\n });\n }\n\n // Before the lookup: a refused caller learns neither whether a run is live\n // on the thread nor any frame of it.\n await this.authorizeRequest(req, { route: \"attach\", threadId });\n\n // The store is not consulted. This route answers whether a run is in\n // flight here, and a run it finds was started on a thread `stream` had\n // already loaded; a miss is `no_live_run` whether or not the thread exists,\n // because a client that gets one re-reads the thread anyway (see\n // `onAttachMiss`) and learns there. The thread's own 404 is `stream`'s,\n // where a turn would otherwise be persisted under it.\n const live = await this.liveRuns.find({ threadId });\n if (live && !this.liveRuns.mayAccess(live.runId, await this.runOwner(req))) {\n // Another caller's run (#442): none of its frames, ended or not.\n return notYourRun();\n }\n if (!live) {\n // An explicit miss, not a 200 with an empty stream. See `MemoryLiveRuns`:\n // behind a round-robin load balancer this is the common case, and it has\n // to be visible as one.\n return jsonResponse(404, {\n code: \"no_live_run\",\n message: `No run in progress for thread ${threadId} in this process.`,\n });\n }\n\n // A cursor is only a number if you know which run it counts within: `seq`\n // restarts at zero in every run, so honouring a cursor from run_1 against a\n // live run_2 would skip that many frames off the head of a run this client\n // has seen nothing of. `runId` is the client saying which run its cursor\n // means; naming one that is not live forfeits the cursor and takes the\n // tail, which is as close to the start as the buffer can offer.\n //\n // Only a MISMATCH forfeits. An absent `runId` is not a wrong answer, it is\n // an older question: `from` and `Last-Event-ID` predate the pairing and\n // carry no run, and an `EventSource` reconnecting on its own will never\n // grow one. Those keep resuming exactly as before.\n const cursorRunId = typeof body.runId === \"string\" ? body.runId : undefined;\n const cursor = cursorRunId && cursorRunId !== live.runId ? undefined : resolveCursor(req, body);\n\n try {\n return sseResponse(this.liveRuns.replay(live.runId, cursor));\n } catch (err) {\n if (err instanceof FrameCursorEvictedError) {\n // 410 rather than 404: the run is there, the position is not. A client\n // that gets this reloads the thread instead of resuming into a hole.\n return jsonResponse(410, {\n code: err.code,\n message: err.message,\n oldestSeq: err.oldest,\n });\n }\n if (err instanceof LiveRunNotFoundError) {\n // Lost the race with eviction between `find` and `replay`.\n return jsonResponse(404, { code: err.code, message: err.message });\n }\n throw err;\n }\n }\n\n /**\n * `POST /<path>/stop` — the explicit cancel. Since a dropped connection no\n * longer stops a run, this and a later turn on the same thread are the only\n * things that do, and it is why stopping cannot be a client-side concern:\n * the tool loop is here, and a client that stops reading has not stopped\n * step four from charging a card.\n *\n * Returns as soon as the run is aborted, not when it has finished unwinding.\n * The terminal events — the stopped tool results, the aborted message — go\n * out on the run's own stream, so whoever is watching it sees the ending,\n * and `onMessage` records it whether anyone is watching or not.\n *\n * Answers `{ stopped }` normally, and a `Response` only to reject a request\n * it could not read — the union is the error, not a second success shape.\n */\n async stop(\n req: HttpRequest<any, any> = new HttpRequest(),\n ): Promise<{ stopped: boolean } | Response> {\n const parsed = await readJsonBody(req, SMALL_BODY_BYTES);\n if (parsed.error) {\n // `{ stopped: false }` would be the wrong answer as well as the wrong\n // status: it means \"there was nothing to stop\", and the truth is that we\n // could not tell what to stop. A client that believes the first one stops\n // asking, and the run keeps going.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n\n await this.authorizeRequest(req, {\n route: \"stop\",\n threadId: typeof body.threadId === \"string\" ? body.threadId : undefined,\n });\n\n // Three handles, most specific first, because which ones the client has\n // depends on how far the run got. `runId` is the server's own and settles\n // it. `clientRunId` covers the window before `run-start`, when the client\n // has nothing else for a stateless first turn — and, before that, a turn\n // that has not become a run yet because it is waiting its place on the\n // thread, which is ended where it waits. `threadId` is the fallback for a\n // client that did not start this run at all — one that attached to it,\n // whose replayed tail carried no `run-start`.\n const caller = await this.runOwner(req);\n let runId = typeof body.runId === \"string\" ? body.runId : undefined;\n if (!runId && typeof body.clientRunId === \"string\") {\n runId = this.liveRuns.findByClientRunId(body.clientRunId) ?? undefined;\n if (!runId) {\n const pending = pendingTurns.get(body.clientRunId);\n if (pending) {\n // A `clientRunId` is the client's own choice and only as unguessable\n // as it made it, so the turn it names is checked like a run (#442).\n if (pending.owner !== null && pending.owner !== caller) {\n return notYourRun();\n }\n // Not on to `threadId`: that names the run this turn is queued\n // behind, which is already stopping, and answering for it would\n // leave this one to start.\n pending.cancelled = true;\n return { stopped: true };\n }\n }\n }\n if (!runId && typeof body.threadId === \"string\") {\n runId = (await this.liveRuns.find({ threadId: body.threadId }))?.runId;\n }\n\n const run = runId ? this.liveRuns.get(runId) : null;\n if (!run) {\n // Already finished, already evicted, or never here. Not an error: the\n // caller wanted the run stopped and it is not running.\n return { stopped: false };\n }\n if (!this.liveRuns.mayAccess(run.runId, caller)) {\n // Someone else's run, by whichever handle (#442). See `runOwner`.\n return notYourRun();\n }\n\n run.stop({ reason: typeof body.reason === \"string\" ? body.reason : undefined });\n\n // Deliberately not awaiting `run.result()`. Unwinding means letting tools\n // in flight settle into `denied` results and finalizing the assistant\n // message, which can take as long as the slowest tool — and a stop button\n // that spins for twenty seconds is a stop button people press twice.\n return { stopped: true };\n }\n\n /**\n * WHO A SCOPE BELONGS TO, and the one question in this file whose wrong\n * answer is a data leak rather than a bug.\n *\n * An attachment id given to the model comes back *from* the model, and what\n * the model writes is a function of everything it read — the user's text, a\n * tool's output, a document someone uploaded. So the id is untrusted in\n * exactly the way a request body is, and the scope it resolves under must come\n * from the server's own knowledge of the request. Nothing that reaches this\n * method may be readable or writable by the model: `req` is the HTTP request,\n * and `threadId` is the client's handle, not the model's.\n *\n * THE DEFAULT IS THE AUTHENTICATED USER, falling back to the thread, falling\n * back to `null`.\n *\n * - `user:<id>` when the request is authenticated. `req.ctx().user` is what\n * `AuthenticationMiddleware` and the `Auth` facade put there, so an agent\n * route behind `middlewares = [\"auth\"]` — which `ApiRouter.agent()` makes\n * the default posture — has a subject without the app writing anything.\n * - `thread:<id>` for an unauthenticated chat that has a thread. A `threadId`\n * is minted by `createThread` as a uuid and is documented as a capability,\n * and `upload` only passes one here that `store.loadThread` finds;\n * an anonymous support widget has nothing better, and scoping to the\n * conversation is strictly narrower than scoping to nothing.\n * - `null` otherwise, which means no attachment id is minted at all. There is\n * no third fallback on purpose. `sessionId()` is the tempting one and it is\n * the wrong one: it is a cookie the visitor writes, documented as *not a\n * credential*, so scoping to it is scoping to a value the caller chooses —\n * which is not a scope, it is a lookup key with extra steps.\n *\n * WHAT THIS DEFAULT GETS WRONG, since it will get something wrong for someone:\n * it is per user, not per conversation, so a user's own upload from one thread\n * resolves in another thread of theirs. That is the loose direction, and it is\n * chosen because the tight one breaks the flow the framework actually ships —\n * `useChat.uploadFile` posts a file before any thread exists, so a per-thread\n * default would make the first upload of every conversation unresolvable. An\n * app that wants per-conversation isolation returns\n * `{ key: \\`user:${id}:thread:${threadId}\\` }` here and has it; an app with\n * tenants returns `{ key: \\`org:${orgId}\\` }` and has that. What the default\n * must never be is broader than a user, and it is not.\n *\n * WHATEVER THIS READS MUST BE PRESENT ON EVERY AGENT ROUTE, and the default\n * reads `req.ctx().user`, which is present only where authentication\n * middleware ran. `agent()` mounts four routes and `.middleware()` guards\n * them individually, so `middleware({ stream: \"auth\" })` — the example in\n * `ApiRouter.agent`'s own doc — leaves `POST /chat/files` unauthenticated.\n * The upload then files the record under `thread:<id>` (or nothing at all)\n * while the run that follows, on the guarded route, resolves under\n * `user:<id>`, and every id minted on upload is a miss for the rest of the\n * conversation. It fails as `AttachmentNotFoundError`, worded identically to\n * an id the model invented, which is the point of that error and is also why\n * this particular misconfiguration is invisible. Guard `upload` and `stream`\n * together, or derive the key from something both of them have.\n *\n * gemi does not detect the skew for you, and the reason is the module's whole\n * premise: noticing that an id exists under a *different* scope requires\n * looking it up without one, and an unscoped read is the thing that must not\n * exist here — not even behind a `console.warn`. So the answer is the\n * documentation you are reading and the identical error, not a probe.\n *\n * THE BODY, AND THE ONE RULE FOR READING IT (#603). The third argument is the\n * client's `body` option — what `instructions()` gets — on both routes that\n * resolve a scope: `stream`, and `upload`, where `useChat.uploadFile` sends\n * the same option beside the file. It exists for the chat that has neither a\n * user nor a thread, a stateless page builder say, whose subject is only in\n * the body:\n *\n * protected async attachmentScope(req, threadId, { body }) {\n * const scope = await super.attachmentScope(req, threadId);\n * if (scope) return scope;\n * if (typeof body.pageId !== \"string\") return null;\n * const page = await Page.findFirst({ where: { publicId: body.pageId } });\n * return page ? { key: `page:${page.publicId}` } : null;\n * }\n *\n * The `typeof` line is not tidiness. `Body` types the shape, not the contents,\n * and to an ORM `{ publicId: undefined }` is no filter at all: a request that\n * leaves `pageId` out would find the first page in the table and be filed\n * under it, along with every other request that leaves it out.\n *\n * A body field is a value the caller chose, which is exactly what the\n * `sessionId()` paragraph above refuses. What separates the keys this may be\n * built from is not whether the client sent them — `threadId` is sent by the\n * client too — but WHETHER THE VALUE IS AN UNGUESSABLE CAPABILITY WHOSE\n * EXISTENCE THE SERVER CHECKS. A page `publicId` that is looked up, as above,\n * is one, on the same footing as a `threadId` that `loadThread` finds: holding\n * it is what entitles the caller to the page, and an id nobody minted resolves\n * to nothing. `body.orgId` in an app with users is NOT one, and passing the\n * body is precisely what makes `` { key: `org:${body.orgId}` } `` spellable: an\n * org id is enumerable and the caller may not belong to that org, so that is\n * every tenant's files handed to whoever types another tenant's id. A tenant\n * comes from `req.ctx().user`, never from here. And a value interpolated\n * without being looked up is the `sessionId()` mistake again, however\n * unguessable it looks — an anonymous caller then mints a fresh scope per\n * request. Look it up, and key on what the lookup returned.\n *\n * The same skew rule as above applies to the body, and more quietly: the key\n * must come out the same on `upload` and on `stream`. `useChat` sends the one\n * `body` option to both, so a key derived from a field that stays put for the\n * whole conversation — the page, not the selected element — agrees by\n * construction. One derived from a field that changes between the upload and\n * the turn does not, and fails as that same `AttachmentNotFoundError`.\n *\n * The third argument is new, and the method keeps its first two, so an\n * override written as `attachmentScope(req, threadId)` works unchanged; one\n * that calls `super.attachmentScope(req, threadId)` may leave it off too.\n *\n * The key is opaque and compared with `===`. It is never sent to the client\n * and never shown to the model.\n */\n protected attachmentScope(\n req: HttpRequest<any, any>,\n threadId?: string,\n extra?: { body: Body },\n ): AttachmentScope | null | Promise<AttachmentScope | null> {\n void extra;\n const user = req.ctx()?.user;\n const userId = user?.id ?? user?.publicId;\n if (userId !== undefined && userId !== null && String(userId) !== \"\") {\n return { key: `user:${String(userId)}` };\n }\n if (threadId) {\n return { key: `thread:${threadId}` };\n }\n return null;\n }\n\n /**\n * WHAT THIS ROUTE ACCEPTS AT ALL: a size ceiling and a list of types (#683).\n * Checked once per upload, after `authorizeRequest` and before anything is\n * stored or sent to the provider, and a file outside them is answered **422**\n * with `{ error: { code, message } }` — `file_too_large` or\n * `unsupported_file_type` — which `useChat().attach()` rejects with as an\n * `AttachError`, so a composer can mark the one file.\n *\n * `accept` reads like an `<input accept>`: `\".pdf\"` matches the file name's\n * extension, `\"image/*\"` a type family, `\"text/csv\"` one type. A file\n * matching any entry is accepted. Left out (or `null` returned, the default)\n * means no limit of that kind, which is how the route behaved before.\n *\n * Here rather than in `attachmentDestination`, which an app could throw from\n * to the same end: a throw there is a 500 unless the app builds the response\n * itself, and the provider's own refusal only arrives after the bytes were\n * stored. A limit is a rule about the file, so it is answered before either.\n *\n * protected attachmentLimits() {\n * return { maxBytes: 10 * 1024 * 1024, accept: [\".pdf\", \"image/*\"] };\n * }\n */\n protected attachmentLimits(\n req: HttpRequest<any, any>,\n ): AttachmentLimits | null | Promise<AttachmentLimits | null> {\n void req;\n return null;\n }\n\n /**\n * WHERE ONE FILE'S BYTES SHOULD GO. Called once per upload, with the file in\n * hand.\n *\n * The model needs to perceive a file only for vision or document reading; a\n * tool needs the bytes only to forward them. Those are different needs and\n * they were being answered the same way, because `upload` sent everything to\n * the vendor unconditionally — which is a cost and a data-minimisation problem\n * as much as a capability one. A CSV that exists to be imported belongs in\n * storage and not at the provider; an image the model must look at and no tool\n * will forward is the reverse.\n *\n * THE DEFAULT IS `\"both\"`, AND THE JUSTIFICATION IS THE FAILURE MODE, not the\n * hit rate. A mimeType table was the obvious alternative — images and PDFs to\n * the provider, everything else to storage — and it is wrong in the quiet\n * direction. Getting `\"both\"` wrong sends a file to a vendor that did not need\n * it: it costs money, it is visible on an invoice and in the vendor's file\n * list, and it is corrected by overriding one method. Getting `\"storage\"`\n * wrong drops the file out of the model's view with no error anywhere; the\n * model answers as though the image were not there, which is indistinguishable\n * from a bad prompt, and the developer debugs their instructions for an\n * afternoon. Being wrong on the invoice beats being wrong in a way that\n * presents as \"the AI is stupid\".\n *\n * `\"both\"` is also what keeps this change additive: every upload that reached\n * the provider before still reaches it, and storage is added underneath. An\n * app that never asks for an attachment id sees no difference except a second\n * copy it owns.\n *\n * A client may ask, per file, for `\"storage\"` under a `\"both\"` policy — the\n * one direction that only ever removes the vendor. It may not ask for\n * anything else, including `\"provider\"`, which would let a form field decide\n * that the app does not keep its own copy. See `narrowDestination`.\n */\n protected attachmentDestination(\n file: File,\n req: HttpRequest<any, any>,\n ): AttachmentDestination | Promise<AttachmentDestination> {\n void file;\n void req;\n return \"both\";\n }\n\n /**\n * The attachment handle for this request — the object a tool is given.\n *\n * `null` when `attachmentScope` says the request has no subject, and a caller\n * that gets `null` must not fall back to anything: there is no unscoped handle\n * to fall back to, which is the point.\n *\n * Issue #490 hangs `ctx.attachments` off this.\n */\n protected async attachmentsFor(\n req: HttpRequest<any, any>,\n threadId?: string,\n extra: { body: Body } = { body: {} as Body },\n ): Promise<ScopedAttachments | null> {\n const scope = await this.attachmentScope(req, threadId, extra);\n if (!scope) {\n return null;\n }\n return new ScopedAttachments(this.attachments, this.attachmentStorage, scope);\n }\n\n /**\n * `POST /<path>/files` — takes an attachment and answers the handles for it.\n *\n * `fileId` IS STILL IN THE ANSWER AND STILL MEANS THE SAME THING: the\n * provider's id for the file, the thing a `FilePart` carries, unchanged. It\n * has to stay, because it is what makes vision work and what\n * `useChat.uploadFile` already reads; `attachmentId` is added beside it rather\n * than in place of it. The two are not interchangeable, and swapping them\n * would reach the vendor as a file id it has never issued — so\n * `toResponsesInput` rejects a `gemi_att_` prefix in `FilePart.fileId` with a\n * sentence saying so, rather than leaving it to whatever the vendor answers\n * (not measured).\n *\n * `fileId` is absent exactly when the file did not go to the provider, which\n * only happens when the app or the client asked for that. `attachmentId` is\n * absent when there was no scope to file the record under — see\n * `attachmentScope` — and the answer then carries `downgraded: \"no_scope\"`,\n * which is the only thing separating that case from a controller that chose\n * `\"provider\"` on purpose. Both answer `destination: \"provider\"`, because both\n * are true about where the bytes went.\n *\n * ORDER: storage first, then the provider. If the second one fails the request\n * fails either way, so the only question is where the orphan is left, and an\n * orphan in our own bucket is ours to sweep on a schedule we set, while an\n * orphan at the vendor sits under a retention policy that is not ours.\n */\n async upload(req: HttpRequest<any, any> = new HttpRequest()): Promise<UploadResult> {\n const form = await req.rawRequest.formData();\n const file = form.get(\"file\");\n if (!(file instanceof Blob)) {\n throw new Error(\"upload expects a multipart body with a `file` field.\");\n }\n const name = file instanceof File && file.name ? file.name : \"upload\";\n const mimeType = file.type || \"application/octet-stream\";\n\n // The client's `body` option, as one JSON part beside the file (#603), so\n // `authorizeRequest` and `attachmentScope` see here what they see on\n // `stream`. Read off the form already parsed: the request's body is\n // consumed, and an override cannot read it again. A malformed part is\n // refused before anything else runs, as a malformed turn is on `stream`.\n const extraBody = uploadAppBody<Body>(form.get(\"body\"));\n\n // The client's thread, read here only so an unauthenticated chat has\n // something to scope to. It is the client's own handle — `stream` already\n // takes it on trust for the whole conversation — and it is not the model's:\n // this is a form field on an HTTP request the user's browser made, not a\n // tool argument.\n //\n // It is only passed on if the store knows it. `stream` answers\n // `thread_not_found` for an id it has never seen, and this route must not\n // be looser: an invented id would otherwise be a scope, and an anonymous\n // caller could keep writing to storage by sending a fresh one each time.\n const threadField = form.get(\"threadId\");\n // The field as sent, before the store is asked about it, so a refused\n // caller does not learn whether the thread exists.\n await this.authorizeRequest(req, {\n route: \"upload\",\n threadId: typeof threadField === \"string\" && threadField.length > 0 ? threadField : undefined,\n body: extraBody,\n });\n // Before the thread is looked up, the policy is asked, or a byte is kept:\n // a file this route never takes costs nothing past this line.\n const refusal = limitRefusal(await this.attachmentLimits(req), file, name, mimeType);\n if (refusal) {\n throw new LimitedUploadError(refusal.code, refusal.message);\n }\n\n const threadId =\n typeof threadField === \"string\" &&\n threadField.length > 0 &&\n (await this.store.loadThread(threadField)) !== null\n ? threadField\n : undefined;\n\n // Who the provider's copy will belong to (#443): the same key that owns a\n // run this caller starts, so the turn that names the file finds it its own.\n const owner = await this.runOwner(req);\n const recordOwner = (fileId: string) =>\n this.fileOwners.record(fileId, {\n owner,\n name,\n mimeType,\n size: file.size,\n createdAt: new Date().toISOString(),\n });\n\n const policy = await this.attachmentDestination(file as File, req);\n const destination = narrowDestination(policy, form.get(\"destination\"));\n\n const scope = await this.attachmentScope(req, threadId, { body: extraBody });\n\n // The app's policy wanted a copy of these bytes and the request has no\n // subject to file them under. Recorded rather than merely warned about,\n // because the answer has to be able to tell the client that what it is\n // getting is not the policy — see `UploadResult.downgraded`.\n const downgraded = destination !== \"provider\" && !scope;\n if (downgraded) {\n if (destination === \"storage\") {\n // Bytes were asked to be kept and there is nobody to keep them for.\n // Storing them anyway files them under a scope every caller shares, and\n // answering nothing is an upload that silently did not happen. Neither\n // is an answer; this is.\n throw new Error(\n 'This upload was routed to storage, but `attachmentScope()` returned null for the request, so there is no subject to file the attachment under. Guard the route (`this.agent(Chat).middleware({ upload: \"auth\" })`), send a `threadId` with the upload, or override `attachmentScope()`.',\n );\n }\n // Policy said `both` and the request has no subject: fall through to the\n // provider alone, which is exactly what this route did before attachments\n // existed. Downgrading rather than throwing is what keeps an\n // unauthenticated chat working across the upgrade — but a downgrade nobody\n // is told about is the failure mode this file keeps arguing against, so it\n // is warned once per process on the server and marked `downgraded` in the\n // answer, so the client can tell this apart from a deliberate\n // provider-only policy.\n warnUnscopedUploadOnce();\n }\n\n if (destination === \"provider\" || !scope) {\n // Identical to the pre-attachment behaviour, down to the answer's\n // `fileId` — plus `downgraded` when this path was not the app's choice.\n const fileId = await providerUpload(this.agent.provider, file as File);\n await recordOwner(fileId);\n const answer: UploadResult = {\n fileId,\n name,\n mimeType,\n size: file.size,\n destination: \"provider\",\n };\n if (downgraded) {\n answer.downgraded = \"no_scope\";\n }\n return answer;\n }\n\n const attachmentId = newAttachmentId();\n const objectName = await this.attachmentStorage.put({\n name: attachmentObjectName(attachmentId, name),\n body: file,\n contentType: mimeType,\n });\n\n const fileId =\n destination === \"both\" ? await providerUpload(this.agent.provider, file as File) : undefined;\n if (fileId) {\n await recordOwner(fileId);\n }\n\n const record: Attachment = {\n id: attachmentId,\n scopeKey: scope.key,\n fileId,\n objectName,\n name,\n mimeType,\n size: file.size,\n createdAt: new Date().toISOString(),\n destination,\n };\n await this.attachments.put(scope, record);\n\n return { fileId, attachmentId, name, mimeType, size: file.size, destination };\n }\n\n /**\n * The 403 for a turn naming a provider file id that is not this caller's, or\n * `null` when every id may be used (#443). See `fileOwners`.\n *\n * Only `fileId` is checked: an `attachmentId` is resolved under the request's\n * own scope, so another user's is already a not-found (`ScopedAttachments`).\n * An entry carrying the caller's own `attachmentId` beside a foreign `fileId`\n * is refused all the same — the `fileId` is what reaches the provider.\n */\n private async foreignFile(\n files: { fileId?: string }[],\n caller: string | null,\n ): Promise<Response | null> {\n const ids = new Set(\n files.map((file) => file.fileId).filter((id): id is string => typeof id === \"string\"),\n );\n for (const fileId of ids) {\n const record = await this.fileOwners.get(fileId);\n if (record ? record.owner !== null && record.owner !== caller : this.requireKnownFiles) {\n // The same sentence for a file that is someone else's and, in strict\n // mode, one nobody recorded: which of the two it is would tell a caller\n // probing ids that the id exists.\n return notYourFile();\n }\n }\n return null;\n }\n\n /**\n * Protected, not private: these exist to be overridden. `onMessage` fires for\n * every completed message, user and assistant alike, and is the intended\n * persistence point for an app that is not using `store`.\n *\n * Once per message, in the transcript's order. The turn's own user message\n * is handed over while the run is still going: on a thread once the store\n * has it, and before the model's answer, so whatever the app keeps beside it\n * is there for a read of the thread during a long run (#806). Every other\n * message is handed over after the run, as before. A run that fails or is\n * stopped after taking the turn in has still reported it.\n *\n * Every hook runs inside the request that started the run, which is held\n * open for them — after the run, and after a client that left — so\n * `ctx.req.ctx().user` is the user who sent the turn. See `hookHoldMs` for\n * how long a hook that does not finish keeps it.\n */\n protected onMessage(message: AgentMessage, ctx: AgentHookContext): void | Promise<void> {\n void message;\n void ctx;\n }\n\n protected onToolCall(\n call: { toolCallId: string; name: string; input: unknown },\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void call;\n void ctx;\n }\n\n /** Fires before the stream ends `awaiting-input` — where to notify whoever\n * has to approve, if they are not the person watching the stream. */\n protected onAwaitingInput(\n pending: PendingToolCall[],\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void pending;\n void ctx;\n }\n\n /**\n * What the client is told about a failure: the run's `error` frame, and the\n * result of a tool that threw, which the model reads too and the store\n * keeps. Return the error to send.\n *\n * The default (`redactError` from `gemi/ai`) keeps `code`, `retryable` and\n * `toolCallId` and replaces every message gemi did not write with a fixed\n * sentence for its code: a provider's error body names resources,\n * deployments and request ids, and an exception's text can be a connection\n * string. A tool that throws a `ToolError` keeps its message. The full\n * detail is in `info` (`info.failure` for the run, `info.cause` for a\n * tool), in the log, on `result().error`, and in `onError`, which is handed\n * the unredacted error.\n *\n * Override it to show more, for instance everything in development:\n *\n * protected redactError(error, info, ctx) {\n * if (process.env.NODE_ENV === \"development\") return error;\n * return super.redactError(error, info, ctx);\n * }\n *\n * Only the `AgentError` fields of what it returns are sent. One that throws\n * is reported and the default is used instead.\n */\n protected redactError(\n error: AgentError,\n info: ErrorRedactionInfo,\n ctx: AgentHookContext,\n ): AgentError {\n void ctx;\n return redactError(error, info);\n }\n\n /**\n * A failure on the run's stream, unredacted: the provider's own message,\n * and the HTTP `status` and `requestId` when there were any. The client was\n * sent `redactError`'s copy.\n */\n protected onError(error: AgentError, ctx: AgentHookContext): void | Promise<void> {\n void error;\n void ctx;\n }\n\n protected onStreamComplete(\n result: AgentRunResult<ToolShapesOf<A[\"tools\"]>, any>,\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void result;\n void ctx;\n }\n\n /**\n * WHAT HAPPENS WHEN A HOOK THROWS: it is reported and the run carries on.\n *\n * The alternative is to fail the run, and that trade is not close. These\n * hooks are an app's persistence and notification points; the run is a model\n * call the user has already been charged for and whose tools may already have\n * charged a card. Letting a failed `INSERT` in `onMessage` abort a generation\n * mid-sentence loses the answer as well as the row, and the user cannot\n * retry into a better outcome. So the answer survives and the failure is\n * logged.\n *\n * It is logged rather than routed to `onError`: `onError` is itself a hook,\n * and a hook that throws inside the handler for hooks that throw is a loop.\n * Override this to send it somewhere with a pager attached.\n */\n protected reportHookFailure(error: unknown): void {\n console.error(\"[gemi/ai] agent controller hook failed\", error);\n }\n\n private async dispatchEvent(event: AgentStreamEvent, ctx: AgentHookContext): Promise<void> {\n switch (event.type) {\n case \"tool-call\":\n // Skipped while the arguments are still streaming: a hook that fires\n // per token would fire with a half-parsed input, which is worse than\n // firing late. And skipped for a re-sent frame, which carries a parked\n // sub-run's record on a call this hook has already seen — once per call\n // is the contract, and a run that re-parks would otherwise fire it for\n // a call some earlier run made.\n if (!event.part.partial && !event.resent) {\n await this.onToolCall(\n {\n toolCallId: event.part.toolCallId,\n name: String(event.part.name),\n input: event.part.input,\n },\n ctx,\n );\n }\n return;\n case \"awaiting-input\":\n await this.onAwaitingInput(event.pending as PendingToolCall[], ctx);\n return;\n case \"error\":\n // The frame carries the redacted copy; the hook is server-side and\n // gets what it was made from.\n await this.onError(unredactedError(event.error), ctx);\n return;\n default:\n return;\n }\n }\n\n /**\n * The thread as a client should see it: the store's history, with any\n * assistant message a dead run left unfinished marked `interrupted` (#617).\n *\n * For the app's own route that hands a thread to `useChat` (or a native\n * session) as its initial messages. A message whose run is still going here\n * is left as it is, still being written, so the client attaches to it. `null`\n * for a thread the store does not have, as `loadThread` answers.\n *\n * It does not write: the next turn on the thread settles the same messages\n * the same way and stores them then, under the thread's lock.\n */\n async readThread(threadId: string): Promise<AgentMessage[] | null> {\n const history = await this.store.loadThread(threadId);\n return history ? (await this.settleThread(threadId, history, { write: false })).messages : null;\n }\n\n /**\n * Whether the run that was writing a message is still going, so the message\n * is in progress rather than interrupted.\n *\n * The default asks this process's `liveRuns`, which is the whole answer on a\n * single instance: a run lives in the process that started it, and a run\n * that is not there died with an earlier one. A finished run still within\n * `ttlMs` counts as live, since its final write may not have landed yet.\n *\n * Behind several instances it is not the whole answer. A run on another\n * instance is not in this map, so its message reads as interrupted here\n * until that run's own writes replace it. Knowing better needs a lasting\n * record of running runs (#459); override this to consult one.\n */\n protected isRunLive(runId: string, threadId: string): boolean | Promise<boolean> {\n void threadId;\n return this.liveRuns.get(runId) !== null;\n }\n\n private async settleThread(\n threadId: string,\n history: AgentMessage[],\n { write }: { write: boolean },\n ): Promise<{ messages: AgentMessage[]; jobs: AgentJobRecord[] }> {\n const isLive = (runId: string) => this.isRunLive(runId, threadId);\n const interrupted = await settleInterrupted(history, isLive);\n let messages = interrupted.messages;\n let jobs: AgentJobRecord[] = [];\n const settled = new Map(interrupted.settled.map((message) => [message.id, message]));\n\n // Background jobs (#461): each `running` tool result gets its job's\n // current state, and the ones that settled are written back with the\n // rest. A job store that cannot be read leaves the results `running`,\n // which is what the model saw last time, rather than failing the turn.\n if (hasRunningResult(messages) || write) {\n try {\n const overlaid = await overlayJobs(messages, {\n threadId,\n store: AgentJobs.store,\n isRunLive: isLive,\n outputSchemaFor: (name) => this.toolOutputSchema(name),\n scan: this.jobsBlockMax(),\n });\n messages = overlaid.messages;\n jobs = overlaid.jobs;\n for (const message of overlaid.settled) settled.set(message.id, message);\n if (write && overlaid.orphans.length > 0) {\n await markOrphans(AgentJobs.store, overlaid.orphans, (err) =>\n this.reportHookFailure(err),\n );\n const orphans = new Set(overlaid.orphans.map((record) => record.id));\n jobs = jobs.map((record) =>\n orphans.has(record.id) ? { ...record, orphaned: true as const } : record,\n );\n }\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n\n if (write && settled.size > 0) {\n try {\n await this.store.appendMessages(threadId, [...settled.values()]);\n } catch (err) {\n // The run still gets the settled history. The store keeps the\n // unfinished copy, and the next turn settles it the same way again.\n this.reportHookFailure(err);\n }\n }\n return { messages, jobs };\n }\n\n /** The agent's `jobs.contextBlock.max`, or 0 for no block. */\n private jobsBlockMax(): number {\n const block = (this.agent as { jobs?: { contextBlock?: { max?: number } | false } }).jobs\n ?.contextBlock;\n if (block === false) return 0;\n return block?.max ?? DEFAULT_JOBS_CONTEXT_MAX;\n }\n\n private jobsBlock(jobs: AgentJobRecord[]): string | null {\n return renderJobsBlock(jobs, this.jobsBlockMax());\n }\n\n /** A tool's output schema, by name, for checking a background job's output. */\n private toolOutputSchema(name: string): Schema<any> | undefined {\n const visit = (entries: readonly unknown[]): Schema<any> | undefined => {\n for (const entry of entries) {\n const tool = entry as { name?: string; outputSchema?: Schema<any>; tools?: unknown[] };\n if (Array.isArray(tool.tools)) {\n const found = visit(tool.tools);\n if (found) return found;\n } else if (tool.name === name) {\n return tool.outputSchema;\n }\n }\n return undefined;\n };\n return visit((this.agent as { tools?: readonly unknown[] }).tools ?? []);\n }\n\n /**\n * Feeds the run's frames to its journal as they are emitted.\n *\n * A subscriber of its own on `run.frames()` rather than a ride on the\n * `onEvent` chain: that chain waits for the app's hooks, and a slow\n * `onToolCall` must not be what decides whether a tool call was stored\n * before the process died. `frames()` is a read of the run's own buffer, the\n * one `toResponse` already reads beside `liveRuns`, so a third reader costs a\n * cursor and nothing else.\n */\n private follow(run: AgentRun, journal: TurnJournal): void {\n void (async () => {\n try {\n for await (const frame of run.frames()) journal.frame(frame);\n } catch (err) {\n this.reportHookFailure(err);\n }\n })();\n }\n\n /**\n * Runs after the stream is over, whether or not anyone was still watching it.\n *\n * The messages come from `result()` rather than from the event stream because\n * assembling a message out of deltas is the agent's job and doing it twice is\n * how the two copies drift. It also means a stopped run persists the same way\n * a finished one does: `stop()` finalizes the transcript, so by the time this\n * resolves there is a valid history to store.\n *\n * `stored` settles when the transcript is in the store, not when the app is\n * done with it. The next turn on this thread waits on that (see\n * `withThread`), and the hooks are the app's: an `onMessage` that writes to\n * something slow would make every later turn wait for it, once per message\n * of the old run, and one that never settles — which `safely` cannot catch —\n * would hold the thread, and every turn queued on it, behind an open\n * connection each. So the hooks run on after it on their own, reported the\n * same way.\n *\n * `hooks` settles once they have too, and every event-stream hook the run\n * led to (`eventHooks`), or after `hookHoldMs` of them, and is what the\n * request that started the run is held open for. Separate from\n * `stored` for the reason above, and it has to exist from the start: by the\n * time the hooks are called the run has settled, and the request with it,\n * unless something was already holding it. Neither rejects.\n */\n private persistRun(\n run: AgentRun,\n ctx: AgentHookContext,\n eventHooks: Promise<void>,\n journal: TurnJournal | null = null,\n early: EarlyTurn = { id: null, notified: Promise.resolve() },\n ): { stored: Promise<void>; hooks: Promise<void> } {\n // Assigned before `stored` settles, on every path, so `hooks` below reads\n // the chain this run actually started.\n let notified: Promise<void> = Promise.resolve();\n\n const stored = (async () => {\n let result: AgentRunResult<ToolShapes, unknown>;\n try {\n result = await run.result();\n } catch (err) {\n // What was written while it ran stays: it is the most the store can\n // know about a run that did not settle, and the next read marks it\n // interrupted once the run is gone.\n journal?.close();\n await journal?.settled();\n // After the turn's own `onMessage`, if the run got that far: the hooks\n // keep their order on every path.\n notified = early.notified.then(() =>\n this.safely(() =>\n this.onError(\n {\n code: \"unknown\",\n message: err instanceof Error ? err.message : String(err),\n retryable: false,\n },\n ctx,\n ),\n ),\n );\n return;\n }\n\n const messages = result.messages as AgentMessage[];\n\n // The writes made while it ran land first, then the transcript whole: the\n // same messages under the same ids, now final, so this replaces every\n // in-progress copy rather than adding to them.\n journal?.close(messages);\n await journal?.settled();\n\n if (ctx.threadId && messages.length > 0) {\n try {\n await this.store.appendMessages(ctx.threadId, messages);\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n\n notified = this.notifyRun(result, messages, ctx, early);\n })();\n\n // The bound starts once the run has settled, not with the run: a long run\n // is not a hung hook. `eventHooks` is in it because the event-stream hooks\n // are chained (see `MemoryLiveRuns.register`): an `onAwaitingInput` queued\n // behind a slow `onToolCall` is called after the run, and after every hook\n // above, and has nothing else to hold the request for it.\n const hooks = stored.then(() =>\n within(\n Promise.all([notified, eventHooks]).then(() => {}),\n this.hookHoldMs,\n ),\n );\n return { stored, hooks };\n }\n\n /** The hooks on a finished run, in order. Never rejects: see `safely`. */\n private async notifyRun(\n result: AgentRunResult<ToolShapes, unknown>,\n messages: AgentMessage[],\n ctx: AgentHookContext,\n early: EarlyTurn,\n ): Promise<void> {\n // The turn's message was handed to `onMessage` while the run went. It\n // comes before every message the run made after it, so waiting for it\n // here keeps the hook's order the transcript's.\n await early.notified;\n for (const message of messages) {\n if (message.id === early.id) continue;\n await this.safely(() => this.onMessage(message, ctx));\n }\n\n await this.safely(() => this.onStreamComplete(result as any, ctx));\n }\n\n private async safely(fn: () => void | Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n}\n\n/**\n * The turn's user message, as far as the app's `onMessage` has heard of it\n * (#806).\n *\n * The turn's message is the one thing a run stores that the app usually wants\n * to tag from the request: where it was sent from, whether the app sent it on\n * the user's behalf. Called after the run with everything else, those tags\n * were missing for the whole of a long run, to a reload or a second tab, while\n * the store already held the message. So it is called as soon as the journal\n * has written it, and `notifyRun` skips it by `id`: once per message, as\n * before, and in the same order.\n */\ntype EarlyTurn = {\n /** The turn message's id, once the run has reported it. */\n id: string | null;\n /** Settles once its `onMessage` has. Never rejects. */\n notified: Promise<void>;\n};\n\n// --- request plumbing ----------------------------------------------------\n\n/**\n * The keys of the turn envelope itself, which `useChat` puts in the same JSON\n * object as an app's `body`.\n *\n * Listed so `appBody` can take them back out. Sharing one object was the right\n * wire choice — a nested `body` field would be a second envelope for every\n * client, including the Swift and Kotlin ones — but it does mean the app's\n * fields and the framework's are mixed together on arrival, and handing an app\n * `turn` and `messages` would invite reading them. They are this module's to\n * change; an app that depended on their shape would break on a release that\n * never mentioned them.\n */\nconst ENVELOPE_KEYS = [\"turn\", \"clientRunId\", \"threadId\", \"messages\", \"regenerate\"] as const;\n\n/**\n * The turn's own fields, which `toClientTurn` reads off the top level when the\n * body carries no `turn` object. Reserved in that form and only that form —\n * with an envelope present, a top-level `text` is the app's.\n */\nconst BARE_TURN_KEYS = [\"text\", \"files\", \"toolResults\"] as const;\n\n/**\n * An app's own fields, out of the parsed turn body.\n *\n * A fresh object rather than a `delete` on the parsed one. Nothing reads the\n * body after this today — `turn`, `threadId`, `clientRunId` and `messages` are\n * all pulled out above — so this is not load-bearing and no test pins it. It is\n * how a helper that takes a parsed body should behave regardless: the next\n * reader to move a line above this one should not have to know that the body\n * was quietly hollowed out.\n */\nfunction appBody<Body extends object>(\n body: Record<string, any>,\n reserved: readonly string[] = hasTurnEnvelope(body)\n ? ENVELOPE_KEYS\n : [...ENVELOPE_KEYS, ...BARE_TURN_KEYS],\n): Body {\n const extra: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(body)) {\n if (reserved.includes(key)) continue;\n // `JSON.parse` produces `__proto__` as an own property, and `Object.entries`\n // hands it over like any other. Assigning it with `[]` goes through\n // `Object.prototype`'s setter and changes the prototype of the object an app\n // is about to read — from a value the client chose. `defineProperty` writes\n // the key itself, which is what \"the fields the client sent\" means.\n Object.defineProperty(extra, key, {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n return extra as Body;\n}\n\n/**\n * The app's fields from an upload's `body` form part — the JSON of\n * `useChat`'s `body` option — in the shape `stream` hands out.\n *\n * One JSON part rather than a form field per key: a form field is a string, so\n * `{ count: 3 }` would arrive as `\"3\"` and `Body` would lie on this route and\n * not the other. A missing part is `{}`, as a turn with no app fields is.\n *\n * Only the envelope's four names are taken back out, not the bare-turn ones:\n * `useChat` always sends a `turn` envelope, so on `stream` an app's `text` is\n * the app's, and it has to be here as well.\n *\n * Anything else — a file where the JSON should be, JSON that does not parse,\n * JSON that is not an object — is a 400, not `{}`. Read as empty, the scope\n * would quietly resolve to `null` and the upload downgrade, and the reason\n * would be a missing page rather than a broken client.\n */\nfunction uploadAppBody<Body extends object>(part: FormDataEntryValue | null): Body {\n if (part === null) {\n return {} as Body;\n }\n let parsed: unknown;\n if (typeof part === \"string\") {\n try {\n parsed = JSON.parse(part);\n } catch {\n throw new InvalidUploadError(\"The upload's `body` field is not valid JSON.\");\n }\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new InvalidUploadError(\"The upload's `body` field must be a JSON object.\");\n }\n return appBody<Body>(parsed as Record<string, any>, ENVELOPE_KEYS);\n}\n\n/**\n * A 400 from `upload`, which answers `UploadResult` and so rejects by throwing.\n * The payload is the shape `stream`'s own 400s have, so a client reads both the\n * same way.\n */\nclass InvalidUploadError extends RequestBreakerError {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidUploadError\";\n this.payload = {\n api: { status: 400, data: { error: { code: \"invalid_request\", message } } },\n view: {},\n };\n }\n}\n\n/**\n * The provider's upload, with a refusal of THE FILE answered as the client's\n * problem rather than the server's.\n *\n * A vendor that will not take a file answers 4xx, and before this that left\n * `upload` as an unhandled `ProviderHttpError`: a 500 that tells the person\n * attaching the file nothing about the file. MEASURED on Azure (#682,\n * 2026-10-01): with `purpose: \"user_data\"` a `.docx` was refused with `400\n * Unsupported extension: .docx. Supported extensions: .txt, .md, .pdf, …`; with\n * `assistants` the `.docx` is accepted (and read in a turn), and an `.exe` is\n * refused with `400 Invalid extension exe. Supported formats: \"c\", \"cpp\", …`.\n * Either sentence is exactly what the person needs to read, so it is passed\n * through as the message.\n *\n * Only the statuses that are about the request body: 400, 413, 415 and 422. A\n * 401/403 is our key, a 429/5xx is the vendor's day, and both stay server\n * errors — a person cannot fix either by picking another file.\n */\nasync function providerUpload(provider: { upload(file: File): Promise<string> }, file: File) {\n try {\n return await provider.upload(file);\n } catch (error) {\n if (error instanceof ProviderHttpError && REJECTED_FILE_STATUSES.has(error.status)) {\n throw new RejectedUploadError(normalizeProviderError(error).message);\n }\n throw error;\n }\n}\n\nconst REJECTED_FILE_STATUSES = new Set([400, 413, 415, 422]);\n\n/** A 422 from `upload` for a file outside `attachmentLimits`. */\nclass LimitedUploadError extends RequestBreakerError {\n constructor(code: \"file_too_large\" | \"unsupported_file_type\", message: string) {\n super(message);\n this.name = \"LimitedUploadError\";\n this.payload = {\n api: { status: 422, data: { error: { code, message } } },\n view: {},\n };\n }\n}\n\n/** Why `file` is outside `limits`, or `null` when it is not. Exported for the\n * tests; the route is the only caller. */\nexport function limitRefusal(\n limits: AttachmentLimits | null | undefined,\n file: Blob,\n name: string,\n mimeType: string,\n): { code: \"file_too_large\" | \"unsupported_file_type\"; message: string } | null {\n if (!limits) return null;\n const { maxBytes, accept } = limits;\n if (typeof maxBytes === \"number\" && file.size > maxBytes) {\n return {\n code: \"file_too_large\",\n message: `${JSON.stringify(name)} is ${formatBytes(file.size)}; the limit is ${formatBytes(maxBytes)}.`,\n };\n }\n if (\n accept &&\n accept.length > 0 &&\n !accept.some((entry) => acceptMatches(entry, name, mimeType))\n ) {\n return {\n code: \"unsupported_file_type\",\n message: `${JSON.stringify(name)} is not a type this chat accepts. Accepted: ${accept.join(\", \")}.`,\n };\n }\n return null;\n}\n\nfunction acceptMatches(entry: string, name: string, mimeType: string): boolean {\n const rule = entry.trim().toLowerCase();\n if (!rule) return false;\n if (rule.startsWith(\".\")) return name.toLowerCase().endsWith(rule);\n const type = mimeType.toLowerCase().split(\";\")[0]!.trim();\n if (rule.endsWith(\"/*\")) return type.startsWith(rule.slice(0, -1));\n return type === rule;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n const units = [\"KB\", \"MB\", \"GB\"];\n let value = bytes / 1024;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit++;\n }\n return `${Math.round(value * 10) / 10} ${units[unit]}`;\n}\n\n/**\n * A 422 from `upload`: the provider would not take this file. `code` is\n * `unsupported_file_type` when the vendor said the type was the problem (an\n * extension or format allow-list) and `file_rejected` otherwise, so\n * a composer can mark the one chip without parsing English. Same payload shape\n * as `InvalidUploadError`.\n */\nclass RejectedUploadError extends RequestBreakerError {\n constructor(message: string) {\n super(message);\n this.name = \"RejectedUploadError\";\n const code =\n /(unsupported|invalid) (extension|file type|format|mime)|supported (extensions|formats?)/i.test(\n message,\n )\n ? \"unsupported_file_type\"\n : \"file_rejected\";\n this.payload = {\n api: { status: 422, data: { error: { code, message } } },\n view: {},\n };\n }\n}\n\n/**\n * A body, or the reason there is not one.\n *\n * Deliberately one shape with an optional `error` rather than a discriminated\n * union on `ok`: this package compiles with `strict: false`, and without\n * `strictNullChecks` TypeScript will not narrow a union by a boolean\n * discriminant — `if (!parsed.ok)` leaves `parsed.message` an error. A field\n * that is either set or not needs no narrowing to read.\n */\ntype ParsedBody = {\n body: Record<string, any>;\n error?: string;\n /** Which HTTP error the rejection is. A missing one is the 400. */\n status?: number;\n code?: string;\n};\n\n/**\n * The body, as JSON — or a reason it is not.\n *\n * Read off the raw request rather than through `req.input()`: that path also\n * accepts `+json` types and answers its failures as a thrown refusal, while\n * these routes are held to `application/json` alone (below) and answer with\n * a `{ code, message }` body of their own.\n *\n * Matching the type by prefix is not the same as ignoring it. A body that\n * arrives as anything other than `application/json` is a 415, and the reason\n * is not tidiness: a cross-site `<form enctype=\"text/plain\">` can be made to\n * concatenate its one field into valid JSON, and a JSON parser that reads\n * whatever it is handed turns that form into a turn on someone else's\n * conversation. Insisting on `application/json` is what makes these routes\n * non-simple requests — the browser will not send one cross-origin without a\n * preflight — and that holds whether or not the app's cookies are `SameSite`\n * and whether or not `CSRFMiddleware` is mounted. Only a request that carries a\n * body is held to this; a bodiless POST has no type to check and stays `{}`.\n *\n * The three cases are kept apart deliberately. NO body is a real request — a\n * reattach, or a turn that just lets the model continue — and reads as `{}`. A\n * body that will not parse, or that parses to something other than an object,\n * is a failed request and has to say so: folding it into `{}` made a truncated\n * proxy response or a mis-serialized client indistinguishable from an empty\n * turn, so `stream` billed a model call with no history and no turn and threw\n * the user's actual message away. That presents as the model hallucinating\n * rather than as an error, which is the expensive way to debug it. Pre-flight\n * failures stay ordinary HTTP errors and never reach the event stream.\n *\n * An array counts as malformed even though `typeof [] === \"object\"`: nothing\n * downstream reads a positional body, so `[1,2,3]` could only ever have run as\n * an empty turn.\n */\nasync function readJsonBody(req: HttpRequest<any, any>, maxBytes: number): Promise<ParsedBody> {\n const raw = req?.rawRequest;\n if (!raw || raw.method === \"GET\" || raw.method === \"HEAD\" || !raw.body) {\n return { body: {} };\n }\n\n if (!isJsonContentType(raw.headers.get(\"Content-Type\"))) {\n // Before the body is read: nothing in a body about to be refused is worth\n // the bytes, and the refusal must not depend on what they were.\n return {\n body: {},\n status: 415,\n code: \"unsupported_media_type\",\n error: \"The request body must be sent as application/json.\",\n };\n }\n\n // Before a byte is read when the client declared its length, and while\n // reading when it did not (#444).\n const declared = Number(raw.headers.get(\"Content-Length\"));\n if (Number.isFinite(declared) && declared > maxBytes) {\n return bodyTooLarge(maxBytes);\n }\n\n let text: string;\n try {\n const read = await readCapped(raw, maxBytes);\n if (read === null) {\n return bodyTooLarge(maxBytes);\n }\n text = read;\n } catch {\n // A body that stopped arriving mid-flight. Same class of failure as one\n // that arrived truncated, and the same answer.\n return { body: {}, error: \"The request body could not be read.\" };\n }\n\n if (!text.trim()) {\n return { body: {} };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return { body: {}, error: \"The request body is not valid JSON.\" };\n }\n\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { body: {}, error: \"The request body must be a JSON object.\" };\n }\n\n return { body: parsed as Record<string, any> };\n}\n\n/**\n * Media types compare case-insensitively and may carry parameters, so the\n * comparison is on the lowercased type with its parameters cut off, and\n * `Application/JSON; charset=utf-8` passes. It is an equality on that type\n * rather than a prefix, so `application/json-seq` and the other types that\n * merely begin with those bytes do not. None of the three types a browser will\n * send without a preflight — `text/plain`, `application/x-www-form-urlencoded`,\n * `multipart/form-data` — does either, and neither does no type at all, which\n * is what a hand-written `fetch` with a string body and no header ends up\n * sending as `text/plain`.\n */\nfunction isJsonContentType(value: string | null): boolean {\n return mediaType(value) === \"application/json\";\n}\n\n/**\n * The body as text, or `null` once more than `maxBytes` of it has arrived, at\n * which point the rest is not read. A limit that is not finite reads it all.\n */\nasync function readCapped(raw: Request, maxBytes: number): Promise<string | null> {\n if (!Number.isFinite(maxBytes) || !raw.body) {\n return await raw.text();\n }\n const reader = raw.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel().catch(noop);\n return null;\n }\n chunks.push(value);\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(bytes);\n}\n\nfunction bodyTooLarge(maxBytes: number): ParsedBody {\n return {\n body: {},\n status: 413,\n code: \"body_too_large\",\n error: `The request body is larger than this agent accepts (${maxBytes} bytes).`,\n };\n}\n\n/**\n * A refusal for one of #444's limits: the `{ kind, message, status }` every\n * refusal has (#686), plus the `code` the agent routes' own errors carry, so a\n * client can tell the limits apart without reading the message.\n */\nfunction limitResponse(status: number, code: string, message: string): Response {\n return jsonResponse(status, {\n ...refusal(refusalKindForStatus(status), message, status),\n code,\n });\n}\n\nfunction invalidRequest(parsed: ParsedBody): Response {\n if (parsed.status === 413) {\n return limitResponse(413, parsed.code ?? \"body_too_large\", parsed.error ?? \"\");\n }\n return jsonResponse(parsed.status ?? 400, {\n code: parsed.code ?? \"invalid_request\",\n message: parsed.error,\n });\n}\n\n/**\n * Whether the turn arrived in a `turn` object of its own, rather than spread\n * across the top level of the body.\n *\n * Both forms are accepted, and which one it is decides what belongs to the app:\n * a top-level `text` is the user's message in the bare form and an app's own\n * field in the enveloped one. `toClientTurn` and `appBody` have to agree about\n * that, so they ask the same question here rather than each testing it.\n */\nfunction hasTurnEnvelope(body: Record<string, any>): boolean {\n return Boolean(body.turn) && typeof body.turn === \"object\";\n}\n\n/**\n * The client's turn, accepting both `{ turn: {...} }` and the flattened\n * `{ text, files, toolResults }` — the second is what a hand-written `fetch`\n * writes, and refusing it buys nothing.\n *\n * `turn` is `undefined` for an empty turn, which is a real request:\n * reattaching to a conversation and letting the model continue is a turn with\n * nothing in it. `error` is a turn that is refused with a 400 before anything\n * runs — see `toTurnFiles`.\n */\nfunction toClientTurn(body: Record<string, any>): { turn?: ClientTurn; error?: string } {\n const source = hasTurnEnvelope(body) ? body.turn : body;\n const turn: ClientTurn = {};\n if (typeof source.text === \"string\") {\n turn.text = source.text;\n }\n if (Array.isArray(source.files)) {\n const files = toTurnFiles(source.files);\n if (typeof files === \"string\") {\n return { error: files };\n }\n turn.files = files;\n }\n if (Array.isArray(source.toolResults)) {\n turn.toolResults = source.toolResults;\n }\n if (Object.keys(turn).length === 0) return {};\n // Envelope only: in the bare form the top level is shared with the app's own\n // fields, and an app that already sends a `localId` of its own would lose it\n // to the turn. `null` and `\"\"` read as absent, as they do for `files`.\n if (\n source === body.turn &&\n source.localId !== undefined &&\n source.localId !== null &&\n source.localId !== \"\"\n ) {\n const { localId } = source;\n if (typeof localId !== \"string\") return { error: \"turn.localId must be a string.\" };\n // Echoed back on the stream and nothing else, so the only thing to bound\n // is what one frame carries.\n if (localId.length > MAX_LOCAL_ID_LENGTH) {\n return { error: `turn.localId is longer than ${MAX_LOCAL_ID_LENGTH} characters.` };\n }\n turn.localId = localId;\n }\n return { turn };\n}\n\n/** How long `turn.localId` may be. Comfortably above `local_<uuid>`. */\nconst MAX_LOCAL_ID_LENGTH = 200;\n\n/**\n * `turn.files`, checked field by field, or the sentence refusing it.\n *\n * REFUSED, NOT FILTERED. Every entry becomes a `FilePart` in a user message,\n * and on a thread that message is stored before the provider sees it. An entry\n * the request builder cannot send — no id at all, or a gemi id in `fileId` —\n * then throws from `toResponsesInput` on this turn and on every turn after it,\n * because every later turn re-sends the history: one bad upload bricks the\n * thread. Dropping the entry instead is quieter and worse — the model answers\n * about a file it was never given, with nothing saying so. A 400 here is the\n * one place the client can still do something about it.\n *\n * Scoping is what makes a foreign `attachmentId` harmless (`ScopedAttachments`\n * answers the same not-found for another tenant's id as for an invented one),\n * so the id is not signed or looked up here. What this checks is the shape a\n * crash would come from: strings where strings go, the prefix on\n * `attachmentId`, at least one id. Unknown fields are dropped rather than\n * refused, since `attach()` answers more than a `FilePart` holds (`downgraded`)\n * and passing its answer on whole is the documented use. `null` and `\"\"` read\n * as absent, for every field: `null` is what a serializer that writes\n * `undefined` as `null` means, and `\"\"` is what a form field left blank sends.\n * Neither can be an id, so refusing `attachmentId: \"\"` for its prefix would\n * turn a blank into an error the entry's `fileId` does not deserve.\n */\nfunction toTurnFiles(raw: unknown[]): NonNullable<ClientTurn[\"files\"]> | string {\n const files: NonNullable<ClientTurn[\"files\"]> = [];\n for (const [index, entry] of raw.entries()) {\n const where = `turn.files[${index}]`;\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n return `${where} must be an object.`;\n }\n const fields: Record<string, string> = {};\n for (const key of [\"fileId\", \"attachmentId\", \"name\", \"mimeType\"] as const) {\n const value = (entry as Record<string, unknown>)[key];\n if (value === undefined || value === null || value === \"\") continue;\n if (typeof value !== \"string\") {\n return `${where}.${key} must be a string.`;\n }\n fields[key] = value;\n }\n const { fileId, attachmentId, name, mimeType } = fields;\n if (fileId?.startsWith(ATTACHMENT_ID_PREFIX)) {\n return `${where}.fileId holds a gemi attachment id (${fileId}). \\`fileId\\` is the provider's id from the upload response; put this one in \\`attachmentId\\`.`;\n }\n if (attachmentId !== undefined && !attachmentId.startsWith(ATTACHMENT_ID_PREFIX)) {\n return `${where}.attachmentId is not a gemi attachment id: it must start with \"${ATTACHMENT_ID_PREFIX}\".`;\n }\n if (!fileId && !attachmentId) {\n return `${where} has neither a \\`fileId\\` nor an \\`attachmentId\\`. Send the ids the upload response answered.`;\n }\n files.push({\n ...(fileId ? { fileId } : {}),\n ...(attachmentId ? { attachmentId } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n return files;\n}\n\n/**\n * Where to resume from, or `undefined` for \"wherever you still can\".\n *\n * An explicit `from` wins, because a client that tracked its own position knows\n * something the transport does not. Otherwise `Last-Event-ID` — the browser\n * sends it on its own when an `EventSource` reconnects, and the frames put\n * `seq` in `id:` precisely so that header is already the right question. It\n * names the last event *received*, so the resume point is one past it.\n *\n * With neither, the answer is `undefined` and NOT 0. A client reattaching on\n * mount is a fresh POST from a page that has just loaded: no `Last-Event-ID`,\n * and no cursor of its own, because the only handle it was given is the\n * `threadId`. Reading that as \"resume from frame 0\" asked `replay` for a frame\n * every run longer than `maxFrames` has already evicted, so the mount-time\n * reattach — the one case `/attach` exists for — 410'd on exactly the long runs\n * it was meant to rescue, and the documented remedy of reloading the thread\n * does not help because the store is only written at run end. `undefined` means\n * the tail, which is all such a client can use anyway.\n */\nfunction resolveCursor(req: HttpRequest<any, any>, body: Record<string, any>): number | undefined {\n if (typeof body.from === \"number\" && Number.isFinite(body.from)) {\n return Math.max(0, Math.floor(body.from));\n }\n // `cursor` is what `useChat` actually sends, and it counts the other way:\n // `from` is the frame to resume AT, `cursor` the last frame the client\n // APPLIED — the same convention as `Last-Event-ID`, and the same `+ 1`. A\n // client that has applied nothing sends -1, which is not a position but the\n // absence of one, so it falls through to the tail rather than asking for\n // frame 0 and 410ing on precisely the long runs `/attach` exists to rescue.\n if (typeof body.cursor === \"number\" && Number.isFinite(body.cursor)) {\n const applied = Math.floor(body.cursor);\n if (applied >= 0) {\n return applied + 1;\n }\n return undefined;\n }\n const header = req?.rawRequest?.headers?.get(\"Last-Event-ID\");\n if (header) {\n const seq = Number.parseInt(header, 10);\n if (Number.isFinite(seq)) {\n return Math.max(0, seq + 1);\n }\n }\n return undefined;\n}\n\nfunction searchParam(req: HttpRequest<any, any>, key: string): string | undefined {\n const value = req?.search?.get(key);\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Where a threaded regenerate cuts the history: at the last message the user\n * wrote, with the turn that wrote it. A file a tool showed is a user-role\n * message too, but it is part of the answer being replaced, so it is stepped\n * over (`injectedMessageIds`, the test `historyForProvider` uses).\n */\nfunction regenerationCut(\n messages: AgentMessage[],\n): { index: number; turn: ClientTurn } | null {\n const injected = injectedMessageIds(messages);\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index]!;\n if (message.role !== \"user\" || injected.has(message.id)) continue;\n let text = \"\";\n const files: NonNullable<ClientTurn[\"files\"]> = [];\n for (const part of message.content) {\n if (part.type === \"text\") text += part.text;\n if (part.type === \"file\") {\n files.push({\n ...(part.fileId ? { fileId: part.fileId } : {}),\n ...(part.attachmentId ? { attachmentId: part.attachmentId } : {}),\n ...(part.name ? { name: part.name } : {}),\n ...(part.mimeType ? { mimeType: part.mimeType } : {}),\n });\n }\n }\n if (!text && files.length === 0) continue;\n return {\n index,\n turn: { ...(text ? { text } : {}), ...(files.length > 0 ? { files } : {}) },\n };\n }\n return null;\n}\n\n/** A turn `/stop` ended while it waited, before anything ran or was charged. */\nfunction stoppedBeforeStart(): Response {\n return jsonResponse(409, {\n code: \"stopped\",\n message: \"The turn was stopped before it started.\",\n });\n}\n\n/**\n * The refusal for a run that belongs to another caller (#442), in the shape\n * every other refusal has (`{ kind, message, status }`, #686), so `useChat` and\n * the client guards classify it as `permission` without matching on text.\n */\nfunction notYourRun(): Response {\n return jsonResponse(\n 403,\n refusal(\"permission\", \"This run belongs to someone else.\", 403) as Record<string, unknown>,\n );\n}\n\n/** The refusal for a turn naming another owner's provider file (#443). Same\n * shape as `notYourRun`. */\nfunction notYourFile(): Response {\n return jsonResponse(\n 403,\n refusal(\n \"permission\",\n \"A file in this turn was uploaded by someone else.\",\n 403,\n ) as Record<string, unknown>,\n );\n}\n\n/**\n * The file parts of a stateless chat's history, which the client carries and\n * may have written anything into. Read defensively: the history is not\n * validated anywhere else before the run, and a malformed one is the run's\n * problem, not this check's.\n */\nfunction clientHistoryFiles(messages: unknown): { fileId?: string }[] {\n if (!Array.isArray(messages)) return [];\n const files: { fileId?: string }[] = [];\n for (const message of messages) {\n const content = (message as { content?: unknown } | null)?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (part && typeof part === \"object\" && typeof part.fileId === \"string\") {\n files.push({ fileId: part.fileId });\n }\n }\n }\n return files;\n}\n\nfunction jsonResponse(status: number, error: Record<string, unknown>): Response {\n return new Response(JSON.stringify({ error }), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\n// --- attachments ---------------------------------------------------------\n\n/**\n * Reads the client's `destination` field and applies it to the app's policy.\n *\n * THE ONLY THING A CLIENT MAY ASK FOR IS \"DO NOT SEND THIS TO THE VENDOR\", and\n * that is the entire permitted vocabulary: a `storage` hint under a `both`\n * policy, or a hint that agrees with the policy and changes nothing. Everything\n * else throws.\n *\n * The rule here used to be \"a hint may narrow, never widen\", counting\n * destinations, and counting is what made it wrong in one direction.\n * `both → provider` is fewer destinations and reads as narrowing, but what it\n * removes is *gemi's own copy*, while the third party still gets the file. That\n * is not a client declining exposure, it is a client overriding the app's\n * retention decision from a field in a multipart body: an app that keeps every\n * upload because a tool has to forward it — or because an auditor asked — loses\n * the copy, mints no `attachmentId`, records nothing, and gets no warning\n * either, since the bytes did reach the provider exactly as policy said. The\n * two directions are not alike, because only one of them reduces who ends up\n * holding the file.\n *\n * What is left is defensible on its own terms: `storage` keeps bytes off a\n * vendor the app was willing to send them to, which is a thing the client is\n * entitled to ask for and which cannot hurt anyone if the client is lying. A UI\n * that knows this CSV exists to be imported and will never be read by the model\n * is the case that makes a hint worth having at all. The policy hook is the\n * ceiling; the hint may only take the vendor out from under it.\n *\n * A hint the policy does not permit throws rather than being ignored. Ignoring\n * it is the shape of this bug that never gets found: the client believes it kept\n * a file off the vendor, the file went anyway, and nothing anywhere says so.\n */\nfunction narrowDestination(\n policy: AttachmentDestination,\n hint: FormDataEntryValue | null,\n): AttachmentDestination {\n if (typeof hint !== \"string\" || hint.length === 0) {\n return policy;\n }\n if (hint !== \"both\" && hint !== \"provider\" && hint !== \"storage\") {\n throw new Error(\n `Unknown attachment destination \"${hint}\". Expected \"both\", \"provider\" or \"storage\".`,\n );\n }\n if (hint === policy || (policy === \"both\" && hint === \"storage\")) {\n return hint;\n }\n if (policy === \"both\" && hint === \"provider\") {\n throw new Error(\n 'This upload asked for the \"provider\" destination under a \"both\" policy. A client may ask for \"storage\", which keeps a file away from the model provider, but it may not ask the server to stop keeping its own copy while the vendor still gets the file — that is the app\\'s retention decision. Change `attachmentDestination()` if this file should not be kept.',\n );\n }\n throw new Error(\n `This upload asked for the \"${hint}\" destination, but the server's policy for it is \"${policy}\", and a client hint may only ask for \"storage\" under a \"both\" policy. Change \\`attachmentDestination()\\` if the file really should go there.`,\n );\n}\n\n/**\n * Said once per process, not once per upload.\n *\n * The condition is a property of how the app is wired — an agent route with no\n * authentication and no `threadId` on its uploads — so it is either true for\n * every request or false for every request. Logging it per request would put a\n * line in the log for every file anyone ever uploads, which is how a warning\n * stops being read.\n */\nlet warnedAboutUnscopedUpload = false;\nfunction warnUnscopedUploadOnce(): void {\n if (warnedAboutUnscopedUpload) return;\n warnedAboutUnscopedUpload = true;\n console.warn(\n \"[gemi/ai] An upload had no attachment scope, so its bytes were sent to the model provider only and no attachment id was minted — a tool cannot forward this file. Guard the route with auth, send a `threadId` with the upload, or override `attachmentScope()`.\",\n );\n}\n\n// --- routing -------------------------------------------------------------\n//\n// `agent()` itself belongs on ApiRouter next to `resource()`, which is the\n// method it works like: one call, several routes, all of them the controller's.\n// The types are declared here because they are the ai module's contract, not\n// the router's.\n//\n// class Api extends ApiRouter {\n// routes = {\n// \"/chat\": this.agent(ChatAgentController),\n// };\n// }\n//\n// POST /chat → stream every client turn\n// POST /chat/attach → attach reattach to a run in progress\n// POST /chat/stop → stop explicit cancel\n// POST /chat/files → upload attachments\n//\n// Mounting under a single path is what gives the client one key to name. The\n// agent's tool types ride along on `AgentRoute`, so `useChat(\"/chat\")` gets them\n// out of the existing `RPC` interface — no second augmentation to generate, and\n// renaming the route moves the client key with it.\n\nexport type AgentRouteMethod = \"stream\" | \"attach\" | \"stop\" | \"upload\";\n\nexport type AgentMiddlewareConfig = Partial<Record<AgentRouteMethod, MiddlewareInput>>;\n\n/**\n * What `this.agent(Controller)` returns. `T` is unconstrained so that mounting\n * the route never resolves the controller (#774): an agent whose tools are\n * routes of the same api would otherwise resolve the api's route table from\n * inside it. That `T` is an `AgentController` class is checked when the route\n * is mounted: `this.agent()` throws otherwise.\n */\nexport type AgentRoute<T> = {\n __internal_brand: \"AgentRoute\";\n controller: T;\n middleware(config: AgentMiddlewareConfig): AgentRoute<T>;\n};\n\n/** What `CreateRPC` should produce for an agent route: enough for the client to\n * type its messages, and nothing that drags server code into the bundle. */\nexport type AgentRouteRPC<T extends new () => AgentController<any, any>> = {\n __agent: true;\n tools: InstanceType<T>[\"agent\"] extends AnyAgent\n ? ToolShapesOf<InstanceType<T>[\"agent\"][\"tools\"]>\n : ToolShapes;\n output: unknown;\n /**\n * The controller's `Body`, so `useChat` can check what it sends against what\n * the controller declared.\n *\n * Read off the phantom key rather than by matching the class, which is what\n * made this fail: `Body` used to reach the instance type only through\n * `instructions`'s second parameter, and a controller overriding\n * `instructions(req)` — the pre-existing signature, so every existing\n * override — gave inference nothing to work with and got the open record.\n */\n body: InstanceType<T> extends { [BODY]?: infer B } ? B : Record<string, unknown>;\n};\n\n/** The longest delay `setTimeout` keeps; past it the runtime fires in ~1ms. */\nconst MAX_TIMEOUT_MS = 2 ** 31 - 1;\n\n/**\n * Settles when `work` does or after `ms`, whichever is first, and never\n * rejects. For how long the request waits on the app's code, not for the code\n * itself, which runs on either way.\n *\n * An `ms` a timer cannot hold — `Infinity` is what \"no bound\" reads as — is\n * no bound. Handed to `setTimeout` it would fire at once, and the request\n * would end before the hooks it was raised for.\n */\nfunction within(work: Promise<void>, ms: number): Promise<void> {\n const settled = work.then(\n () => {},\n () => {},\n );\n if (!(ms <= MAX_TIMEOUT_MS)) {\n return settled;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, ms);\n });\n return Promise.race([settled, timeout]).finally(() => clearTimeout(timer));\n}\n\nlet warnedInMemoryNonces = false;\n\n/**\n * Once per process, in production: a stateless chat whose answers are spent\n * only in this process's memory. Correct for a single instance, which is why\n * it is a warning; with several, a rewound history replays an approval once\n * per instance (#445).\n */\nfunction warnInMemoryNonces(nonces: NonceStore): void {\n if (warnedInMemoryNonces || process.env.NODE_ENV !== \"production\") return;\n if (!(nonces instanceof MemoryNonceStore)) return;\n warnedInMemoryNonces = true;\n console.warn(\n \"[gemi/ai] A stateless agent chat is spending approval nonces in process memory. \" +\n \"With more than one instance a replayed approval is accepted once per instance. \" +\n \"Set `nonces = new RedisNonceStore()` (or your own NonceStore) on the AgentController.\",\n );\n}\n\n/** Whether any message holds a tool result still waiting on a background job. */\nfunction hasRunningResult(messages: AgentMessage[]): boolean {\n return messages.some((message) =>\n message.content.some((part) => part.type === \"tool-result\" && part.status === \"running\"),\n );\n}\n"
|
|
29
|
+
"import { Storage } from \"../facades/Storage\";\nimport { Controller } from \"../http/Controller\";\nimport { refusal, RequestBreakerError } from \"../http/Error\";\nimport { HttpRequest } from \"../http/HttpRequest\";\nimport { RequestContext } from \"../http/requestContext\";\nimport { mediaType } from \"../http/mediaType\";\nimport { refusalKindForStatus } from \"../http/refusal\";\nimport type { MiddlewareInput } from \"../http/middlewareList\";\nimport type { AgentResource } from \"../http/ResourcePolicy\";\nimport type {\n AgentContext,\n AgentRun,\n AgentRunResult,\n AnyAgent,\n PrepareStepContext,\n PrepareStepResult,\n ToolShapesOf,\n} from \"./Agent\";\nimport type { ContextWindowOptions } from \"./contextWindow\";\nimport { isSummaryStore, type ThreadSummary } from \"./contextCompaction\";\nimport { injectedMessageIds } from \"./Agent\";\nimport {\n type Attachment,\n ATTACHMENT_ID_PREFIX,\n type AttachmentDestination,\n attachmentObjectName,\n type AttachmentScope,\n type AttachmentStorage,\n type AttachmentStore,\n defaultAttachmentStore,\n newAttachmentId,\n ScopedAttachments,\n} from \"./store/Attachments\";\nimport {\n FrameCursorEvictedError,\n liveRuns as defaultLiveRuns,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n} from \"./store/LiveRuns\";\nimport {\n defaultFileOwners,\n type FileOwnerRecord,\n type FileOwners,\n MemoryFileOwners,\n} from \"./store/FileOwners\";\nimport {\n defaultNonceStore,\n MemoryNonceStore,\n type NonceRedisClient,\n type NonceStore,\n RedisNonceStore,\n type RedisNonceStoreOptions,\n} from \"./store/Nonces\";\nimport {\n MemoryReceiptStore,\n type ReceiptClaim,\n type ReceiptRedisClient,\n type ReceiptStore,\n RedisReceiptStore,\n type RedisReceiptStoreOptions,\n} from \"./store/Receipts\";\nimport { defaultAgentStore, MemoryAgentStore } from \"./store/MemoryAgentStore\";\nimport { normalizeProviderError, ProviderHttpError } from \"./providers/errors\";\nimport { redactError, unredactedError } from \"./redact\";\nimport type { ErrorRedactionInfo } from \"./redact\";\nimport { sseResponse } from \"./store/sse\";\nimport { settleInterrupted, TurnJournal } from \"./store/TurnJournal\";\nimport { AgentJobs } from \"./jobs/AgentJob\";\nimport { markOrphans, overlayJobs } from \"./jobs/overlay\";\nimport { DEFAULT_JOBS_CONTEXT_MAX, renderJobsBlock } from \"./jobs/contextBlock\";\nimport type { AgentJobRecord } from \"./jobs/AgentJobStore\";\nimport type { Schema } from \"./Schema\";\nimport type {\n AgentError,\n AgentMessage,\n AgentStreamEvent,\n ClientTurn,\n PendingToolCall,\n ToolShapes,\n} from \"./types\";\n\n// --- storage -------------------------------------------------------------\n\n/**\n * Where conversations live.\n *\n * Stateless is the default and nothing here is required to hold a conversation:\n * the client can carry its own history, and a pending approval travels in it\n * safely because the server signed it. What a store buys is a conversation that\n * survives the browser — and, with `/attach`, one whose interrupted turn is\n * still there after a refresh.\n */\nexport interface AgentStore {\n /**\n * Where a `threadId` comes from. `ApiRouter.agent()` mounts no route for\n * this: the app writes one, calls it here, and hands the id to `useChat` —\n * the mount is the app's because it is where ownership gets recorded, and a\n * store that holds no user cannot do that for it. An id that did not come out\n * of here is `null` from `loadThread` and a 404 from the controller, unless\n * the store's ids are the client's by design (`MemoryAgentStore`'s\n * `clientOwnedIds`).\n */\n createThread(params: { userId?: string | number }): Promise<{ threadId: string }>;\n /**\n * The history, or `null` for a thread the store does not have.\n *\n * `null` and `[]` are different answers and the controller acts on the\n * difference: an empty array is a conversation with nothing in it yet, and a\n * turn on it runs; `null` is a 404 before anything runs. A store that answers\n * `[]` for an id it has never seen turns an expired or mistyped thread into a\n * fresh conversation with no signal, and persists the next turn under the\n * dead id. Only a store whose ids are minted by the client should do that,\n * and then on purpose — see `MemoryAgentStore`'s `clientOwnedIds`.\n */\n loadThread(threadId: string): Promise<AgentMessage[] | null>;\n /**\n * Upsert by message id: replace a message the thread already holds, append\n * one it does not, and keep the order the thread had. Called with a thread\n * `loadThread` just found; must not create one.\n *\n * The name says append because that is what almost every call is, but a\n * turn that resolves a pending call reports the earlier assistant message\n * again — same id, now with the result attached — and a store that only\n * appends ends up with both versions. A table keyed by message id has the\n * lookup already but still needs an insert-or-update rather than a plain\n * insert, which would fail on the key; a store that is a list has to look\n * before it pushes.\n *\n * It is also called while a turn runs, not only when it ends (#617): with the\n * user's message as the run starts, with the assistant message in progress\n * (no `finishReason`, the run's id in `runId`) as it opens and at each tool\n * call and result, and with each message again once it is finished. The\n * same message arrives several times, and the last write is the one to\n * keep. Calls for one run never overlap: each waits for the one before.\n */\n appendMessages(threadId: string, messages: AgentMessage[]): Promise<void>;\n /**\n * Delete these messages from the thread; ids it does not hold are ignored.\n *\n * What a threaded `regenerate` needs (#451): the server owns the history,\n * so the answer being replaced has to leave the store, or the model reads\n * `user: X, assistant: A, user: X` and writes a follow-up instead of a new\n * answer. The controller calls it under the thread's lock with the last user\n * turn and everything after it, then runs that turn again.\n *\n * Optional so a store written before it still compiles; without it a turn\n * with `regenerate: true` on a thread is a 501 `regenerate_unsupported`.\n */\n removeMessages?(threadId: string, messageIds: string[]): Promise<void>;\n /**\n * Optional: where `contextWindow.compact` keeps the thread's summaries\n * (#782), so they live, and are deleted, with the thread. Implement both to\n * opt in; without them summaries go to `defaultSummaryStore`, in memory.\n * Same contract as `SummaryStore`.\n */\n loadSummaries?(threadId: string): Promise<ThreadSummary[]>;\n saveSummary?(threadId: string, summary: ThreadSummary): Promise<void>;\n /** Optional cross-process lock for one cut. See `SummaryStore.lockSummary`. */\n lockSummary?(\n threadId: string,\n cutMessageId: string,\n ttlMs: number,\n ): Promise<(() => Promise<void>) | null>;\n}\n\n/** The default: conversations last as long as the process. */\nexport { defaultAgentStore, MemoryAgentStore };\n\n/** The attachment half of the same story. See `store/Attachments.ts`. */\nexport {\n type Attachment,\n type AttachmentDestination,\n AttachmentNotFoundError,\n type AttachmentScope,\n type AttachmentStorage,\n type AttachmentStore,\n defaultAttachmentStore,\n InvalidAttachmentScopeError,\n MemoryAttachmentStore,\n type PutAttachmentParams,\n ScopedAttachments,\n type ToolAttachmentPut,\n type ToolAttachmentRecord,\n type ToolAttachments,\n} from \"./store/Attachments\";\n\n/**\n * The runs currently in flight, and their frames.\n *\n * A run outlives the request that started it, so something has to hold it while\n * no one is listening, and hold what it emitted meanwhile so a returning client\n * can catch up rather than start over. That is all this is: a per-process map\n * plus a bounded buffer.\n *\n * Per-process is not an implementation shortcut that a better store fixes — a\n * running generator lives in one process, and a second server cannot attach to\n * it. Reattachment therefore needs the request to land where the run is: one\n * server, sticky routing, or a proxy that forwards by `runId`. Worth saying out\n * loud, because the failure mode behind a round-robin load balancer is a\n * refresh that usually works.\n *\n * This is the read side, which is all `attach` and `stop` need. Registering a\n * run and replaying its buffer are on `MemoryLiveRuns`, the only implementation\n * there can be — see the note there for why a second one would not help.\n */\nexport interface LiveRuns {\n /** What the client asks after a refresh: is anything still going here? */\n find(params: { threadId: string }): Promise<{ runId: string; seq: number } | null>;\n get(runId: string): AgentRun | null;\n /** Kept for a short while after `run-end`, so a refresh a second late still\n * sees the tail instead of an empty screen. */\n ttlMs: number;\n}\n\nexport {\n FrameCursorEvictedError,\n LiveRunNotFoundError,\n MemoryLiveRuns,\n defaultLiveRuns as liveRuns,\n};\n\n/** Who uploaded each provider file id (#443). See `store/FileOwners.ts`. */\nexport { defaultFileOwners, type FileOwnerRecord, type FileOwners, MemoryFileOwners };\n/** Where approved tools' executions are recorded (#458). See `store/Receipts.ts`. */\nexport {\n MemoryReceiptStore,\n type ReceiptClaim,\n type ReceiptRedisClient,\n type ReceiptStore,\n RedisReceiptStore,\n type RedisReceiptStoreOptions,\n};\n/** Where answered calls' nonces are spent (#445). See `store/Nonces.ts`. */\nexport {\n defaultNonceStore,\n MemoryNonceStore,\n type NonceRedisClient,\n type NonceStore,\n RedisNonceStore,\n type RedisNonceStoreOptions,\n};\n\n// --- controller ----------------------------------------------------------\n\nexport type AgentHookContext = {\n /**\n * The request that started the turn. Its `state` is the turn's own typed\n * state (#887): a value set in `authorizeRequest()`, `instructions()` or\n * `context()` (`req.state.set(key, value)`) is read here with\n * `ctx.req.state.get(key)`, instead of a `WeakMap` keyed on the request.\n * A request answering an approval is a new turn and starts with none.\n */\n req: HttpRequest<any, any>;\n runId: string;\n threadId?: string;\n};\n\n/**\n * What `AgentController.startTurn` takes (#839).\n */\nexport type AgentTurnParams<Body extends object = Record<string, unknown>> = {\n /** The thread the turn is stored on, as a turn from `useChat` would be. */\n threadId: string;\n /** The user's message. Shorthand for `turn: { text }`, and wins over `turn.text`. */\n text?: string;\n /**\n * The whole turn, for files or answers: `{ text, files, toolResults }`, as\n * `useChat` sends it. Neither `text` nor `turn` is a turn with nothing in\n * it, which lets the model continue the thread.\n */\n turn?: ClientTurn;\n /**\n * Who the turn runs as: `req.ctx().user` for `authorizeRequest`, `runOwner`,\n * `context()`, the hooks and every tool, as the authentication middleware\n * would have set it. Absent or `null` is an anonymous turn.\n */\n user?: unknown;\n /** What `useChat`'s `body` option would send: `instructions()`, `context()` and `ctx.body` read it. */\n body?: Body;\n};\n\n/** A turn `AgentController.startTurn` started. */\nexport type AgentTurn = {\n runId: string;\n threadId: string;\n /** The run: iterate it (or its `frames()`) to follow the turn as it goes. */\n run: AgentRun;\n /** What the chat's stop button does. */\n stop(params?: { reason?: string }): void;\n /**\n * Settles when the run has ended, its transcript is stored and the\n * controller's hooks have run (or `hookHoldMs` has passed). Rejects only if\n * the run itself does; a failed model call resolves with `finishReason:\n * \"error\"` and `error`, as `AgentRun.result()` does.\n */\n result(): Promise<AgentTurnResult>;\n};\n\n/** What `AgentTurn.result()` answers: the run's result, and what a caller reads off it. */\nexport type AgentTurnResult = AgentRunResult<ToolShapes, unknown> & {\n threadId: string;\n /** The text of the run's last assistant message; `\"\"` when it wrote none. */\n text: string;\n /**\n * The calls waiting for an answer when `finishReason` is\n * `\"awaiting-input\"`, and `[]` otherwise. They stay on the thread, signed\n * for the turn's `runOwner`: that user can answer them in the chat, or the\n * caller can with another `startTurn({ turn: { toolResults } })`.\n */\n pending: PendingToolCall[];\n};\n\n/**\n * A turn `startTurn` could not start: what the route would have answered,\n * thrown. `status` and `code` are the route's (`404` `thread_not_found`,\n * `429` `too_many_runs`, `403` for another owner's run or file...).\n */\nexport class AgentTurnError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly kind?: string;\n\n constructor(message: string, params: { status: number; code?: string; kind?: string }) {\n super(message);\n this.name = \"AgentTurnError\";\n this.status = params.status;\n this.code = params.code;\n this.kind = params.kind;\n }\n\n /** @internal Reads a refusal `stream` answered. */\n static async from(response: Response): Promise<AgentTurnError> {\n let error: Record<string, unknown> = {};\n try {\n const parsed = (await response.json()) as { error?: Record<string, unknown> };\n if (parsed?.error && typeof parsed.error === \"object\") error = parsed.error;\n } catch {\n // Not a JSON refusal: the status says what there is to say.\n }\n const text = (key: string) => (typeof error[key] === \"string\" ? (error[key] as string) : undefined);\n return new AgentTurnError(\n text(\"message\") ?? `The agent turn was refused with status ${response.status}.`,\n { status: response.status, code: text(\"code\"), kind: text(\"kind\") },\n );\n }\n}\n\n/** `Body` of a controller instance type, as `AgentRouteRPC` reads it. */\ntype ControllerBody<C> = C extends { [BODY]?: infer B }\n ? B extends object\n ? B\n : Record<string, unknown>\n : Record<string, unknown>;\n\n/** The text of the last assistant message among `messages`, or `\"\"`. */\nfunction lastAssistantText(messages: AgentMessage[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages[i];\n if (message.role !== \"assistant\") continue;\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\");\n }\n return \"\";\n}\n\n/** What `AgentController.attachmentLimits` answers. Both optional. */\nexport type AttachmentLimits = {\n /** The largest file accepted, in bytes. */\n maxBytes?: number;\n /** `<input accept>` entries: `\".pdf\"`, `\"image/*\"`, `\"text/csv\"`. */\n accept?: string[];\n};\n\n/** The file `AgentController.checkUpload` is asked about: what it is, not its bytes. */\nexport type UploadCheckFile = {\n /** The file's name as the client sent it, `\"upload\"` when it sent none. */\n name: string;\n /** In bytes. */\n size: number;\n /** As the client sent it, `\"application/octet-stream\"` when it sent none. */\n mimeType: string;\n};\n\n/**\n * What an upload hook is told beyond the request (#836): the client's `body`\n * option (what `attachmentScope` gets) and the thread the upload is for, when\n * the store knows it.\n */\nexport type UploadContext<Body extends object = Record<string, unknown>> = {\n body: Body;\n /** Only a thread the store found; an id it has never seen is left out. */\n threadId?: string;\n};\n\n/**\n * What `AgentController.checkUpload` returns to refuse a file. Answered **422**\n * with `{ error: { code, message } }`, which `useChat().attach()` rejects with\n * as an `AttachError` carrying the same `code` and `message`.\n */\nexport type UploadRefusal = {\n /** A code the composer can switch on. `\"upload_refused\"` when left out. */\n code?: string;\n /** The sentence the person reads. */\n message: string;\n};\n\n/**\n * What `POST /<path>/files` answers.\n *\n * TWO IDS, AND THEY ARE NOT INTERCHANGEABLE. `fileId` is the *provider's* id and\n * means exactly what it always meant — the value a `FilePart` carries so the\n * model can see the file. `attachmentId` is *gemi's*, and is the handle a tool\n * resolves through `ScopedAttachments` to get the bytes back. A file can have\n * both, and usually does.\n *\n * `fileId` stays first and stays named that on purpose: `useChat.uploadFile`\n * already reads it, apps already put it in a `FilePart`, and renaming it or\n * folding the two into one id would break vision for every existing app while\n * looking like a tidier API. The two ids exist because there are two systems\n * holding the file.\n *\n * Both are optional, and `destination` says which to expect: `provider` has no\n * `attachmentId` (nothing was kept), `storage` has no `fileId` (the provider\n * never saw it, so there is nothing for a `FilePart` to point at), `both` has\n * both.\n *\n * `destination` ALONE IS NOT ENOUGH TO SAY WHY AN ID IS MISSING, which is why\n * `downgraded` is here. An upload that reached a route with no authentication\n * and no `threadId` answers `destination: \"provider\"` — truthfully, that is\n * where the bytes went — and so does a controller that deliberately returns\n * `\"provider\"` from `attachmentDestination`. Those two answers were byte\n * identical, and they are the opposite situations: one is the app's policy\n * working, the other is the app's policy silently not applying because the\n * server could not tell who was calling. The server logs the second one once\n * per process; the client saw nothing at all. `downgraded` is the difference,\n * carried in the answer so a client — or an integration test — can assert on\n * it.\n */\nexport type UploadResult = {\n /** The provider's id, for a `FilePart`. Absent when the file never went there. */\n fileId?: string;\n /** gemi's id, for a tool. Absent when nothing was kept — see `attachmentScope`. */\n attachmentId?: string;\n name: string;\n mimeType: string;\n size: number;\n destination: AttachmentDestination;\n /**\n * Set only when the app's policy asked for a copy and the request had no\n * subject to file it under, so the upload fell back to the provider alone.\n * Absent when `destination` is what the app actually chose.\n *\n * A string rather than `true` because there is exactly one reason today and\n * there will be more (a store that refused the write, say), and a boolean\n * that later needs a reason beside it is two fields where one would have\n * done.\n */\n downgraded?: \"no_scope\";\n};\n\n/**\n * `Controller.kind` is typed as the literal `\"controller\"`, so a subclass that\n * declares a `kind` of its own fails the static-side check (TS2417). Widening\n * it belongs in `http/Controller.ts`, which this slice does not own; erasing\n * the static side of the base here is the smaller change and costs nothing —\n * `Controller.kind` has no reader, in this package or out of it.\n */\nconst ControllerBase = Controller as new () => Controller;\n\n/**\n * The thread a `stream` is setting up on, to the setup ahead of it. Module\n * level because the controller is constructed per request, so nothing on it\n * can be seen by the next request; keyed by thread rather than held on\n * `liveRuns` because it guards the controller's protocol, not the frames. An\n * entry is removed once the last setup queued on it releases.\n */\nconst threadLocks = new Map<string, Promise<void>>();\n\n/**\n * Each run to the promise that its transcript has been stored. Weak, so a run\n * the map has evicted is not kept alive here for a promise nobody will ask for.\n */\nconst persisted = new WeakMap<AgentRun, Promise<void>>();\n\n/**\n * The run a `startTurn` request started, by that request (#839). `stream`\n * answers a `Response`, which is what a route needs; `startTurn` needs the run\n * itself and the promise that its hooks are done, and this is how it gets them\n * without `stream` growing a second return shape. Weak, so a request nobody\n * reads back leaves nothing behind.\n */\nconst serverTurns = new WeakMap<\n HttpRequest<any, any>,\n { run: AgentRun; hooks: Promise<void> } | null\n>();\n\n/** The URL of the request `startTurn` builds. Nothing routes to it. */\nconst SERVER_TURN_URL = \"http://gemi.internal/__gemi/agent-turn\";\n\n/**\n * Turns read but not yet registered, by the client's name for them.\n *\n * A run can be stopped from `register` on, and named from `run-start` on. What\n * `/stop` could not reach was a turn still waiting its place on the thread —\n * which is where a user who sent twice and thought better of it presses stop,\n * and the wait is now as long as the old run's unwind. Falling through to\n * `threadId` there found the old run, already stopping, said `stopped: true`,\n * and the queued turn started anyway: unwatched, billing, and with no handle\n * left on the client that had let go of it. The entry is marked rather than\n * removed, because the turn itself is what answers once its wait is over.\n */\nconst pendingTurns = new Map<string, { cancelled: boolean; owner: string | null }>();\n\n// --- limits (#444) -------------------------------------------------------\n\n/** `AgentController.maxBodyBytes`'s default. */\nexport const DEFAULT_MAX_BODY_BYTES = 4 * 1024 * 1024;\n/** `AgentController.maxHistoryMessages`'s default. */\nexport const DEFAULT_MAX_HISTORY_MESSAGES = 1000;\n/** `AgentController.maxConcurrentRuns`'s default. */\nexport const DEFAULT_MAX_CONCURRENT_RUNS = 5;\n/** The cap on `attach` and `stop` bodies, which carry ids and nothing else. */\nconst SMALL_BODY_BYTES = 64 * 1024;\n\nconst noop = () => {};\n\n/**\n * The runs each `runLimitKey` has going, by lane: a thread is one lane however\n * many turns are queued or superseding on it, and a stateless turn is a lane\n * of its own. A lane is held from the moment its turn is admitted until its\n * last run ends.\n */\nclass RunSlots {\n private byKey = new Map<string, Map<string, number>>();\n\n /**\n * Admits a turn in `lane` for `key`, or answers `null` when `key` already\n * holds `limit` other lanes. Synchronous, so two turns arriving together\n * cannot both see the last free slot. The function it returns frees the\n * turn's hold; calling it twice is harmless.\n */\n take(key: string, lane: string, limit: number): (() => void) | null {\n let lanes = this.byKey.get(key);\n if (!lanes?.has(lane) && (lanes?.size ?? 0) >= limit) {\n return null;\n }\n if (!lanes) {\n lanes = new Map();\n this.byKey.set(key, lanes);\n }\n lanes.set(lane, (lanes.get(lane) ?? 0) + 1);\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = this.byKey.get(key);\n const count = (current?.get(lane) ?? 1) - 1;\n if (!current) return;\n if (count > 0) {\n current.set(lane, count);\n } else {\n current.delete(lane);\n if (current.size === 0) this.byKey.delete(key);\n }\n };\n }\n}\n\n/**\n * Slots are counted per `liveRuns` registry rather than per process: the\n * registry is what holds the runs being counted, and an app (or a test) with\n * two registries has two sets of runs.\n */\nconst runSlots = new WeakMap<object, RunSlots>();\nfunction runSlotsFor(liveRuns: object): RunSlots {\n let slots = runSlots.get(liveRuns);\n if (!slots) {\n slots = new RunSlots();\n runSlots.set(liveRuns, slots);\n }\n return slots;\n}\n\n/**\n * The key that carries `Body` on the instance type.\n *\n * A `declare const` unique symbol, so it exists only in the type layer — the\n * same device `Schema.ts` uses for its output type, and for the same reason: a\n * real property would be one an app could see, serialise or depend on.\n */\ndeclare const BODY: unique symbol;\n\n/**\n * What `authorizeRequest` is told about the request, per route.\n *\n * A union on `route` because `body` exists on only two of them: `stream` and\n * `upload` carry the client's `body` option, `attach` and `stop` carry none.\n * Typing it optional everywhere would make every reader of `body.pageId` on\n * `stream` write a check for a case that cannot happen there; narrowing on\n * `route` says which case it is. An override written against the older\n * `{ route; threadId? }` shape still accepts every member.\n */\nexport type AuthorizeRequestParams<Body extends object = Record<string, unknown>> =\n | { route: \"stream\" | \"upload\"; threadId?: string; body: Body }\n | { route: \"attach\" | \"stop\"; threadId?: string; body?: undefined };\n\nexport abstract class AgentController<\n A extends AnyAgent = AnyAgent,\n /**\n * The extra fields `useChat`'s `body` option sends with every turn, as they\n * arrive in `instructions()` and on `ctx.body`.\n *\n * Declaring it also types the client: `useChat` reads it back off the route\n * through `AgentRouteRPC`, so a `body` the controller does not expect is a\n * compile error at the call site rather than an `undefined` three layers\n * into a tool. It types the shape, not the contents — see `instructions`.\n *\n * Constrained to `object`, not `Record<string, unknown>`: an `interface` gets\n * no implicit index signature, so the tighter bound refused\n * `interface PageBody { pageId: string }` with a `TS2344` that names the\n * constraint and not the reason. An interface is how most apps write a request\n * shape, and turning that into a puzzle about `type` versus `interface` is a\n * poor first impression of the feature.\n */\n Body extends object = Record<string, unknown>,\n> extends ControllerBase {\n static kind = \"agent-controller\" as const;\n\n /**\n * `Body`, in a position nothing can shorten away.\n *\n * It has to appear on the instance type for `AgentRouteRPC` to infer it, and\n * `instructions`'s second parameter is not a safe place to leave that job:\n * TypeScript's parameter-wise inference stops at the shorter signature, so a\n * controller overriding `instructions(req)` — which is every override written\n * before this existed, since that was the only signature — supplied no\n * candidate and silently fell back to the open record. The client-side\n * checking then vanished on the most ordinary upgrade path, with nothing to\n * read.\n *\n * `declare` so it emits no field: there is no value here, only a type for\n * `infer B` to find. Optional and never assigned, so no subclass has to\n * mention it.\n */\n declare readonly [BODY]?: Body;\n\n /** The agent this controller serves. A property rather than a constructor\n * argument so `Router.agent(ChatController)` can take the class, matching how\n * every other controller is mounted. */\n abstract agent: A;\n\n /**\n * Defaults to the process-wide `MemoryAgentStore`.\n *\n * Whatever you put here, make it something that outlives the request: this\n * controller is constructed fresh for every call, so `store = new\n * MemoryAgentStore()` written here is an empty store on every turn and a\n * threaded conversation silently reads back nothing. Assign a module-level\n * instance, or a store whose state is somewhere else entirely.\n */\n store: AgentStore = defaultAgentStore;\n\n /**\n * Defaults to the process-wide map. Overridable so a test — or an app running\n * two agents that must not see each other's runs — can hold its own; not so\n * that it can be moved off the process, which is not a thing that can be\n * done. See `MemoryLiveRuns`.\n */\n liveRuns: MemoryLiveRuns = defaultLiveRuns;\n\n /**\n * Where attachment *records* live — the row that says which bytes, whose, and\n * under what id. Defaults to the process-wide `MemoryAttachmentStore`, with\n * the same warning `store` carries: assign something that outlives the\n * request, because this controller is constructed per call.\n */\n attachments: AttachmentStore = defaultAttachmentStore;\n\n /**\n * Where an attachment's *bytes* live. Defaults to the app's configured\n * `FileStorage` through the `Storage` facade, which resolves the driver per\n * call out of the container — so an app that configured S3 gets S3 here\n * without saying so twice.\n *\n * Overridable mostly for tests and for an app that keeps user uploads in a\n * different bucket from everything else.\n */\n attachmentStorage: AttachmentStorage = Storage;\n\n /**\n * Who uploaded each provider file id (#443). `upload` records the id under\n * `runOwner(req)`, and `stream` refuses a turn whose files name an id\n * recorded for another owner with a 403 `{ error: { kind: \"permission\",\n * message, status } }`. Defaults to the process-wide `MemoryFileOwners`; the\n * same warning as `store` applies — assign something that outlives the\n * request. An app with several processes, or that wants the binding to\n * survive a restart, gives it a table (see `FileOwners`).\n */\n fileOwners: FileOwners = defaultFileOwners;\n\n /**\n * Where the nonce of each answered approval or question is spent, which is\n * what makes a signed answer single-use (#445). On a stateless chat the\n * client carries its history and can rewind it to before a result existed;\n * the spent nonce is then the only thing that refuses the replayed answer.\n *\n * Defaults to the process-wide `MemoryNonceStore`, which is exact for one\n * instance and forgets on restart. An app running several instances (or\n * behind a load balancer whose affinity is best effort) assigns a shared\n * store, built once at module scope like `store`:\n *\n * const nonces = new RedisNonceStore();\n * class ChatController extends AgentController<typeof chat> {\n * nonces = nonces;\n * }\n *\n * or its own `NonceStore` over a table keyed by the nonce. In production a\n * stateless turn served with the in-memory default logs a warning once.\n */\n nonces: NonceStore = defaultNonceStore;\n\n /**\n * Where approved tools' executions are claimed and their results recorded,\n * so that an approval runs its tool at most once (#458). Off by default.\n *\n * The nonce makes an answer single-use; it does not remember what the tool\n * did. So a retried submit whose response was lost is refused (\"already\n * used\") although the tool acted, and an answer that reaches two instances\n * with unshared nonce stores runs the tool twice. With a receipt store the\n * first presentation claims the execution and records its result; a later\n * one gets that result back without running anything, and one that arrives\n * while the first is still running gets a `tool_error` result for the model.\n *\n * Assign one built at module scope, like `nonces`, shared by every instance:\n *\n * const receipts = new RedisReceiptStore();\n * class ChatController extends AgentController<typeof chat> {\n * receipts = receipts;\n * }\n *\n * or your own `ReceiptStore` over a table (see `store/Receipts.ts`).\n * `MemoryReceiptStore` is exact for one instance only.\n */\n receipts?: ReceiptStore;\n\n /**\n * Whether a turn may name a provider file id that `fileOwners` has no record\n * of. `false` by default, which is what keeps the change additive: an id\n * uploaded before the upgrade, before a restart (with the in-memory default),\n * on another process, or by the app outside `upload` still works, as every id\n * did before. An id that IS recorded for someone else is refused either way.\n *\n * Set it to `true` once `fileOwners` is durable and shared, to make the\n * binding complete: then an id is usable only by the owner it was recorded\n * for, or by anyone when it was recorded as anonymous. On a stateless chat\n * the client carries its history, so this also refuses a file a tool attached\n * earlier in the conversation; a strict app keeps its chats on a thread.\n */\n protected requireKnownFiles = false;\n\n /**\n * How long the request that started a run is held open for its hooks, in\n * milliseconds, once the run has settled. The run itself is not bounded\n * here — the request is held for as long as it runs — only the app's code\n * still going after it, from `onMessage` to an `onAwaitingInput` queued\n * behind a slow `onToolCall`.\n *\n * The hooks read the user from that request (`ctx.req.ctx().user`,\n * `Auth.user()`, a policied query), so the request stays open until they are\n * done; but a hook that never settles — a `fetch` with no timeout — would\n * then hold the store, the user and `onRequestEnd` forever, one per turn. Past\n * this the request ends anyway: `onRequestEnd` runs, the user is released,\n * and the hook runs on without one. Thirty seconds is far past a healthy\n * write or notification, so a hook that reaches it is hung rather than slow.\n * Raise it for a hook that is legitimately longer; `Infinity` holds the\n * request until the hooks are done, however long that is.\n */\n protected hookHoldMs = 30_000;\n\n /**\n * Appended to the agent's static instructions for this request — the user's\n * name, tenant, today's date.\n *\n * `body` is what `useChat`'s `body` option sent, with the four keys the wire\n * format owns removed. It is the only way to read it here: this controller\n * consumes the request body itself, so `await req.input()` answers `Body\n * already used` and takes the whole turn down with it.\n *\n * It is client-controlled, exactly like any request body. `Body` types what\n * arrives, it does not check it — a client can send anything, and a tenant id\n * read from here is the client's claim about which tenant it wants, not the\n * middleware's finding about who it is.\n */\n instructions(req: HttpRequest<any, any>, extra: { body: Body }): string | Promise<string> | void {\n void req;\n void extra;\n }\n\n /**\n * What every tool of this turn's run gets as `ctx.context` — the user, the\n * tenant, functions the tools call back into. See `AgentContext`.\n *\n * The run is not given the request, so this is where the request's facts\n * become the run's: read the user the middleware authenticated here, and a\n * tool reads it from `ctx.context` instead of reaching for `req`. Runs after\n * `authorizeRequest()`, once per turn, and before anything is asked of the\n * model.\n *\n * The default is `{}`. An app that gives `AgentContext` a required field must\n * override this: the type of the default cannot see the app's declaration,\n * so forgetting is a tool that finds the field missing, not a compile error.\n *\n * Values from `body` are the client's claim, exactly as in `instructions()`;\n * putting one here does not make it any more trustworthy, only easier to\n * mistake for something the server decided.\n */\n context(req: HttpRequest<any, any>, extra: { body: Body }): AgentContext | Promise<AgentContext> {\n void req;\n void extra;\n return {} as AgentContext;\n }\n\n /**\n * Refuse a turn that arrives without a `threadId`, with a 400\n * `thread_required`, before anything runs.\n *\n * A stateless turn is otherwise open to any caller the route's middleware\n * lets through: the client carries the history, so the model runs, and is\n * billed, as a general-purpose chat. An app whose tools resolve their subject\n * from the thread can make them refuse such a turn, but the model has still\n * been paid for by then.\n *\n * It governs `stream` only. `upload` can still reach the provider without a\n * thread (a `provider` destination); refuse that in `authorizeRequest`.\n */\n protected requireThread = false;\n\n /**\n * The largest JSON body `stream` reads, in bytes (#444). Default 4 MB.\n *\n * A turn is a few kilobytes; even a long stateless chat carrying its whole\n * history is well under a megabyte, since files travel by id and not inline.\n * Without a cap the route read whatever arrived (the production server\n * accepts up to 10 GB), parsed it, and sent it to the provider at the app's\n * expense. A body over it is refused with a 413 `{ error: { kind, message,\n * status, code: \"body_too_large\" } }` before it is parsed, and before\n * `authorizeRequest`. Checked against `Content-Length` when there is one and\n * against the bytes read otherwise, so a chunked body cannot get past it.\n * `attach` and `stop` carry only ids and are held to 64 KB. `Infinity` turns\n * it off.\n */\n protected maxBodyBytes = DEFAULT_MAX_BODY_BYTES;\n\n /**\n * The most messages a stateless turn's client-carried history may hold\n * (#444). Default 1000. A longer one is a 413 `history_too_long` before\n * anything runs. Only `body.messages` counts: a threaded turn reads its\n * history from the store, which the client does not write. Every message is\n * sent to the model on every step, so this bounds what one turn can be billed\n * for as much as `maxBodyBytes` does. `Infinity` turns it off.\n */\n protected maxHistoryMessages = DEFAULT_MAX_HISTORY_MESSAGES;\n\n /**\n * Bounds what each model call of this controller's turns is sent (#473):\n * the latest turns of the thread that fit, cut at a turn start, the cut\n * moving `step` turns at a time so the prompt cache keeps hitting. See\n * `ContextWindowOptions`. `undefined` (the default) uses the agent's own\n * `contextWindow`, if it has one; `false` sends the whole history.\n *\n * The store is untouched: `loadThread` still answers the whole thread, every\n * message is still appended, and `readThread` shows all of it. Unlike\n * `maxHistoryMessages`, which refuses a stateless turn, this applies to\n * threaded and stateless turns alike and refuses nothing.\n *\n * protected contextWindow = { maxTurns: 40, maxTokens: 100_000 };\n */\n protected contextWindow: ContextWindowOptions | false | undefined = undefined;\n\n /**\n * Called before every model call of a turn's run, after the agent's own\n * `prepareStep`, with the request it hands over (`step.messages`,\n * `step.instructions`) and the turn's hook context. Answer `{ messages }`\n * or `{ instructions }` to send something else for that call alone; nothing\n * answered is stored. Not called for a sub-agent's model calls.\n *\n * protected prepareStep(step: PrepareStepContext) {\n * return { messages: windowMessages(step.history, { maxTurns: 20 }).messages };\n * }\n */\n protected prepareStep(\n step: PrepareStepContext,\n ctx: AgentHookContext,\n ): PrepareStepResult | void | Promise<PrepareStepResult | void> {\n void step;\n void ctx;\n }\n\n /**\n * How many runs one caller may have going at once in this process (#444).\n * Default 5. A run outlives the request that started it (so `attach` can\n * find it), which means a client can post a turn and disconnect and the run\n * still bills up to `maxSteps` model calls; without a cap, a thousand posts\n * were a thousand runs.\n *\n * Counted per `runLimitKey` (by default `runOwner`, the authenticated user),\n * and per conversation rather than per request: every turn on one thread is\n * one slot, because a thread holds one run at a time and a new turn there\n * supersedes the old one rather than adding to it. So a user resending\n * mid-answer is never refused; a user with five chats answering at once and\n * starting a sixth is, with a 429 `{ error: { kind: \"rate_limit\", message,\n * status, code: \"too_many_runs\" } }`, after `authorizeRequest` and before the\n * model is asked anything. A slot is freed when the run ends (stopped, timed\n * out, or finished). `Infinity` turns it off.\n */\n protected maxConcurrentRuns = DEFAULT_MAX_CONCURRENT_RUNS;\n\n /**\n * Who `maxConcurrentRuns` counts a turn against (#444). The default is\n * `runOwner`'s answer, the authenticated user; `null` is not counted.\n *\n * An anonymous turn is therefore not limited by default, because there is\n * nothing sound to count it under: a client address is the proxy's unless\n * `GEMI_TRUST_PROXY` is set, which would put every visitor in one bucket, and\n * the session cookie is the visitor's to drop. An app that serves anonymous\n * chats returns its own key here (`ip:${clientIp(req)}` behind a trusted\n * proxy, say), sets `requireThread`, or puts `RateLimitMiddleware` on the\n * route.\n */\n protected runLimitKey(\n req: HttpRequest<any, any>,\n params: { owner: string | null; threadId?: string },\n ): string | null | Promise<string | null> {\n void req;\n return params.owner;\n }\n\n /**\n * Decides whether this caller may use this route, on every one of the four:\n * `stream`, `attach`, `stop` and `upload` (#542). Throw a request breaker\n * (`InsufficientPermissionsError`, say) to refuse; return to let it through.\n *\n * It runs before the route does any work of its own: on `stream`, ahead of\n * the thread's lock and load, `instructions()` and the provider, so a refused\n * turn is not charged for, waits behind no run and does not learn whether its\n * thread exists; on `attach`, before a live run's frames are read.\n *\n * `threadId` is the one the client sent, taken on trust and not yet checked\n * against the store — which is what makes this the place to check that the\n * caller owns it. A thread-scoped app that checks it here on every route\n * keeps a thread's live answer, its stop button and its attachments to its\n * owner. It is `undefined` when the request names no thread: a stateless\n * turn, an upload without one, a stop by `runId` or `clientRunId`.\n *\n * `body` is the client's `body` option — the same object `instructions()`,\n * `context()` and `attachmentScope()` get — on the two routes that carry it,\n * `stream` and `upload` (#603). A chat with no thread and no user names its\n * subject there (a page id, say), and this is where to check that the caller\n * may touch it. `attach` and `stop` carry no body, so it is absent on them;\n * narrow on `route` to read it. Like `threadId` it is the client's claim,\n * unchecked.\n *\n * THE DEFAULT CHECKS `resource`, when there is one, and lets everything\n * through otherwise. An override that also wants it calls\n * `super.authorizeRequest(req, params)`.\n */\n protected authorizeRequest(\n req: HttpRequest<any, any>,\n params: AuthorizeRequestParams<Body>,\n ): void | Promise<void> {\n return this.resource?.authorize(req, params);\n }\n\n /**\n * THE RESOURCE THIS CHAT IS ABOUT, checked on every route by the default\n * `authorizeRequest` (#726): a resource policy's `forAgent`, which names the\n * resource's id in the `body` and the resource a thread belongs to.\n *\n * ```ts\n * resource = PagePolicy.forAgent({\n * body: (body: PageBody) => body.pageId,\n * thread: (threadId) => ChatThread.pageIdOf(threadId),\n * });\n * ```\n *\n * `stream` and `upload` are refused unless the caller may use the resource\n * the body names, and, when they name a thread, unless it is that\n * resource's. `attach` and `stop` are refused unless the caller may use the\n * thread's resource. A refusal is the policy's (a 404 by default), the same\n * for a resource or thread that does not exist. A live run still answers\n * only its `runOwner`.\n */\n protected resource?: AgentResource<Body>;\n\n /**\n * WHO OWNS A RUN THIS REQUEST STARTS, and who a request to `attach` or `stop`\n * one is (#442). An opaque key, compared with `===`; `null` is nobody.\n *\n * `stream` records it on the run, and from then on the run answers only that\n * key: `attach` to it, `stop` of it (by `runId`, `threadId` or `clientRunId`,\n * including a turn still waiting its place), and a turn on its thread that\n * would supersede it while it is still going are each refused with a 403\n * `{ error: { kind: \"permission\", message, status } }` for any other caller.\n * That holds whatever `authorizeRequest` says, which is the point: every\n * handle on a run is one a third party can come to hold (a shared link, a\n * log line, a guessable `clientRunId`), and none of them says whose it is.\n *\n * THE DEFAULT IS THE AUTHENTICATED USER, `user:<id>`, and `null` without one.\n * A `null` owner records an unowned run, which answers whoever holds a\n * handle — exactly what every run did before this existed. So:\n *\n * - an anonymous turn starts an unowned run; its `threadId` stays the\n * capability. `sessionId()` is not used as a fallback: it is a cookie the\n * visitor writes, it can be minted between the turn and the reattach (a\n * view visited in between), and a mismatch would lock a visitor out of\n * their own run. An app with its own anonymous identity returns it here.\n * - a run started by an authenticated user cannot be read or stopped by an\n * anonymous request, nor by another user.\n * - a run the server starts itself (registered on `liveRuns` with no\n * `owner`) is unowned.\n *\n * Override it for anything wider than a user — a thread shared by a team\n * returns `team:<id>` (from the user, never from the body) — or `null` to\n * turn the check off. Whatever it reads must be present on all of `stream`,\n * `attach` and `stop`, the same rule `attachmentScope` states: guard the three\n * routes with the same middleware.\n *\n * It is also the `subject` every pending call of the run is signed for\n * (#447): an approval or answer is accepted only on a turn whose `runOwner`\n * is the one the question was asked of. So it must answer the same on the\n * turn that asks and the turn that answers.\n */\n protected runOwner(req: HttpRequest<any, any>): string | null | Promise<string | null> {\n const user = req.ctx?.()?.user;\n const userId = user?.id ?? user?.publicId;\n if (userId !== undefined && userId !== null && String(userId) !== \"\") {\n return `user:${String(userId)}`;\n }\n return null;\n }\n\n /**\n * STARTS A TURN FROM SERVER CODE (#839): a queue job, a command, an MCP\n * tool, a webhook. No browser and no route: the turn goes through this\n * controller's `stream` as a `useChat` turn would, on a request built here,\n * so the agent, the store, `authorizeRequest` and `resource`, `runOwner`,\n * `maxConcurrentRuns`, the thread's lock, `instructions()`, `context()`,\n * the hooks and the tools' `ctx` (`threadId`, `ctx.jobs`, `ctx.generate`)\n * are the same as for a turn from the chat.\n *\n * ```ts\n * const turn = await ChatController.startTurn({\n * threadId,\n * text: \"Make the hero darker\",\n * user, // req.ctx().user for the turn\n * body: { siteId }, // what useChat's `body` option would send\n * });\n * const { text, finishReason, pending } = await turn.result();\n * ```\n *\n * The route's middleware does not run: the caller is server code and names\n * the user itself (`null` or absent is an anonymous turn). A turn the route\n * would refuse throws an `AgentTurnError` with the status and code it would\n * have answered; a request breaker thrown by `authorizeRequest` is thrown\n * as it is.\n *\n * The run lives in the process that called this, like every run. From a\n * queue job, await `result()` so the worker does not move on without it.\n */\n static async startTurn<C extends AgentController<any, any>>(\n this: new () => C,\n params: AgentTurnParams<ControllerBody<C>>,\n ): Promise<AgentTurn> {\n const { threadId } = params;\n if (typeof threadId !== \"string\" || threadId === \"\") {\n throw new TypeError(\n \"AgentController.startTurn needs a `threadId`: a server turn is stored on a thread. Create one with the store's `createThread`.\",\n );\n }\n const turn: ClientTurn = {\n ...params.turn,\n ...(params.text !== undefined ? { text: params.text } : {}),\n };\n // The app's fields first, so none of them can take the place of the\n // envelope's.\n const payload = { ...(params.body as object | undefined), threadId, turn };\n const req = new HttpRequest<any, any>(\n new Request(SERVER_TURN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(payload),\n }),\n {},\n \"api\",\n new URL(SERVER_TURN_URL).pathname,\n );\n const controller = new this();\n // Marks the request as `startTurn`'s, so only its run is kept here.\n serverTurns.set(req, null);\n // A request scope of its own, carrying the caller's user, whether or not\n // this is called from inside another request: the run is not that\n // request's, and must not end with it or read its user.\n const response = await RequestContext.run(req, () => controller.stream(req), {\n user: params.user ?? null,\n });\n\n const started = serverTurns.get(req);\n if (!started) {\n throw await AgentTurnError.from(response);\n }\n serverTurns.delete(req);\n // Nobody reads the stream; the run goes on without it (see `toResponse`).\n response.body?.cancel().catch(noop);\n\n const { run, hooks } = started;\n let pending: PendingToolCall[] = [];\n // The pending calls are on the `awaiting-input` event, not on the result.\n // The run's frames are buffered from the start, so this misses nothing.\n const watched = (async () => {\n for await (const event of run) {\n if (event.type === \"awaiting-input\") pending = event.pending as PendingToolCall[];\n }\n })().catch(noop);\n\n let result: Promise<AgentTurnResult> | undefined;\n return {\n runId: run.runId,\n threadId,\n run,\n stop: (stopParams) => run.stop(stopParams),\n result: () =>\n (result ??= (async () => {\n const outcome = await run.result();\n // After the transcript is stored and the hooks are done (or\n // `hookHoldMs` passed), so a caller that reads the thread next sees\n // this turn in it.\n await Promise.all([hooks, watched]);\n const messages = outcome.messages as AgentMessage[];\n return {\n ...outcome,\n threadId,\n text: lastAssistantText(messages),\n pending: outcome.finishReason === \"awaiting-input\" ? pending : [],\n };\n })()),\n };\n }\n\n /**\n * `POST /<path>` — one route for every client turn. A first message, an\n * approval, an answer to a question and a client tool's result are all just\n * the next turn, so none of them gets an endpoint of its own.\n */\n async stream(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req, this.maxBodyBytes);\n if (parsed.error) {\n // Before anything is registered or charged for. A run started off a body\n // we could not read would answer nothing, at the user's expense.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId = typeof body.threadId === \"string\" ? body.threadId : undefined;\n const parsedTurn = toClientTurn(body);\n if (parsedTurn.error) {\n return invalidRequest({ body: {}, error: parsedTurn.error });\n }\n // Reassigned by a regenerate: the turn run again is the one the store holds.\n let turn = parsedTurn.turn;\n // Replace the thread's last answer rather than answer after it (#451). Only\n // meaningful on a thread: a stateless client trims its own history.\n const regenerate = threadId !== undefined && body.regenerate === true;\n const clientRunId = typeof body.clientRunId === \"string\" ? body.clientRunId : undefined;\n // The app's fields, separated once and handed to every method that reads\n // them — `authorizeRequest`, `instructions`, `context`, `attachmentScope` —\n // so none of them can disagree about what the client sent. They cannot read\n // it themselves: `readJsonBody` has consumed the request's body by now.\n const extraBody = appBody<Body>(body);\n\n // Before `pendingTurns`, so a refused turn leaves nothing for `/stop` to\n // find. It does not yield, unlike `authorizeRequest` below.\n if (this.requireThread && !threadId) {\n return jsonResponse(400, {\n code: \"thread_required\",\n message: \"This agent takes a turn only on a thread: send a threadId.\",\n });\n }\n\n if (regenerate && !this.store.removeMessages) {\n return jsonResponse(501, {\n code: \"regenerate_unsupported\",\n message:\n \"This agent's store cannot remove messages, so a thread's answer cannot be regenerated. Implement `removeMessages` on the AgentStore.\",\n });\n }\n\n // The client's history is the only part of a stateless turn whose size the\n // client chooses and the model is billed for on every step (#444). A\n // threaded turn's `messages` are ignored, so they are not counted.\n if (\n !threadId &&\n Array.isArray(body.messages) &&\n body.messages.length > this.maxHistoryMessages\n ) {\n return limitResponse(\n 413,\n \"history_too_long\",\n `The conversation has ${body.messages.length} messages; this agent takes at most ${this.maxHistoryMessages}.`,\n );\n }\n\n // Who this run will belong to. Read before `pending` exists, so a stop that\n // finds the pending turn can already be checked against it. See `runOwner`.\n const owner = await this.runOwner(req);\n\n // From here until `register`, the only thing `/stop` can find this turn by.\n // See `pendingTurns`.\n const pending = clientRunId ? { cancelled: false, owner } : null;\n if (pending) {\n pendingTurns.set(clientRunId, pending);\n }\n\n // The whole of the stateless/threaded difference, in one expression: with a\n // thread the server owns the history, without one the client carries it.\n // Nothing else below branches on it, which is why stateless keeps working\n // even for an app that never configures a store.\n //\n // The `threadId` is the client's, and nothing here checks that this caller\n // owns it — `AgentStore` cannot, since it holds no user. A `threadId` is\n // therefore a capability and has to be unguessable (`createThread` mints a\n // uuid) and, for anything that matters, checked: override `authorizeRequest()`\n // or give it a `store` that scopes by `req.user`. The framework's job is to make\n // sure the route is behind the router's middleware in the first place,\n // which `ApiRouter.agent()` now does.\n //\n // Everything from the load on happens inside `start`, which on a thread\n // runs under the thread's lock once the previous run's transcript is in the\n // store — the load has to come after that, or it reads a history the old\n // answer is missing from. `instructions()` follows the load in there rather\n // than running ahead of the lock, so that a dead thread is still a 404\n // before the app's own work is spent on it; the cost is that a turn queued\n // behind this one waits for `instructions()` as well.\n // The run `start` registered, if it got that far: its end is what frees\n // this turn's `maxConcurrentRuns` slot.\n let started: AgentRun | null = null;\n // What a regenerate took out of the thread, kept until the run replacing\n // it has started.\n let removed: AgentMessage[] = [];\n const start = async (): Promise<Response> => {\n try {\n return await startRun();\n } finally {\n // A regenerate that never started its run — stopped while it waited,\n // or a throw from the app's hooks — puts back what it took out, since\n // no new answer is coming to replace it. Still under the thread's lock,\n // and appended at the end, which is where it was: it was the tail.\n if (threadId && removed.length > 0 && (started as AgentRun | null) === null) {\n await this.store\n .appendMessages(threadId, removed)\n .catch((err) => this.reportHookFailure(err));\n }\n }\n };\n const startRun = async (): Promise<Response> => {\n let messages: AgentMessage[];\n // The `<jobs>` block for this turn's system prompt (#461), on a thread\n // that has background jobs.\n let jobsBlock: string | null = null;\n if (threadId) {\n const history = await this.store.loadThread(threadId);\n if (!history) {\n // Before `instructions()` and before the run: nothing has been\n // charged for, and the client has to learn that its thread is gone —\n // expired, mistyped, or on an instance that no longer exists — rather\n // than see it answered as an empty conversation and have this turn\n // persisted under the dead id.\n //\n // That ordering is deliberate. An ownership check belongs in\n // `authorizeRequest()`, which has already run; one left in\n // `instructions()` has not, so a caller holding a uuid learns whether\n // it is live here without the app's say. The id is unguessable, so\n // the load stays above `instructions()`, whose own work (a database\n // read, typically) would otherwise be spent on a thread that is gone.\n // Move it below and that work is spent on every dead id instead.\n return jsonResponse(404, {\n code: \"thread_not_found\",\n message: `Thread ${threadId} does not exist here, or has expired.`,\n });\n }\n // A message a dead run left unfinished is closed here, and written\n // back, before the run is handed the history: the model then reads it\n // as interrupted, and its open calls have results. Under the thread's\n // lock and after the previous run's transcript is stored, so the only\n // unfinished message left is one no run in this process owns.\n const thread = await this.settleThread(threadId, history, { write: true });\n messages = thread.messages;\n jobsBlock = this.jobsBlock(thread.jobs);\n if (regenerate) {\n const cut = regenerationCut(messages);\n if (!cut) {\n return jsonResponse(409, {\n code: \"nothing_to_regenerate\",\n message: `Thread ${threadId} has no user turn to answer again.`,\n });\n }\n // The last user turn and everything after it leave the store, and the\n // turn is run again from what the store held — not from the client's\n // copy, which may be stale or carry local ids. The user message comes\n // back under a new id when the run reports it. Under the thread's\n // lock and after the previous run's transcript is stored, so nothing\n // writes the removed answer back. Each removed message takes its\n // `usage` with it: the thread never holds both answers' costs.\n removed = messages.slice(cut.index);\n await this.store.removeMessages!(\n threadId,\n removed.map((message) => message.id),\n );\n messages = messages.slice(0, cut.index);\n // The stored turn, under the client's `localId` for it: the message\n // is minted again, and the client has to be told the new id (#466).\n turn = turn?.localId ? { ...cut.turn, localId: turn.localId } : cut.turn;\n }\n } else {\n messages = Array.isArray(body.messages) ? (body.messages as AgentMessage[]) : [];\n warnInMemoryNonces(this.nonces);\n }\n\n const instructions =\n [(await this.instructions(req, { body: extraBody })) || undefined, jobsBlock ?? undefined]\n .filter(Boolean)\n .join(\"\\n\\n\") || undefined;\n const context = await this.context(req, { body: extraBody });\n // Above the cancel check, not below it, and that placement is the whole\n // reason this is a separate statement rather than an argument on the call\n // below: the comment on that check says nothing yields between it and\n // `register`, and an `await` for the app's `attachmentScope()` — a\n // database read, in any app that has one — is exactly the yield a stop\n // would land in and be missed.\n const attachments = await this.attachmentsFor(req, threadId, { body: extraBody });\n\n if (pending?.cancelled) {\n // Stopped while it waited. Nothing has been asked of the model and\n // nothing registered, so there is no run to end and nothing charged\n // for. Checked after the last `await` above, so that a stop landing\n // during it is not missed: from here to `register` nothing yields.\n return stoppedBeforeStart();\n }\n\n // Only a threaded turn has anywhere to be written as it runs. See\n // `TurnJournal`.\n const journal = threadId\n ? new TurnJournal(this.store, threadId, messages, (err) => this.reportHookFailure(err))\n : null;\n\n // Chosen here rather than by the run, so the hook context exists before\n // the run does: `redactError` below is handed it, and the run may call\n // it for its first frame.\n const runId = `run_${crypto.randomUUID()}`;\n const ctx: AgentHookContext = { req, runId, threadId };\n\n // The app's `onMessage` for the turn's user message, called while the\n // run goes rather than after it (#806). See `EarlyTurn`.\n const early: EarlyTurn = { id: null, notified: Promise.resolve() };\n\n const run = this.agent.stream({\n runId,\n messages,\n turn,\n threadId,\n // The run reports each message as it finishes it, the user's turn\n // first and before the model is asked anything. Only the store hears\n // about most of them here: the app's `onMessage` runs after the run,\n // in `notifyRun`, except for the turn's own message (below).\n ...(journal ? { onMessage: (message: AgentMessage) => journal.finish(message) } : {}),\n // The turn's user message, once the journal has written it: the app's\n // `onMessage` for it is called now, so whatever the app keeps beside\n // a stored message (where it was sent from, say) is there for a read\n // of the thread while the run is still going (#806). Off the run's\n // path, as the journal is: neither the store nor the hook holds up\n // the model. `notifyRun` waits for it and does not call it again.\n onTurn: (message: AgentMessage) => {\n if (early.id !== null) return;\n early.id = message.id;\n const written = journal ? journal.settled() : Promise.resolve();\n early.notified = written.then(() => this.safely(() => this.onMessage(message, ctx)));\n },\n instructions,\n // Built from this request once, here, and the only thing the run knows\n // about who asked. The run has no request of its own — see\n // `AgentContext` — so a tool that needs the user reads it from this.\n context,\n // Resolved once, above, and handed to every tool of the run as\n // `ctx.attachments`. It is derived from the request — the user the\n // middleware authenticated, or the thread — and never from anything the\n // model can write, which is the property that makes an attachment id\n // safe to give a model at all. `null` for a request with no subject:\n // tools still get an object, and it throws with a sentence naming\n // `attachmentScope()`.\n attachments,\n // The same object `instructions()` was handed, so the two cannot\n // disagree about what the client sent — and carried on the run\n // because a run outlives the request that started it. By the time a\n // tool executes, the body is long gone.\n // Cast because `Body` is constrained to `object` so an `interface` can be\n // used, and an interface has no index signature to satisfy\n // `Record<string, unknown>`. The value is a parsed JSON object either\n // way; the constraint is about what an app may declare, not about what\n // arrives.\n body: extraBody as Record<string, unknown>,\n // What the client, and for a tool's exception the model, is told about\n // a failure. See `redactError`.\n redactError: (error, info) => this.redactError(error, info, ctx),\n // Where answers' nonces are spent. See `nonces`.\n nonces: this.nonces,\n // Where approved tools' executions are recorded. See `receipts`.\n receipts: this.receipts,\n // The principal its pending calls are bound to (#447): an answer is\n // only accepted from the same `runOwner` the question was asked of.\n subject: owner,\n // Background jobs (#461) settle into the thread, so only a threaded\n // turn can start one. The job records who started it.\n ...(threadId ? { jobs: { owner } } : {}),\n // What each model call is sent (#473). Only the request: the store\n // still gets every message through `journal` above.\n ...(this.contextWindow !== undefined ? { contextWindow: this.contextWindow } : {}),\n // Where `contextWindow.compact` keeps this thread's summaries, when\n // the store holds them (#782).\n ...(threadId && isSummaryStore(this.store) ? { summaryStore: this.store } : {}),\n // Only when overridden, so a controller without one adds no call.\n ...(this.prepareStep !== AgentController.prototype.prepareStep\n ? { prepareStep: (step: PrepareStepContext) => this.prepareStep(step, ctx) }\n : {}),\n }) as AgentRun;\n\n // Registered before the response is built: the run is now owned by the\n // process rather than by this request, which is the property `/attach`\n // depends on and the reason a dropped connection no longer cancels\n // anything.\n const eventHooks = this.liveRuns.register(run, {\n threadId,\n // Who may attach to it and stop it from now on. See `runOwner`.\n owner,\n // The client's handle on a run it started, which is the only one that\n // exists before `run-start` reaches it. See `RegisterParams`.\n clientRunId,\n onEvent: (event) => this.dispatchEvent(event, ctx),\n onInternalError: (err) => this.reportHookFailure(err),\n // So the registry's age ceiling never cuts short a run its agent\n // allowed to be longer. See `MemoryLiveRuns.maxAgeMs`.\n maxRunDurationMs: this.agent.maxRunDurationMs,\n });\n\n started = run;\n if (journal) this.follow(run, journal);\n\n // Kept, not just fired: the next turn on this thread has to know when\n // this one's transcript is in the store. See `withThread`. The request\n // waits for more than the thread does — the hooks as well — so that\n // `onMessage` still finds the user who sent the message; the thread\n // waits only for the store, so a slow hook is not a slow next turn.\n const { stored, hooks } = this.persistRun(run, ctx, eventHooks, journal, early);\n persisted.set(run, stored);\n if (serverTurns.has(req)) serverTurns.set(req, { run, hooks });\n // Registered now, while the request is certainly open: `waitUntil` is\n // ignored once it has ended, and the run settling can end it before a\n // single hook has been called.\n req.ctx?.()?.waitUntil(hooks);\n\n return run.toResponse();\n };\n\n try {\n // After `pending` is registered, not before: the app's check is a yield —\n // a database read, typically — and a stop pressed during it has to find\n // this turn. Before the thread's lock, which ends the thread's previous\n // run, so a refused or stopped turn does not end it either.\n await this.authorizeRequest(req, { route: \"stream\", threadId, body: extraBody });\n // After the app's check, so a caller it refuses does not learn which ids\n // are someone's; before the thread's lock, so a refused turn supersedes\n // nothing. The client's history only counts without a thread: with one,\n // `body.messages` is ignored and the history comes from the store.\n const foreign = await this.foreignFile(\n [...(turn?.files ?? []), ...(threadId ? [] : clientHistoryFiles(body.messages))],\n owner,\n );\n if (foreign) {\n return foreign;\n }\n if (pending?.cancelled) {\n return stoppedBeforeStart();\n }\n // After the app's check, so a refused caller spends no slot; before the\n // thread's lock, so a turn over the limit waits behind nothing. No yield\n // between the count and the take: see `RunSlots.take`.\n const limitKey = await this.runLimitKey(req, { owner, threadId });\n const release =\n limitKey === null\n ? noop\n : runSlotsFor(this.liveRuns).take(\n limitKey,\n threadId ? `thread:${threadId}` : `run:${crypto.randomUUID()}`,\n this.maxConcurrentRuns,\n );\n if (!release) {\n return limitResponse(\n 429,\n \"too_many_runs\",\n `You already have ${this.maxConcurrentRuns} conversations answering. Wait for one to finish, or stop it, and send again.`,\n );\n }\n try {\n return threadId ? await this.withThread(threadId, owner, start) : await start();\n } finally {\n // A turn that never started a run (a dead thread, stopped while it\n // waited, a throw) frees its slot now; one that did, when the run ends.\n const run = started as AgentRun | null;\n if (run) {\n run.result().then(release, release);\n } else {\n release();\n }\n }\n } finally {\n if (pending && pendingTurns.get(clientRunId) === pending) {\n pendingTurns.delete(clientRunId);\n }\n }\n }\n\n /**\n * A thread holds one run at a time; a new turn on it ends the old one first.\n *\n * Since a dropped connection no longer stops a run, a user who sends again\n * mid-answer used to leave the first run going. It could not see the new\n * turn, the new run's `loadThread` could not see its answer, and both\n * appended when they finished — in whichever order the model returned them,\n * so the thread read `user2, assistant2, user1, assistant1`. `byThread` then\n * named the second run while the first was still live and unstoppable by\n * `threadId`.\n *\n * Stopping the old run and waiting for its transcript to land is chosen over\n * refusing the new turn with a 409, because sending again *is* the stop: it\n * is what `useChat.send` means, and a client that has to poll `/stop` until\n * the run is really gone before it may post the turn it has already shown is\n * a worse client for no better thread. The cost is that the new turn waits\n * for the old run to unwind, which is as long as its slowest tool in flight —\n * and that wait is the thing that puts `assistant1` before `user2`.\n *\n * The wait is on `persistRun`'s `stored`, not on `run.result()`. `result()`\n * settling is the transcript being final, not stored: `appendMessages` runs\n * after it, and a `loadThread` in that gap reads a history the old answer is\n * missing from, which is the original bug by a shorter route. It is also\n * *only* that: `stored` settles once the transcript is stored, and the app's\n * hooks run on in `hooks`, which holds the old run's request and not the\n * thread, so a slow `onMessage` is not a slow thread and a hung one is not a\n * hung thread.\n *\n * The lock around it is what makes a *third* turn wait for the second rather\n * than for the first. Two turns arriving together both see the same live\n * run, both stop it, both wait for it, and both start — the same race, one\n * message later. Under the lock the later one finds the earlier one\n * registered and stops that instead. Per process, like `LiveRuns`, and for\n * the same reason: the run it guards lives here.\n */\n private async withThread(\n threadId: string,\n owner: string | null,\n fn: () => Promise<Response>,\n ): Promise<Response> {\n const previous = threadLocks.get(threadId) ?? Promise.resolve();\n let release!: () => void;\n const held = new Promise<void>((resolve) => {\n release = resolve;\n });\n const tail = previous.then(() => held);\n threadLocks.set(threadId, tail);\n await previous;\n try {\n const live = await this.liveRuns.find({ threadId });\n if (\n live &&\n this.liveRuns.isRunning(live.runId) &&\n !this.liveRuns.mayAccess(live.runId, owner)\n ) {\n // Superseding is a stop, and someone else's run is not this caller's to\n // stop (#442). Only while it is still going: an ended run is kept for\n // `ttlMs` but a turn after it touches nothing of it. Whether this caller\n // may post on the thread at all is `authorizeRequest`'s question.\n return notYourRun();\n }\n const run = live ? this.liveRuns.get(live.runId) : null;\n if (run) {\n // A run that already ended is still `find`-able for `ttlMs`; stopping\n // it is a no-op and waiting on it is the append it may still be doing.\n run.stop({ reason: \"superseded by a later turn on this thread\" });\n await persisted.get(run);\n }\n return await fn();\n } finally {\n release();\n if (threadLocks.get(threadId) === tail) {\n threadLocks.delete(threadId);\n }\n }\n }\n\n /**\n * `POST /<path>/attach` — subscribe to a run already in progress, from a\n * cursor. This is a read of a live run, not a continuation of a stopped one:\n * the work never paused, the listener changed.\n *\n * The cursor is `from`, else the client's `cursor`, else `Last-Event-ID`,\n * else the oldest frame still buffered — and it is honoured only for the run\n * the client's `runId` names. A cursor the buffer has dropped is a 410 naming\n * what survives; *no* cursor is the tail, because a page reattaching on mount\n * has no transcript to leave a hole in. See `resolveCursor`.\n */\n async attach(req: HttpRequest<any, any> = new HttpRequest()): Promise<Response> {\n const parsed = await readJsonBody(req, SMALL_BODY_BYTES);\n if (parsed.error) {\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n const threadId =\n typeof body.threadId === \"string\" ? body.threadId : searchParam(req, \"threadId\");\n\n if (!threadId) {\n return jsonResponse(400, {\n code: \"invalid_request\",\n message: \"attach needs a threadId: it is the handle that survives a refresh.\",\n });\n }\n\n // Before the lookup: a refused caller learns neither whether a run is live\n // on the thread nor any frame of it.\n await this.authorizeRequest(req, { route: \"attach\", threadId });\n\n // The store is not consulted. This route answers whether a run is in\n // flight here, and a run it finds was started on a thread `stream` had\n // already loaded; a miss is `no_live_run` whether or not the thread exists,\n // because a client that gets one re-reads the thread anyway (see\n // `onAttachMiss`) and learns there. The thread's own 404 is `stream`'s,\n // where a turn would otherwise be persisted under it.\n const live = await this.liveRuns.find({ threadId });\n if (live && !this.liveRuns.mayAccess(live.runId, await this.runOwner(req))) {\n // Another caller's run (#442): none of its frames, ended or not.\n return notYourRun();\n }\n if (!live) {\n // An explicit miss, not a 200 with an empty stream. See `MemoryLiveRuns`:\n // behind a round-robin load balancer this is the common case, and it has\n // to be visible as one.\n return jsonResponse(404, {\n code: \"no_live_run\",\n message: `No run in progress for thread ${threadId} in this process.`,\n });\n }\n\n // A cursor is only a number if you know which run it counts within: `seq`\n // restarts at zero in every run, so honouring a cursor from run_1 against a\n // live run_2 would skip that many frames off the head of a run this client\n // has seen nothing of. `runId` is the client saying which run its cursor\n // means; naming one that is not live forfeits the cursor and takes the\n // tail, which is as close to the start as the buffer can offer.\n //\n // Only a MISMATCH forfeits. An absent `runId` is not a wrong answer, it is\n // an older question: `from` and `Last-Event-ID` predate the pairing and\n // carry no run, and an `EventSource` reconnecting on its own will never\n // grow one. Those keep resuming exactly as before.\n const cursorRunId = typeof body.runId === \"string\" ? body.runId : undefined;\n const cursor = cursorRunId && cursorRunId !== live.runId ? undefined : resolveCursor(req, body);\n\n try {\n return sseResponse(this.liveRuns.replay(live.runId, cursor));\n } catch (err) {\n if (err instanceof FrameCursorEvictedError) {\n // 410 rather than 404: the run is there, the position is not. A client\n // that gets this reloads the thread instead of resuming into a hole.\n return jsonResponse(410, {\n code: err.code,\n message: err.message,\n oldestSeq: err.oldest,\n });\n }\n if (err instanceof LiveRunNotFoundError) {\n // Lost the race with eviction between `find` and `replay`.\n return jsonResponse(404, { code: err.code, message: err.message });\n }\n throw err;\n }\n }\n\n /**\n * `POST /<path>/stop` — the explicit cancel. Since a dropped connection no\n * longer stops a run, this and a later turn on the same thread are the only\n * things that do, and it is why stopping cannot be a client-side concern:\n * the tool loop is here, and a client that stops reading has not stopped\n * step four from charging a card.\n *\n * Returns as soon as the run is aborted, not when it has finished unwinding.\n * The terminal events — the stopped tool results, the aborted message — go\n * out on the run's own stream, so whoever is watching it sees the ending,\n * and `onMessage` records it whether anyone is watching or not.\n *\n * Answers `{ stopped }` normally, and a `Response` only to reject a request\n * it could not read — the union is the error, not a second success shape.\n */\n async stop(\n req: HttpRequest<any, any> = new HttpRequest(),\n ): Promise<{ stopped: boolean } | Response> {\n const parsed = await readJsonBody(req, SMALL_BODY_BYTES);\n if (parsed.error) {\n // `{ stopped: false }` would be the wrong answer as well as the wrong\n // status: it means \"there was nothing to stop\", and the truth is that we\n // could not tell what to stop. A client that believes the first one stops\n // asking, and the run keeps going.\n return invalidRequest(parsed);\n }\n const body = parsed.body;\n\n await this.authorizeRequest(req, {\n route: \"stop\",\n threadId: typeof body.threadId === \"string\" ? body.threadId : undefined,\n });\n\n // Three handles, most specific first, because which ones the client has\n // depends on how far the run got. `runId` is the server's own and settles\n // it. `clientRunId` covers the window before `run-start`, when the client\n // has nothing else for a stateless first turn — and, before that, a turn\n // that has not become a run yet because it is waiting its place on the\n // thread, which is ended where it waits. `threadId` is the fallback for a\n // client that did not start this run at all — one that attached to it,\n // whose replayed tail carried no `run-start`.\n const caller = await this.runOwner(req);\n let runId = typeof body.runId === \"string\" ? body.runId : undefined;\n if (!runId && typeof body.clientRunId === \"string\") {\n runId = this.liveRuns.findByClientRunId(body.clientRunId) ?? undefined;\n if (!runId) {\n const pending = pendingTurns.get(body.clientRunId);\n if (pending) {\n // A `clientRunId` is the client's own choice and only as unguessable\n // as it made it, so the turn it names is checked like a run (#442).\n if (pending.owner !== null && pending.owner !== caller) {\n return notYourRun();\n }\n // Not on to `threadId`: that names the run this turn is queued\n // behind, which is already stopping, and answering for it would\n // leave this one to start.\n pending.cancelled = true;\n return { stopped: true };\n }\n }\n }\n if (!runId && typeof body.threadId === \"string\") {\n runId = (await this.liveRuns.find({ threadId: body.threadId }))?.runId;\n }\n\n const run = runId ? this.liveRuns.get(runId) : null;\n if (!run) {\n // Already finished, already evicted, or never here. Not an error: the\n // caller wanted the run stopped and it is not running.\n return { stopped: false };\n }\n if (!this.liveRuns.mayAccess(run.runId, caller)) {\n // Someone else's run, by whichever handle (#442). See `runOwner`.\n return notYourRun();\n }\n\n run.stop({ reason: typeof body.reason === \"string\" ? body.reason : undefined });\n\n // Deliberately not awaiting `run.result()`. Unwinding means letting tools\n // in flight settle into `denied` results and finalizing the assistant\n // message, which can take as long as the slowest tool — and a stop button\n // that spins for twenty seconds is a stop button people press twice.\n return { stopped: true };\n }\n\n /**\n * WHO A SCOPE BELONGS TO, and the one question in this file whose wrong\n * answer is a data leak rather than a bug.\n *\n * An attachment id given to the model comes back *from* the model, and what\n * the model writes is a function of everything it read — the user's text, a\n * tool's output, a document someone uploaded. So the id is untrusted in\n * exactly the way a request body is, and the scope it resolves under must come\n * from the server's own knowledge of the request. Nothing that reaches this\n * method may be readable or writable by the model: `req` is the HTTP request,\n * and `threadId` is the client's handle, not the model's.\n *\n * THE DEFAULT IS THE AUTHENTICATED USER, falling back to the thread, falling\n * back to `null`.\n *\n * - `user:<id>` when the request is authenticated. `req.ctx().user` is what\n * `AuthenticationMiddleware` and the `Auth` facade put there, so an agent\n * route behind `middlewares = [\"auth\"]` — which `ApiRouter.agent()` makes\n * the default posture — has a subject without the app writing anything.\n * - `thread:<id>` for an unauthenticated chat that has a thread. A `threadId`\n * is minted by `createThread` as a uuid and is documented as a capability,\n * and `upload` only passes one here that `store.loadThread` finds;\n * an anonymous support widget has nothing better, and scoping to the\n * conversation is strictly narrower than scoping to nothing.\n * - `null` otherwise, which means no attachment id is minted at all. There is\n * no third fallback on purpose. `sessionId()` is the tempting one and it is\n * the wrong one: it is a cookie the visitor writes, documented as *not a\n * credential*, so scoping to it is scoping to a value the caller chooses —\n * which is not a scope, it is a lookup key with extra steps.\n *\n * WHAT THIS DEFAULT GETS WRONG, since it will get something wrong for someone:\n * it is per user, not per conversation, so a user's own upload from one thread\n * resolves in another thread of theirs. That is the loose direction, and it is\n * chosen because the tight one breaks the flow the framework actually ships —\n * `useChat.uploadFile` posts a file before any thread exists, so a per-thread\n * default would make the first upload of every conversation unresolvable. An\n * app that wants per-conversation isolation returns\n * `{ key: \\`user:${id}:thread:${threadId}\\` }` here and has it; an app with\n * tenants returns `{ key: \\`org:${orgId}\\` }` and has that. What the default\n * must never be is broader than a user, and it is not.\n *\n * WHATEVER THIS READS MUST BE PRESENT ON EVERY AGENT ROUTE, and the default\n * reads `req.ctx().user`, which is present only where authentication\n * middleware ran. `agent()` mounts four routes and `.middleware()` guards\n * them individually, so `middleware({ stream: \"auth\" })` — the example in\n * `ApiRouter.agent`'s own doc — leaves `POST /chat/files` unauthenticated.\n * The upload then files the record under `thread:<id>` (or nothing at all)\n * while the run that follows, on the guarded route, resolves under\n * `user:<id>`, and every id minted on upload is a miss for the rest of the\n * conversation. It fails as `AttachmentNotFoundError`, worded identically to\n * an id the model invented, which is the point of that error and is also why\n * this particular misconfiguration is invisible. Guard `upload` and `stream`\n * together, or derive the key from something both of them have.\n *\n * gemi does not detect the skew for you, and the reason is the module's whole\n * premise: noticing that an id exists under a *different* scope requires\n * looking it up without one, and an unscoped read is the thing that must not\n * exist here — not even behind a `console.warn`. So the answer is the\n * documentation you are reading and the identical error, not a probe.\n *\n * THE BODY, AND THE ONE RULE FOR READING IT (#603). The third argument is the\n * client's `body` option — what `instructions()` gets — on both routes that\n * resolve a scope: `stream`, and `upload`, where `useChat.uploadFile` sends\n * the same option beside the file. It exists for the chat that has neither a\n * user nor a thread, a stateless page builder say, whose subject is only in\n * the body:\n *\n * protected async attachmentScope(req, threadId, { body }) {\n * const scope = await super.attachmentScope(req, threadId);\n * if (scope) return scope;\n * if (typeof body.pageId !== \"string\") return null;\n * const page = await Page.findFirst({ where: { publicId: body.pageId } });\n * return page ? { key: `page:${page.publicId}` } : null;\n * }\n *\n * The `typeof` line is not tidiness. `Body` types the shape, not the contents,\n * and to an ORM `{ publicId: undefined }` is no filter at all: a request that\n * leaves `pageId` out would find the first page in the table and be filed\n * under it, along with every other request that leaves it out.\n *\n * A body field is a value the caller chose, which is exactly what the\n * `sessionId()` paragraph above refuses. What separates the keys this may be\n * built from is not whether the client sent them — `threadId` is sent by the\n * client too — but WHETHER THE VALUE IS AN UNGUESSABLE CAPABILITY WHOSE\n * EXISTENCE THE SERVER CHECKS. A page `publicId` that is looked up, as above,\n * is one, on the same footing as a `threadId` that `loadThread` finds: holding\n * it is what entitles the caller to the page, and an id nobody minted resolves\n * to nothing. `body.orgId` in an app with users is NOT one, and passing the\n * body is precisely what makes `` { key: `org:${body.orgId}` } `` spellable: an\n * org id is enumerable and the caller may not belong to that org, so that is\n * every tenant's files handed to whoever types another tenant's id. A tenant\n * comes from `req.ctx().user`, never from here. And a value interpolated\n * without being looked up is the `sessionId()` mistake again, however\n * unguessable it looks — an anonymous caller then mints a fresh scope per\n * request. Look it up, and key on what the lookup returned.\n *\n * The same skew rule as above applies to the body, and more quietly: the key\n * must come out the same on `upload` and on `stream`. `useChat` sends the one\n * `body` option to both, so a key derived from a field that stays put for the\n * whole conversation — the page, not the selected element — agrees by\n * construction. One derived from a field that changes between the upload and\n * the turn does not, and fails as that same `AttachmentNotFoundError`.\n *\n * The third argument is new, and the method keeps its first two, so an\n * override written as `attachmentScope(req, threadId)` works unchanged; one\n * that calls `super.attachmentScope(req, threadId)` may leave it off too.\n *\n * The key is opaque and compared with `===`. It is never sent to the client\n * and never shown to the model.\n */\n protected attachmentScope(\n req: HttpRequest<any, any>,\n threadId?: string,\n extra?: { body: Body },\n ): AttachmentScope | null | Promise<AttachmentScope | null> {\n void extra;\n const user = req.ctx()?.user;\n const userId = user?.id ?? user?.publicId;\n if (userId !== undefined && userId !== null && String(userId) !== \"\") {\n return { key: `user:${String(userId)}` };\n }\n if (threadId) {\n return { key: `thread:${threadId}` };\n }\n return null;\n }\n\n /**\n * WHAT THIS ROUTE ACCEPTS AT ALL: a size ceiling and a list of types (#683).\n * Checked once per upload, after `authorizeRequest` and before anything is\n * stored or sent to the provider, and a file outside them is answered **422**\n * with `{ error: { code, message } }` — `file_too_large` or\n * `unsupported_file_type` — which `useChat().attach()` rejects with as an\n * `AttachError`, so a composer can mark the one file.\n *\n * `accept` reads like an `<input accept>`: `\".pdf\"` matches the file name's\n * extension, `\"image/*\"` a type family, `\"text/csv\"` one type. A file\n * matching any entry is accepted. Left out (or `null` returned, the default)\n * means no limit of that kind, which is how the route behaved before.\n *\n * Here rather than in `attachmentDestination`, which an app could throw from\n * to the same end: a throw there is a 500 unless the app builds the response\n * itself, and the provider's own refusal only arrives after the bytes were\n * stored. A limit is a rule about the file, so it is answered before either.\n *\n * protected attachmentLimits() {\n * return { maxBytes: 10 * 1024 * 1024, accept: [\".pdf\", \"image/*\"] };\n * }\n */\n protected attachmentLimits(\n req: HttpRequest<any, any>,\n ): AttachmentLimits | null | Promise<AttachmentLimits | null> {\n void req;\n return null;\n }\n\n /**\n * THE APP'S OWN RULE ABOUT ONE UPLOAD (#836): a storage quota, a per-subject\n * cap, anything that needs the file and the request's subject at once.\n * Called once per upload, after `authorizeRequest` and `attachmentLimits` and\n * before anything is stored or sent to the provider.\n *\n * It is told what the file is (`name`, `size`, `mimeType`) and what the\n * upload is about: `body`, the client's `body` option exactly as\n * `attachmentScope` gets it, and `threadId` when the store knows the thread.\n * Return nothing to let the file through, or an `UploadRefusal` to refuse it:\n * the route answers **422** with `{ error: { code, message } }` (`code`\n * defaults to `\"upload_refused\"`), and `useChat().attach()` rejects with an\n * `AttachError` carrying both, as it does for `attachmentLimits`' refusals.\n * A `RequestBreakerError` thrown here is answered as itself; anything else\n * thrown is a 500.\n *\n * protected async checkUpload(file, req, { body }) {\n * if (typeof body.pageId !== \"string\") return;\n * const page = await Page.findFirst({ where: { publicId: body.pageId } });\n * if (!page) return;\n * const used = await storageUsedBy(page);\n * if (used + file.size > capFor(page)) {\n * return { code: \"storage_full\", message: \"This site's storage is full.\" };\n * }\n * }\n *\n * The `body` rule from `attachmentScope` applies here too: it types the\n * shape, not the contents, so check a field before looking it up, and\n * decide whose quota to charge from what the lookup returned.\n *\n * Here rather than in `attachmentDestination`, which also sees the file: a\n * quota is a rule about the file and its subject, not about where the bytes\n * go, and a throw there is a 500 unless the app builds the response itself.\n *\n * A check here is not a reservation: two uploads checked at the same moment\n * both see the old usage. A cap that must never be exceeded by one file is\n * enforced where usage is recorded.\n */\n protected checkUpload(\n file: UploadCheckFile,\n req: HttpRequest<any, any>,\n ctx: UploadContext<Body>,\n ): UploadRefusal | null | void | Promise<UploadRefusal | null | void> {\n void file;\n void req;\n void ctx;\n }\n\n /**\n * WHERE ONE FILE'S BYTES SHOULD GO. Called once per upload, with the file in\n * hand, and since #836 with the same `{ body, threadId }` that `checkUpload`\n * gets as a third argument. An override written as\n * `attachmentDestination(file, req)` works unchanged.\n *\n * The model needs to perceive a file only for vision or document reading; a\n * tool needs the bytes only to forward them. Those are different needs and\n * they were being answered the same way, because `upload` sent everything to\n * the vendor unconditionally — which is a cost and a data-minimisation problem\n * as much as a capability one. A CSV that exists to be imported belongs in\n * storage and not at the provider; an image the model must look at and no tool\n * will forward is the reverse.\n *\n * THE DEFAULT IS `\"both\"`, AND THE JUSTIFICATION IS THE FAILURE MODE, not the\n * hit rate. A mimeType table was the obvious alternative — images and PDFs to\n * the provider, everything else to storage — and it is wrong in the quiet\n * direction. Getting `\"both\"` wrong sends a file to a vendor that did not need\n * it: it costs money, it is visible on an invoice and in the vendor's file\n * list, and it is corrected by overriding one method. Getting `\"storage\"`\n * wrong drops the file out of the model's view with no error anywhere; the\n * model answers as though the image were not there, which is indistinguishable\n * from a bad prompt, and the developer debugs their instructions for an\n * afternoon. Being wrong on the invoice beats being wrong in a way that\n * presents as \"the AI is stupid\".\n *\n * `\"both\"` is also what keeps this change additive: every upload that reached\n * the provider before still reaches it, and storage is added underneath. An\n * app that never asks for an attachment id sees no difference except a second\n * copy it owns.\n *\n * A client may ask, per file, for `\"storage\"` under a `\"both\"` policy — the\n * one direction that only ever removes the vendor. It may not ask for\n * anything else, including `\"provider\"`, which would let a form field decide\n * that the app does not keep its own copy. See `narrowDestination`.\n */\n protected attachmentDestination(\n file: File,\n req: HttpRequest<any, any>,\n extra?: UploadContext<Body>,\n ): AttachmentDestination | Promise<AttachmentDestination> {\n void file;\n void req;\n void extra;\n return \"both\";\n }\n\n /**\n * The attachment handle for this request — the object a tool is given.\n *\n * `null` when `attachmentScope` says the request has no subject, and a caller\n * that gets `null` must not fall back to anything: there is no unscoped handle\n * to fall back to, which is the point.\n *\n * Issue #490 hangs `ctx.attachments` off this.\n */\n protected async attachmentsFor(\n req: HttpRequest<any, any>,\n threadId?: string,\n extra: { body: Body } = { body: {} as Body },\n ): Promise<ScopedAttachments | null> {\n const scope = await this.attachmentScope(req, threadId, extra);\n if (!scope) {\n return null;\n }\n return new ScopedAttachments(this.attachments, this.attachmentStorage, scope);\n }\n\n /**\n * `POST /<path>/files` — takes an attachment and answers the handles for it.\n *\n * `fileId` IS STILL IN THE ANSWER AND STILL MEANS THE SAME THING: the\n * provider's id for the file, the thing a `FilePart` carries, unchanged. It\n * has to stay, because it is what makes vision work and what\n * `useChat.uploadFile` already reads; `attachmentId` is added beside it rather\n * than in place of it. The two are not interchangeable, and swapping them\n * would reach the vendor as a file id it has never issued — so\n * `toResponsesInput` rejects a `gemi_att_` prefix in `FilePart.fileId` with a\n * sentence saying so, rather than leaving it to whatever the vendor answers\n * (not measured).\n *\n * `fileId` is absent exactly when the file did not go to the provider, which\n * only happens when the app or the client asked for that. `attachmentId` is\n * absent when there was no scope to file the record under — see\n * `attachmentScope` — and the answer then carries `downgraded: \"no_scope\"`,\n * which is the only thing separating that case from a controller that chose\n * `\"provider\"` on purpose. Both answer `destination: \"provider\"`, because both\n * are true about where the bytes went.\n *\n * ORDER: storage first, then the provider. If the second one fails the request\n * fails either way, so the only question is where the orphan is left, and an\n * orphan in our own bucket is ours to sweep on a schedule we set, while an\n * orphan at the vendor sits under a retention policy that is not ours.\n */\n async upload(req: HttpRequest<any, any> = new HttpRequest()): Promise<UploadResult> {\n const form = await req.rawRequest.formData();\n const file = form.get(\"file\");\n if (!(file instanceof Blob)) {\n throw new Error(\"upload expects a multipart body with a `file` field.\");\n }\n const name = file instanceof File && file.name ? file.name : \"upload\";\n const mimeType = file.type || \"application/octet-stream\";\n\n // The client's `body` option, as one JSON part beside the file (#603), so\n // `authorizeRequest` and `attachmentScope` see here what they see on\n // `stream`. Read off the form already parsed: the request's body is\n // consumed, and an override cannot read it again. A malformed part is\n // refused before anything else runs, as a malformed turn is on `stream`.\n const extraBody = uploadAppBody<Body>(form.get(\"body\"));\n\n // The client's thread, read here only so an unauthenticated chat has\n // something to scope to. It is the client's own handle — `stream` already\n // takes it on trust for the whole conversation — and it is not the model's:\n // this is a form field on an HTTP request the user's browser made, not a\n // tool argument.\n //\n // It is only passed on if the store knows it. `stream` answers\n // `thread_not_found` for an id it has never seen, and this route must not\n // be looser: an invented id would otherwise be a scope, and an anonymous\n // caller could keep writing to storage by sending a fresh one each time.\n const threadField = form.get(\"threadId\");\n // The field as sent, before the store is asked about it, so a refused\n // caller does not learn whether the thread exists.\n await this.authorizeRequest(req, {\n route: \"upload\",\n threadId: typeof threadField === \"string\" && threadField.length > 0 ? threadField : undefined,\n body: extraBody,\n });\n // Before the thread is looked up, the policy is asked, or a byte is kept:\n // a file this route never takes costs nothing past this line.\n const refusal = limitRefusal(await this.attachmentLimits(req), file, name, mimeType);\n if (refusal) {\n throw new LimitedUploadError(refusal.code, refusal.message);\n }\n\n const threadId =\n typeof threadField === \"string\" &&\n threadField.length > 0 &&\n (await this.store.loadThread(threadField)) !== null\n ? threadField\n : undefined;\n\n // Who the provider's copy will belong to (#443): the same key that owns a\n // run this caller starts, so the turn that names the file finds it its own.\n const owner = await this.runOwner(req);\n const recordOwner = (fileId: string) =>\n this.fileOwners.record(fileId, {\n owner,\n name,\n mimeType,\n size: file.size,\n createdAt: new Date().toISOString(),\n });\n\n // The app's own rule about this file and its subject (#836), still before\n // anything is kept or sent.\n const uploadContext: UploadContext<Body> = { body: extraBody, threadId };\n const appRefusal = await this.checkUpload(\n { name, size: file.size, mimeType },\n req,\n uploadContext,\n );\n if (appRefusal) {\n throw new LimitedUploadError(appRefusal.code || \"upload_refused\", appRefusal.message);\n }\n\n const policy = await this.attachmentDestination(file as File, req, uploadContext);\n const destination = narrowDestination(policy, form.get(\"destination\"));\n\n const scope = await this.attachmentScope(req, threadId, { body: extraBody });\n\n // The app's policy wanted a copy of these bytes and the request has no\n // subject to file them under. Recorded rather than merely warned about,\n // because the answer has to be able to tell the client that what it is\n // getting is not the policy — see `UploadResult.downgraded`.\n const downgraded = destination !== \"provider\" && !scope;\n if (downgraded) {\n if (destination === \"storage\") {\n // Bytes were asked to be kept and there is nobody to keep them for.\n // Storing them anyway files them under a scope every caller shares, and\n // answering nothing is an upload that silently did not happen. Neither\n // is an answer; this is.\n throw new Error(\n 'This upload was routed to storage, but `attachmentScope()` returned null for the request, so there is no subject to file the attachment under. Guard the route (`this.agent(Chat).middleware({ upload: \"auth\" })`), send a `threadId` with the upload, or override `attachmentScope()`.',\n );\n }\n // Policy said `both` and the request has no subject: fall through to the\n // provider alone, which is exactly what this route did before attachments\n // existed. Downgrading rather than throwing is what keeps an\n // unauthenticated chat working across the upgrade — but a downgrade nobody\n // is told about is the failure mode this file keeps arguing against, so it\n // is warned once per process on the server and marked `downgraded` in the\n // answer, so the client can tell this apart from a deliberate\n // provider-only policy.\n warnUnscopedUploadOnce();\n }\n\n if (destination === \"provider\" || !scope) {\n // Identical to the pre-attachment behaviour, down to the answer's\n // `fileId` — plus `downgraded` when this path was not the app's choice.\n const fileId = await providerUpload(this.agent.provider, file as File);\n await recordOwner(fileId);\n const answer: UploadResult = {\n fileId,\n name,\n mimeType,\n size: file.size,\n destination: \"provider\",\n };\n if (downgraded) {\n answer.downgraded = \"no_scope\";\n }\n return answer;\n }\n\n const attachmentId = newAttachmentId();\n const objectName = await this.attachmentStorage.put({\n name: attachmentObjectName(attachmentId, name),\n body: file,\n contentType: mimeType,\n });\n\n const fileId =\n destination === \"both\" ? await providerUpload(this.agent.provider, file as File) : undefined;\n if (fileId) {\n await recordOwner(fileId);\n }\n\n const record: Attachment = {\n id: attachmentId,\n scopeKey: scope.key,\n fileId,\n objectName,\n name,\n mimeType,\n size: file.size,\n createdAt: new Date().toISOString(),\n destination,\n };\n await this.attachments.put(scope, record);\n\n return { fileId, attachmentId, name, mimeType, size: file.size, destination };\n }\n\n /**\n * The 403 for a turn naming a provider file id that is not this caller's, or\n * `null` when every id may be used (#443). See `fileOwners`.\n *\n * Only `fileId` is checked: an `attachmentId` is resolved under the request's\n * own scope, so another user's is already a not-found (`ScopedAttachments`).\n * An entry carrying the caller's own `attachmentId` beside a foreign `fileId`\n * is refused all the same — the `fileId` is what reaches the provider.\n */\n private async foreignFile(\n files: { fileId?: string }[],\n caller: string | null,\n ): Promise<Response | null> {\n const ids = new Set(\n files.map((file) => file.fileId).filter((id): id is string => typeof id === \"string\"),\n );\n for (const fileId of ids) {\n const record = await this.fileOwners.get(fileId);\n if (record ? record.owner !== null && record.owner !== caller : this.requireKnownFiles) {\n // The same sentence for a file that is someone else's and, in strict\n // mode, one nobody recorded: which of the two it is would tell a caller\n // probing ids that the id exists.\n return notYourFile();\n }\n }\n return null;\n }\n\n /**\n * Protected, not private: these exist to be overridden. `onMessage` fires for\n * every completed message, user and assistant alike, and is the intended\n * persistence point for an app that is not using `store`.\n *\n * Once per message, in the transcript's order. The turn's own user message\n * is handed over while the run is still going: on a thread once the store\n * has it, and before the model's answer, so whatever the app keeps beside it\n * is there for a read of the thread during a long run (#806). Every other\n * message is handed over after the run, as before. A run that fails or is\n * stopped after taking the turn in has still reported it.\n *\n * Every hook runs inside the request that started the run, which is held\n * open for them — after the run, and after a client that left — so\n * `ctx.req.ctx().user` is the user who sent the turn. See `hookHoldMs` for\n * how long a hook that does not finish keeps it.\n */\n protected onMessage(message: AgentMessage, ctx: AgentHookContext): void | Promise<void> {\n void message;\n void ctx;\n }\n\n protected onToolCall(\n call: { toolCallId: string; name: string; input: unknown },\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void call;\n void ctx;\n }\n\n /** Fires before the stream ends `awaiting-input` — where to notify whoever\n * has to approve, if they are not the person watching the stream. */\n protected onAwaitingInput(\n pending: PendingToolCall[],\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void pending;\n void ctx;\n }\n\n /**\n * What the client is told about a failure: the run's `error` frame, and the\n * result of a tool that threw, which the model reads too and the store\n * keeps. Return the error to send.\n *\n * The default (`redactError` from `gemi/ai`) keeps `code`, `retryable` and\n * `toolCallId` and replaces every message gemi did not write with a fixed\n * sentence for its code: a provider's error body names resources,\n * deployments and request ids, and an exception's text can be a connection\n * string. A tool that throws a `ToolError` keeps its message. The full\n * detail is in `info` (`info.failure` for the run, `info.cause` for a\n * tool), in the log, on `result().error`, and in `onError`, which is handed\n * the unredacted error.\n *\n * Override it to show more, for instance everything in development:\n *\n * protected redactError(error, info, ctx) {\n * if (process.env.NODE_ENV === \"development\") return error;\n * return super.redactError(error, info, ctx);\n * }\n *\n * Only the `AgentError` fields of what it returns are sent. One that throws\n * is reported and the default is used instead.\n */\n protected redactError(\n error: AgentError,\n info: ErrorRedactionInfo,\n ctx: AgentHookContext,\n ): AgentError {\n void ctx;\n return redactError(error, info);\n }\n\n /**\n * A failure on the run's stream, unredacted: the provider's own message,\n * and the HTTP `status` and `requestId` when there were any. The client was\n * sent `redactError`'s copy.\n */\n protected onError(error: AgentError, ctx: AgentHookContext): void | Promise<void> {\n void error;\n void ctx;\n }\n\n protected onStreamComplete(\n result: AgentRunResult<ToolShapesOf<A[\"tools\"]>, any>,\n ctx: AgentHookContext,\n ): void | Promise<void> {\n void result;\n void ctx;\n }\n\n /**\n * WHAT HAPPENS WHEN A HOOK THROWS: it is reported and the run carries on.\n *\n * The alternative is to fail the run, and that trade is not close. These\n * hooks are an app's persistence and notification points; the run is a model\n * call the user has already been charged for and whose tools may already have\n * charged a card. Letting a failed `INSERT` in `onMessage` abort a generation\n * mid-sentence loses the answer as well as the row, and the user cannot\n * retry into a better outcome. So the answer survives and the failure is\n * logged.\n *\n * It is logged rather than routed to `onError`: `onError` is itself a hook,\n * and a hook that throws inside the handler for hooks that throw is a loop.\n * Override this to send it somewhere with a pager attached.\n */\n protected reportHookFailure(error: unknown): void {\n console.error(\"[gemi/ai] agent controller hook failed\", error);\n }\n\n private async dispatchEvent(event: AgentStreamEvent, ctx: AgentHookContext): Promise<void> {\n switch (event.type) {\n case \"tool-call\":\n // Skipped while the arguments are still streaming: a hook that fires\n // per token would fire with a half-parsed input, which is worse than\n // firing late. And skipped for a re-sent frame, which carries a parked\n // sub-run's record on a call this hook has already seen — once per call\n // is the contract, and a run that re-parks would otherwise fire it for\n // a call some earlier run made.\n if (!event.part.partial && !event.resent) {\n await this.onToolCall(\n {\n toolCallId: event.part.toolCallId,\n name: String(event.part.name),\n input: event.part.input,\n },\n ctx,\n );\n }\n return;\n case \"awaiting-input\":\n await this.onAwaitingInput(event.pending as PendingToolCall[], ctx);\n return;\n case \"error\":\n // The frame carries the redacted copy; the hook is server-side and\n // gets what it was made from.\n await this.onError(unredactedError(event.error), ctx);\n return;\n default:\n return;\n }\n }\n\n /**\n * The thread as a client should see it: the store's history, with any\n * assistant message a dead run left unfinished marked `interrupted` (#617).\n *\n * For the app's own route that hands a thread to `useChat` (or a native\n * session) as its initial messages. A message whose run is still going here\n * is left as it is, still being written, so the client attaches to it. `null`\n * for a thread the store does not have, as `loadThread` answers.\n *\n * It does not write: the next turn on the thread settles the same messages\n * the same way and stores them then, under the thread's lock.\n */\n async readThread(threadId: string): Promise<AgentMessage[] | null> {\n const history = await this.store.loadThread(threadId);\n return history ? (await this.settleThread(threadId, history, { write: false })).messages : null;\n }\n\n /**\n * Whether the run that was writing a message is still going, so the message\n * is in progress rather than interrupted.\n *\n * The default asks this process's `liveRuns`, which is the whole answer on a\n * single instance: a run lives in the process that started it, and a run\n * that is not there died with an earlier one. A finished run still within\n * `ttlMs` counts as live, since its final write may not have landed yet.\n *\n * Behind several instances it is not the whole answer. A run on another\n * instance is not in this map, so its message reads as interrupted here\n * until that run's own writes replace it. Knowing better needs a lasting\n * record of running runs (#459); override this to consult one.\n */\n protected isRunLive(runId: string, threadId: string): boolean | Promise<boolean> {\n void threadId;\n return this.liveRuns.get(runId) !== null;\n }\n\n private async settleThread(\n threadId: string,\n history: AgentMessage[],\n { write }: { write: boolean },\n ): Promise<{ messages: AgentMessage[]; jobs: AgentJobRecord[] }> {\n const isLive = (runId: string) => this.isRunLive(runId, threadId);\n const interrupted = await settleInterrupted(history, isLive);\n let messages = interrupted.messages;\n let jobs: AgentJobRecord[] = [];\n const settled = new Map(interrupted.settled.map((message) => [message.id, message]));\n\n // Background jobs (#461): each `running` tool result gets its job's\n // current state, and the ones that settled are written back with the\n // rest. A job store that cannot be read leaves the results `running`,\n // which is what the model saw last time, rather than failing the turn.\n if (hasRunningResult(messages) || write) {\n try {\n const overlaid = await overlayJobs(messages, {\n threadId,\n store: AgentJobs.store,\n isRunLive: isLive,\n outputSchemaFor: (name) => this.toolOutputSchema(name),\n scan: this.jobsBlockMax(),\n });\n messages = overlaid.messages;\n jobs = overlaid.jobs;\n for (const message of overlaid.settled) settled.set(message.id, message);\n if (write && overlaid.orphans.length > 0) {\n await markOrphans(AgentJobs.store, overlaid.orphans, (err) =>\n this.reportHookFailure(err),\n );\n const orphans = new Set(overlaid.orphans.map((record) => record.id));\n jobs = jobs.map((record) =>\n orphans.has(record.id) ? { ...record, orphaned: true as const } : record,\n );\n }\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n\n if (write && settled.size > 0) {\n try {\n await this.store.appendMessages(threadId, [...settled.values()]);\n } catch (err) {\n // The run still gets the settled history. The store keeps the\n // unfinished copy, and the next turn settles it the same way again.\n this.reportHookFailure(err);\n }\n }\n return { messages, jobs };\n }\n\n /** The agent's `jobs.contextBlock.max`, or 0 for no block. */\n private jobsBlockMax(): number {\n const block = (this.agent as { jobs?: { contextBlock?: { max?: number } | false } }).jobs\n ?.contextBlock;\n if (block === false) return 0;\n return block?.max ?? DEFAULT_JOBS_CONTEXT_MAX;\n }\n\n private jobsBlock(jobs: AgentJobRecord[]): string | null {\n return renderJobsBlock(jobs, this.jobsBlockMax());\n }\n\n /** A tool's output schema, by name, for checking a background job's output. */\n private toolOutputSchema(name: string): Schema<any> | undefined {\n const visit = (entries: readonly unknown[]): Schema<any> | undefined => {\n for (const entry of entries) {\n const tool = entry as { name?: string; outputSchema?: Schema<any>; tools?: unknown[] };\n if (Array.isArray(tool.tools)) {\n const found = visit(tool.tools);\n if (found) return found;\n } else if (tool.name === name) {\n return tool.outputSchema;\n }\n }\n return undefined;\n };\n return visit((this.agent as { tools?: readonly unknown[] }).tools ?? []);\n }\n\n /**\n * Feeds the run's frames to its journal as they are emitted.\n *\n * A subscriber of its own on `run.frames()` rather than a ride on the\n * `onEvent` chain: that chain waits for the app's hooks, and a slow\n * `onToolCall` must not be what decides whether a tool call was stored\n * before the process died. `frames()` is a read of the run's own buffer, the\n * one `toResponse` already reads beside `liveRuns`, so a third reader costs a\n * cursor and nothing else.\n */\n private follow(run: AgentRun, journal: TurnJournal): void {\n void (async () => {\n try {\n for await (const frame of run.frames()) journal.frame(frame);\n } catch (err) {\n this.reportHookFailure(err);\n }\n })();\n }\n\n /**\n * Runs after the stream is over, whether or not anyone was still watching it.\n *\n * The messages come from `result()` rather than from the event stream because\n * assembling a message out of deltas is the agent's job and doing it twice is\n * how the two copies drift. It also means a stopped run persists the same way\n * a finished one does: `stop()` finalizes the transcript, so by the time this\n * resolves there is a valid history to store.\n *\n * `stored` settles when the transcript is in the store, not when the app is\n * done with it. The next turn on this thread waits on that (see\n * `withThread`), and the hooks are the app's: an `onMessage` that writes to\n * something slow would make every later turn wait for it, once per message\n * of the old run, and one that never settles — which `safely` cannot catch —\n * would hold the thread, and every turn queued on it, behind an open\n * connection each. So the hooks run on after it on their own, reported the\n * same way.\n *\n * `hooks` settles once they have too, and every event-stream hook the run\n * led to (`eventHooks`), or after `hookHoldMs` of them, and is what the\n * request that started the run is held open for. Separate from\n * `stored` for the reason above, and it has to exist from the start: by the\n * time the hooks are called the run has settled, and the request with it,\n * unless something was already holding it. Neither rejects.\n */\n private persistRun(\n run: AgentRun,\n ctx: AgentHookContext,\n eventHooks: Promise<void>,\n journal: TurnJournal | null = null,\n early: EarlyTurn = { id: null, notified: Promise.resolve() },\n ): { stored: Promise<void>; hooks: Promise<void> } {\n // Assigned before `stored` settles, on every path, so `hooks` below reads\n // the chain this run actually started.\n let notified: Promise<void> = Promise.resolve();\n\n const stored = (async () => {\n let result: AgentRunResult<ToolShapes, unknown>;\n try {\n result = await run.result();\n } catch (err) {\n // What was written while it ran stays: it is the most the store can\n // know about a run that did not settle, and the next read marks it\n // interrupted once the run is gone.\n journal?.close();\n await journal?.settled();\n // After the turn's own `onMessage`, if the run got that far: the hooks\n // keep their order on every path.\n notified = early.notified.then(() =>\n this.safely(() =>\n this.onError(\n {\n code: \"unknown\",\n message: err instanceof Error ? err.message : String(err),\n retryable: false,\n },\n ctx,\n ),\n ),\n );\n return;\n }\n\n const messages = result.messages as AgentMessage[];\n\n // The writes made while it ran land first, then the transcript whole: the\n // same messages under the same ids, now final, so this replaces every\n // in-progress copy rather than adding to them.\n journal?.close(messages);\n await journal?.settled();\n\n if (ctx.threadId && messages.length > 0) {\n try {\n await this.store.appendMessages(ctx.threadId, messages);\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n\n notified = this.notifyRun(result, messages, ctx, early);\n })();\n\n // The bound starts once the run has settled, not with the run: a long run\n // is not a hung hook. `eventHooks` is in it because the event-stream hooks\n // are chained (see `MemoryLiveRuns.register`): an `onAwaitingInput` queued\n // behind a slow `onToolCall` is called after the run, and after every hook\n // above, and has nothing else to hold the request for it.\n const hooks = stored.then(() =>\n within(\n Promise.all([notified, eventHooks]).then(() => {}),\n this.hookHoldMs,\n ),\n );\n return { stored, hooks };\n }\n\n /** The hooks on a finished run, in order. Never rejects: see `safely`. */\n private async notifyRun(\n result: AgentRunResult<ToolShapes, unknown>,\n messages: AgentMessage[],\n ctx: AgentHookContext,\n early: EarlyTurn,\n ): Promise<void> {\n // The turn's message was handed to `onMessage` while the run went. It\n // comes before every message the run made after it, so waiting for it\n // here keeps the hook's order the transcript's.\n await early.notified;\n for (const message of messages) {\n if (message.id === early.id) continue;\n await this.safely(() => this.onMessage(message, ctx));\n }\n\n await this.safely(() => this.onStreamComplete(result as any, ctx));\n }\n\n private async safely(fn: () => void | Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (err) {\n this.reportHookFailure(err);\n }\n }\n}\n\n/**\n * The turn's user message, as far as the app's `onMessage` has heard of it\n * (#806).\n *\n * The turn's message is the one thing a run stores that the app usually wants\n * to tag from the request: where it was sent from, whether the app sent it on\n * the user's behalf. Called after the run with everything else, those tags\n * were missing for the whole of a long run, to a reload or a second tab, while\n * the store already held the message. So it is called as soon as the journal\n * has written it, and `notifyRun` skips it by `id`: once per message, as\n * before, and in the same order.\n */\ntype EarlyTurn = {\n /** The turn message's id, once the run has reported it. */\n id: string | null;\n /** Settles once its `onMessage` has. Never rejects. */\n notified: Promise<void>;\n};\n\n// --- request plumbing ----------------------------------------------------\n\n/**\n * The keys of the turn envelope itself, which `useChat` puts in the same JSON\n * object as an app's `body`.\n *\n * Listed so `appBody` can take them back out. Sharing one object was the right\n * wire choice — a nested `body` field would be a second envelope for every\n * client, including the Swift and Kotlin ones — but it does mean the app's\n * fields and the framework's are mixed together on arrival, and handing an app\n * `turn` and `messages` would invite reading them. They are this module's to\n * change; an app that depended on their shape would break on a release that\n * never mentioned them.\n */\nconst ENVELOPE_KEYS = [\"turn\", \"clientRunId\", \"threadId\", \"messages\", \"regenerate\"] as const;\n\n/**\n * The turn's own fields, which `toClientTurn` reads off the top level when the\n * body carries no `turn` object. Reserved in that form and only that form —\n * with an envelope present, a top-level `text` is the app's.\n */\nconst BARE_TURN_KEYS = [\"text\", \"files\", \"toolResults\"] as const;\n\n/**\n * An app's own fields, out of the parsed turn body.\n *\n * A fresh object rather than a `delete` on the parsed one. Nothing reads the\n * body after this today — `turn`, `threadId`, `clientRunId` and `messages` are\n * all pulled out above — so this is not load-bearing and no test pins it. It is\n * how a helper that takes a parsed body should behave regardless: the next\n * reader to move a line above this one should not have to know that the body\n * was quietly hollowed out.\n */\nfunction appBody<Body extends object>(\n body: Record<string, any>,\n reserved: readonly string[] = hasTurnEnvelope(body)\n ? ENVELOPE_KEYS\n : [...ENVELOPE_KEYS, ...BARE_TURN_KEYS],\n): Body {\n const extra: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(body)) {\n if (reserved.includes(key)) continue;\n // `JSON.parse` produces `__proto__` as an own property, and `Object.entries`\n // hands it over like any other. Assigning it with `[]` goes through\n // `Object.prototype`'s setter and changes the prototype of the object an app\n // is about to read — from a value the client chose. `defineProperty` writes\n // the key itself, which is what \"the fields the client sent\" means.\n Object.defineProperty(extra, key, {\n value,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n return extra as Body;\n}\n\n/**\n * The app's fields from an upload's `body` form part — the JSON of\n * `useChat`'s `body` option — in the shape `stream` hands out.\n *\n * One JSON part rather than a form field per key: a form field is a string, so\n * `{ count: 3 }` would arrive as `\"3\"` and `Body` would lie on this route and\n * not the other. A missing part is `{}`, as a turn with no app fields is.\n *\n * Only the envelope's four names are taken back out, not the bare-turn ones:\n * `useChat` always sends a `turn` envelope, so on `stream` an app's `text` is\n * the app's, and it has to be here as well.\n *\n * Anything else — a file where the JSON should be, JSON that does not parse,\n * JSON that is not an object — is a 400, not `{}`. Read as empty, the scope\n * would quietly resolve to `null` and the upload downgrade, and the reason\n * would be a missing page rather than a broken client.\n */\nfunction uploadAppBody<Body extends object>(part: FormDataEntryValue | null): Body {\n if (part === null) {\n return {} as Body;\n }\n let parsed: unknown;\n if (typeof part === \"string\") {\n try {\n parsed = JSON.parse(part);\n } catch {\n throw new InvalidUploadError(\"The upload's `body` field is not valid JSON.\");\n }\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new InvalidUploadError(\"The upload's `body` field must be a JSON object.\");\n }\n return appBody<Body>(parsed as Record<string, any>, ENVELOPE_KEYS);\n}\n\n/**\n * A 400 from `upload`, which answers `UploadResult` and so rejects by throwing.\n * The payload is the shape `stream`'s own 400s have, so a client reads both the\n * same way.\n */\nclass InvalidUploadError extends RequestBreakerError {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidUploadError\";\n this.payload = {\n api: { status: 400, data: { error: { code: \"invalid_request\", message } } },\n view: {},\n };\n }\n}\n\n/**\n * The provider's upload, with a refusal of THE FILE answered as the client's\n * problem rather than the server's.\n *\n * A vendor that will not take a file answers 4xx, and before this that left\n * `upload` as an unhandled `ProviderHttpError`: a 500 that tells the person\n * attaching the file nothing about the file. MEASURED on Azure (#682,\n * 2026-10-01): with `purpose: \"user_data\"` a `.docx` was refused with `400\n * Unsupported extension: .docx. Supported extensions: .txt, .md, .pdf, …`; with\n * `assistants` the `.docx` is accepted (and read in a turn), and an `.exe` is\n * refused with `400 Invalid extension exe. Supported formats: \"c\", \"cpp\", …`.\n * Either sentence is exactly what the person needs to read, so it is passed\n * through as the message.\n *\n * Only the statuses that are about the request body: 400, 413, 415 and 422. A\n * 401/403 is our key, a 429/5xx is the vendor's day, and both stay server\n * errors — a person cannot fix either by picking another file.\n */\nasync function providerUpload(provider: { upload(file: File): Promise<string> }, file: File) {\n try {\n return await provider.upload(file);\n } catch (error) {\n if (error instanceof ProviderHttpError && REJECTED_FILE_STATUSES.has(error.status)) {\n throw new RejectedUploadError(normalizeProviderError(error).message);\n }\n throw error;\n }\n}\n\nconst REJECTED_FILE_STATUSES = new Set([400, 413, 415, 422]);\n\n/** A 422 from `upload` for a file outside `attachmentLimits`, or one\n * `checkUpload` refused. */\nclass LimitedUploadError extends RequestBreakerError {\n constructor(code: string, message: string) {\n super(message);\n this.name = \"LimitedUploadError\";\n this.payload = {\n api: { status: 422, data: { error: { code, message } } },\n view: {},\n };\n }\n}\n\n/** Why `file` is outside `limits`, or `null` when it is not. Exported for the\n * tests; the route is the only caller. */\nexport function limitRefusal(\n limits: AttachmentLimits | null | undefined,\n file: Blob,\n name: string,\n mimeType: string,\n): { code: \"file_too_large\" | \"unsupported_file_type\"; message: string } | null {\n if (!limits) return null;\n const { maxBytes, accept } = limits;\n if (typeof maxBytes === \"number\" && file.size > maxBytes) {\n return {\n code: \"file_too_large\",\n message: `${JSON.stringify(name)} is ${formatBytes(file.size)}; the limit is ${formatBytes(maxBytes)}.`,\n };\n }\n if (\n accept &&\n accept.length > 0 &&\n !accept.some((entry) => acceptMatches(entry, name, mimeType))\n ) {\n return {\n code: \"unsupported_file_type\",\n message: `${JSON.stringify(name)} is not a type this chat accepts. Accepted: ${accept.join(\", \")}.`,\n };\n }\n return null;\n}\n\nfunction acceptMatches(entry: string, name: string, mimeType: string): boolean {\n const rule = entry.trim().toLowerCase();\n if (!rule) return false;\n if (rule.startsWith(\".\")) return name.toLowerCase().endsWith(rule);\n const type = mimeType.toLowerCase().split(\";\")[0]!.trim();\n if (rule.endsWith(\"/*\")) return type.startsWith(rule.slice(0, -1));\n return type === rule;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n const units = [\"KB\", \"MB\", \"GB\"];\n let value = bytes / 1024;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit++;\n }\n return `${Math.round(value * 10) / 10} ${units[unit]}`;\n}\n\n/**\n * A 422 from `upload`: the provider would not take this file. `code` is\n * `unsupported_file_type` when the vendor said the type was the problem (an\n * extension or format allow-list) and `file_rejected` otherwise, so\n * a composer can mark the one chip without parsing English. Same payload shape\n * as `InvalidUploadError`.\n */\nclass RejectedUploadError extends RequestBreakerError {\n constructor(message: string) {\n super(message);\n this.name = \"RejectedUploadError\";\n const code =\n /(unsupported|invalid) (extension|file type|format|mime)|supported (extensions|formats?)/i.test(\n message,\n )\n ? \"unsupported_file_type\"\n : \"file_rejected\";\n this.payload = {\n api: { status: 422, data: { error: { code, message } } },\n view: {},\n };\n }\n}\n\n/**\n * A body, or the reason there is not one.\n *\n * Deliberately one shape with an optional `error` rather than a discriminated\n * union on `ok`: this package compiles with `strict: false`, and without\n * `strictNullChecks` TypeScript will not narrow a union by a boolean\n * discriminant — `if (!parsed.ok)` leaves `parsed.message` an error. A field\n * that is either set or not needs no narrowing to read.\n */\ntype ParsedBody = {\n body: Record<string, any>;\n error?: string;\n /** Which HTTP error the rejection is. A missing one is the 400. */\n status?: number;\n code?: string;\n};\n\n/**\n * The body, as JSON — or a reason it is not.\n *\n * Read off the raw request rather than through `req.input()`: that path also\n * accepts `+json` types and answers its failures as a thrown refusal, while\n * these routes are held to `application/json` alone (below) and answer with\n * a `{ code, message }` body of their own.\n *\n * Matching the type by prefix is not the same as ignoring it. A body that\n * arrives as anything other than `application/json` is a 415, and the reason\n * is not tidiness: a cross-site `<form enctype=\"text/plain\">` can be made to\n * concatenate its one field into valid JSON, and a JSON parser that reads\n * whatever it is handed turns that form into a turn on someone else's\n * conversation. Insisting on `application/json` is what makes these routes\n * non-simple requests — the browser will not send one cross-origin without a\n * preflight — and that holds whether or not the app's cookies are `SameSite`\n * and whether or not `CSRFMiddleware` is mounted. Only a request that carries a\n * body is held to this; a bodiless POST has no type to check and stays `{}`.\n *\n * The three cases are kept apart deliberately. NO body is a real request — a\n * reattach, or a turn that just lets the model continue — and reads as `{}`. A\n * body that will not parse, or that parses to something other than an object,\n * is a failed request and has to say so: folding it into `{}` made a truncated\n * proxy response or a mis-serialized client indistinguishable from an empty\n * turn, so `stream` billed a model call with no history and no turn and threw\n * the user's actual message away. That presents as the model hallucinating\n * rather than as an error, which is the expensive way to debug it. Pre-flight\n * failures stay ordinary HTTP errors and never reach the event stream.\n *\n * An array counts as malformed even though `typeof [] === \"object\"`: nothing\n * downstream reads a positional body, so `[1,2,3]` could only ever have run as\n * an empty turn.\n */\nasync function readJsonBody(req: HttpRequest<any, any>, maxBytes: number): Promise<ParsedBody> {\n const raw = req?.rawRequest;\n if (!raw || raw.method === \"GET\" || raw.method === \"HEAD\" || !raw.body) {\n return { body: {} };\n }\n\n if (!isJsonContentType(raw.headers.get(\"Content-Type\"))) {\n // Before the body is read: nothing in a body about to be refused is worth\n // the bytes, and the refusal must not depend on what they were.\n return {\n body: {},\n status: 415,\n code: \"unsupported_media_type\",\n error: \"The request body must be sent as application/json.\",\n };\n }\n\n // Before a byte is read when the client declared its length, and while\n // reading when it did not (#444).\n const declared = Number(raw.headers.get(\"Content-Length\"));\n if (Number.isFinite(declared) && declared > maxBytes) {\n return bodyTooLarge(maxBytes);\n }\n\n let text: string;\n try {\n const read = await readCapped(raw, maxBytes);\n if (read === null) {\n return bodyTooLarge(maxBytes);\n }\n text = read;\n } catch {\n // A body that stopped arriving mid-flight. Same class of failure as one\n // that arrived truncated, and the same answer.\n return { body: {}, error: \"The request body could not be read.\" };\n }\n\n if (!text.trim()) {\n return { body: {} };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return { body: {}, error: \"The request body is not valid JSON.\" };\n }\n\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { body: {}, error: \"The request body must be a JSON object.\" };\n }\n\n return { body: parsed as Record<string, any> };\n}\n\n/**\n * Media types compare case-insensitively and may carry parameters, so the\n * comparison is on the lowercased type with its parameters cut off, and\n * `Application/JSON; charset=utf-8` passes. It is an equality on that type\n * rather than a prefix, so `application/json-seq` and the other types that\n * merely begin with those bytes do not. None of the three types a browser will\n * send without a preflight — `text/plain`, `application/x-www-form-urlencoded`,\n * `multipart/form-data` — does either, and neither does no type at all, which\n * is what a hand-written `fetch` with a string body and no header ends up\n * sending as `text/plain`.\n */\nfunction isJsonContentType(value: string | null): boolean {\n return mediaType(value) === \"application/json\";\n}\n\n/**\n * The body as text, or `null` once more than `maxBytes` of it has arrived, at\n * which point the rest is not read. A limit that is not finite reads it all.\n */\nasync function readCapped(raw: Request, maxBytes: number): Promise<string | null> {\n if (!Number.isFinite(maxBytes) || !raw.body) {\n return await raw.text();\n }\n const reader = raw.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel().catch(noop);\n return null;\n }\n chunks.push(value);\n }\n const bytes = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(bytes);\n}\n\nfunction bodyTooLarge(maxBytes: number): ParsedBody {\n return {\n body: {},\n status: 413,\n code: \"body_too_large\",\n error: `The request body is larger than this agent accepts (${maxBytes} bytes).`,\n };\n}\n\n/**\n * A refusal for one of #444's limits: the `{ kind, message, status }` every\n * refusal has (#686), plus the `code` the agent routes' own errors carry, so a\n * client can tell the limits apart without reading the message.\n */\nfunction limitResponse(status: number, code: string, message: string): Response {\n return jsonResponse(status, {\n ...refusal(refusalKindForStatus(status), message, status),\n code,\n });\n}\n\nfunction invalidRequest(parsed: ParsedBody): Response {\n if (parsed.status === 413) {\n return limitResponse(413, parsed.code ?? \"body_too_large\", parsed.error ?? \"\");\n }\n return jsonResponse(parsed.status ?? 400, {\n code: parsed.code ?? \"invalid_request\",\n message: parsed.error,\n });\n}\n\n/**\n * Whether the turn arrived in a `turn` object of its own, rather than spread\n * across the top level of the body.\n *\n * Both forms are accepted, and which one it is decides what belongs to the app:\n * a top-level `text` is the user's message in the bare form and an app's own\n * field in the enveloped one. `toClientTurn` and `appBody` have to agree about\n * that, so they ask the same question here rather than each testing it.\n */\nfunction hasTurnEnvelope(body: Record<string, any>): boolean {\n return Boolean(body.turn) && typeof body.turn === \"object\";\n}\n\n/**\n * The client's turn, accepting both `{ turn: {...} }` and the flattened\n * `{ text, files, toolResults }` — the second is what a hand-written `fetch`\n * writes, and refusing it buys nothing.\n *\n * `turn` is `undefined` for an empty turn, which is a real request:\n * reattaching to a conversation and letting the model continue is a turn with\n * nothing in it. `error` is a turn that is refused with a 400 before anything\n * runs — see `toTurnFiles`.\n */\nfunction toClientTurn(body: Record<string, any>): { turn?: ClientTurn; error?: string } {\n const source = hasTurnEnvelope(body) ? body.turn : body;\n const turn: ClientTurn = {};\n if (typeof source.text === \"string\") {\n turn.text = source.text;\n }\n if (Array.isArray(source.files)) {\n const files = toTurnFiles(source.files);\n if (typeof files === \"string\") {\n return { error: files };\n }\n turn.files = files;\n }\n if (Array.isArray(source.toolResults)) {\n turn.toolResults = source.toolResults;\n }\n if (Object.keys(turn).length === 0) return {};\n // Envelope only: in the bare form the top level is shared with the app's own\n // fields, and an app that already sends a `localId` of its own would lose it\n // to the turn. `null` and `\"\"` read as absent, as they do for `files`.\n if (\n source === body.turn &&\n source.localId !== undefined &&\n source.localId !== null &&\n source.localId !== \"\"\n ) {\n const { localId } = source;\n if (typeof localId !== \"string\") return { error: \"turn.localId must be a string.\" };\n // Echoed back on the stream and nothing else, so the only thing to bound\n // is what one frame carries.\n if (localId.length > MAX_LOCAL_ID_LENGTH) {\n return { error: `turn.localId is longer than ${MAX_LOCAL_ID_LENGTH} characters.` };\n }\n turn.localId = localId;\n }\n return { turn };\n}\n\n/** How long `turn.localId` may be. Comfortably above `local_<uuid>`. */\nconst MAX_LOCAL_ID_LENGTH = 200;\n\n/**\n * `turn.files`, checked field by field, or the sentence refusing it.\n *\n * REFUSED, NOT FILTERED. Every entry becomes a `FilePart` in a user message,\n * and on a thread that message is stored before the provider sees it. An entry\n * the request builder cannot send — no id at all, or a gemi id in `fileId` —\n * then throws from `toResponsesInput` on this turn and on every turn after it,\n * because every later turn re-sends the history: one bad upload bricks the\n * thread. Dropping the entry instead is quieter and worse — the model answers\n * about a file it was never given, with nothing saying so. A 400 here is the\n * one place the client can still do something about it.\n *\n * Scoping is what makes a foreign `attachmentId` harmless (`ScopedAttachments`\n * answers the same not-found for another tenant's id as for an invented one),\n * so the id is not signed or looked up here. What this checks is the shape a\n * crash would come from: strings where strings go, the prefix on\n * `attachmentId`, at least one id. Unknown fields are dropped rather than\n * refused, since `attach()` answers more than a `FilePart` holds (`downgraded`)\n * and passing its answer on whole is the documented use. `null` and `\"\"` read\n * as absent, for every field: `null` is what a serializer that writes\n * `undefined` as `null` means, and `\"\"` is what a form field left blank sends.\n * Neither can be an id, so refusing `attachmentId: \"\"` for its prefix would\n * turn a blank into an error the entry's `fileId` does not deserve.\n */\nfunction toTurnFiles(raw: unknown[]): NonNullable<ClientTurn[\"files\"]> | string {\n const files: NonNullable<ClientTurn[\"files\"]> = [];\n for (const [index, entry] of raw.entries()) {\n const where = `turn.files[${index}]`;\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n return `${where} must be an object.`;\n }\n const fields: Record<string, string> = {};\n for (const key of [\"fileId\", \"attachmentId\", \"name\", \"mimeType\"] as const) {\n const value = (entry as Record<string, unknown>)[key];\n if (value === undefined || value === null || value === \"\") continue;\n if (typeof value !== \"string\") {\n return `${where}.${key} must be a string.`;\n }\n fields[key] = value;\n }\n const { fileId, attachmentId, name, mimeType } = fields;\n if (fileId?.startsWith(ATTACHMENT_ID_PREFIX)) {\n return `${where}.fileId holds a gemi attachment id (${fileId}). \\`fileId\\` is the provider's id from the upload response; put this one in \\`attachmentId\\`.`;\n }\n if (attachmentId !== undefined && !attachmentId.startsWith(ATTACHMENT_ID_PREFIX)) {\n return `${where}.attachmentId is not a gemi attachment id: it must start with \"${ATTACHMENT_ID_PREFIX}\".`;\n }\n if (!fileId && !attachmentId) {\n return `${where} has neither a \\`fileId\\` nor an \\`attachmentId\\`. Send the ids the upload response answered.`;\n }\n files.push({\n ...(fileId ? { fileId } : {}),\n ...(attachmentId ? { attachmentId } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(mimeType !== undefined ? { mimeType } : {}),\n });\n }\n return files;\n}\n\n/**\n * Where to resume from, or `undefined` for \"wherever you still can\".\n *\n * An explicit `from` wins, because a client that tracked its own position knows\n * something the transport does not. Otherwise `Last-Event-ID` — the browser\n * sends it on its own when an `EventSource` reconnects, and the frames put\n * `seq` in `id:` precisely so that header is already the right question. It\n * names the last event *received*, so the resume point is one past it.\n *\n * With neither, the answer is `undefined` and NOT 0. A client reattaching on\n * mount is a fresh POST from a page that has just loaded: no `Last-Event-ID`,\n * and no cursor of its own, because the only handle it was given is the\n * `threadId`. Reading that as \"resume from frame 0\" asked `replay` for a frame\n * every run longer than `maxFrames` has already evicted, so the mount-time\n * reattach — the one case `/attach` exists for — 410'd on exactly the long runs\n * it was meant to rescue, and the documented remedy of reloading the thread\n * does not help because the store is only written at run end. `undefined` means\n * the tail, which is all such a client can use anyway.\n */\nfunction resolveCursor(req: HttpRequest<any, any>, body: Record<string, any>): number | undefined {\n if (typeof body.from === \"number\" && Number.isFinite(body.from)) {\n return Math.max(0, Math.floor(body.from));\n }\n // `cursor` is what `useChat` actually sends, and it counts the other way:\n // `from` is the frame to resume AT, `cursor` the last frame the client\n // APPLIED — the same convention as `Last-Event-ID`, and the same `+ 1`. A\n // client that has applied nothing sends -1, which is not a position but the\n // absence of one, so it falls through to the tail rather than asking for\n // frame 0 and 410ing on precisely the long runs `/attach` exists to rescue.\n if (typeof body.cursor === \"number\" && Number.isFinite(body.cursor)) {\n const applied = Math.floor(body.cursor);\n if (applied >= 0) {\n return applied + 1;\n }\n return undefined;\n }\n const header = req?.rawRequest?.headers?.get(\"Last-Event-ID\");\n if (header) {\n const seq = Number.parseInt(header, 10);\n if (Number.isFinite(seq)) {\n return Math.max(0, seq + 1);\n }\n }\n return undefined;\n}\n\nfunction searchParam(req: HttpRequest<any, any>, key: string): string | undefined {\n const value = req?.search?.get(key);\n return typeof value === \"string\" ? value : undefined;\n}\n\n/**\n * Where a threaded regenerate cuts the history: at the last message the user\n * wrote, with the turn that wrote it. A file a tool showed is a user-role\n * message too, but it is part of the answer being replaced, so it is stepped\n * over (`injectedMessageIds`, the test `historyForProvider` uses).\n */\nfunction regenerationCut(\n messages: AgentMessage[],\n): { index: number; turn: ClientTurn } | null {\n const injected = injectedMessageIds(messages);\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index]!;\n if (message.role !== \"user\" || injected.has(message.id)) continue;\n let text = \"\";\n const files: NonNullable<ClientTurn[\"files\"]> = [];\n for (const part of message.content) {\n if (part.type === \"text\") text += part.text;\n if (part.type === \"file\") {\n files.push({\n ...(part.fileId ? { fileId: part.fileId } : {}),\n ...(part.attachmentId ? { attachmentId: part.attachmentId } : {}),\n ...(part.name ? { name: part.name } : {}),\n ...(part.mimeType ? { mimeType: part.mimeType } : {}),\n });\n }\n }\n if (!text && files.length === 0) continue;\n return {\n index,\n turn: { ...(text ? { text } : {}), ...(files.length > 0 ? { files } : {}) },\n };\n }\n return null;\n}\n\n/** A turn `/stop` ended while it waited, before anything ran or was charged. */\nfunction stoppedBeforeStart(): Response {\n return jsonResponse(409, {\n code: \"stopped\",\n message: \"The turn was stopped before it started.\",\n });\n}\n\n/**\n * The refusal for a run that belongs to another caller (#442), in the shape\n * every other refusal has (`{ kind, message, status }`, #686), so `useChat` and\n * the client guards classify it as `permission` without matching on text.\n */\nfunction notYourRun(): Response {\n return jsonResponse(\n 403,\n refusal(\"permission\", \"This run belongs to someone else.\", 403) as Record<string, unknown>,\n );\n}\n\n/** The refusal for a turn naming another owner's provider file (#443). Same\n * shape as `notYourRun`. */\nfunction notYourFile(): Response {\n return jsonResponse(\n 403,\n refusal(\n \"permission\",\n \"A file in this turn was uploaded by someone else.\",\n 403,\n ) as Record<string, unknown>,\n );\n}\n\n/**\n * The file parts of a stateless chat's history, which the client carries and\n * may have written anything into. Read defensively: the history is not\n * validated anywhere else before the run, and a malformed one is the run's\n * problem, not this check's.\n */\nfunction clientHistoryFiles(messages: unknown): { fileId?: string }[] {\n if (!Array.isArray(messages)) return [];\n const files: { fileId?: string }[] = [];\n for (const message of messages) {\n const content = (message as { content?: unknown } | null)?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (part && typeof part === \"object\" && typeof part.fileId === \"string\") {\n files.push({ fileId: part.fileId });\n }\n }\n }\n return files;\n}\n\nfunction jsonResponse(status: number, error: Record<string, unknown>): Response {\n return new Response(JSON.stringify({ error }), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\n// --- attachments ---------------------------------------------------------\n\n/**\n * Reads the client's `destination` field and applies it to the app's policy.\n *\n * THE ONLY THING A CLIENT MAY ASK FOR IS \"DO NOT SEND THIS TO THE VENDOR\", and\n * that is the entire permitted vocabulary: a `storage` hint under a `both`\n * policy, or a hint that agrees with the policy and changes nothing. Everything\n * else throws.\n *\n * The rule here used to be \"a hint may narrow, never widen\", counting\n * destinations, and counting is what made it wrong in one direction.\n * `both → provider` is fewer destinations and reads as narrowing, but what it\n * removes is *gemi's own copy*, while the third party still gets the file. That\n * is not a client declining exposure, it is a client overriding the app's\n * retention decision from a field in a multipart body: an app that keeps every\n * upload because a tool has to forward it — or because an auditor asked — loses\n * the copy, mints no `attachmentId`, records nothing, and gets no warning\n * either, since the bytes did reach the provider exactly as policy said. The\n * two directions are not alike, because only one of them reduces who ends up\n * holding the file.\n *\n * What is left is defensible on its own terms: `storage` keeps bytes off a\n * vendor the app was willing to send them to, which is a thing the client is\n * entitled to ask for and which cannot hurt anyone if the client is lying. A UI\n * that knows this CSV exists to be imported and will never be read by the model\n * is the case that makes a hint worth having at all. The policy hook is the\n * ceiling; the hint may only take the vendor out from under it.\n *\n * A hint the policy does not permit throws rather than being ignored. Ignoring\n * it is the shape of this bug that never gets found: the client believes it kept\n * a file off the vendor, the file went anyway, and nothing anywhere says so.\n */\nfunction narrowDestination(\n policy: AttachmentDestination,\n hint: FormDataEntryValue | null,\n): AttachmentDestination {\n if (typeof hint !== \"string\" || hint.length === 0) {\n return policy;\n }\n if (hint !== \"both\" && hint !== \"provider\" && hint !== \"storage\") {\n throw new Error(\n `Unknown attachment destination \"${hint}\". Expected \"both\", \"provider\" or \"storage\".`,\n );\n }\n if (hint === policy || (policy === \"both\" && hint === \"storage\")) {\n return hint;\n }\n if (policy === \"both\" && hint === \"provider\") {\n throw new Error(\n 'This upload asked for the \"provider\" destination under a \"both\" policy. A client may ask for \"storage\", which keeps a file away from the model provider, but it may not ask the server to stop keeping its own copy while the vendor still gets the file — that is the app\\'s retention decision. Change `attachmentDestination()` if this file should not be kept.',\n );\n }\n throw new Error(\n `This upload asked for the \"${hint}\" destination, but the server's policy for it is \"${policy}\", and a client hint may only ask for \"storage\" under a \"both\" policy. Change \\`attachmentDestination()\\` if the file really should go there.`,\n );\n}\n\n/**\n * Said once per process, not once per upload.\n *\n * The condition is a property of how the app is wired — an agent route with no\n * authentication and no `threadId` on its uploads — so it is either true for\n * every request or false for every request. Logging it per request would put a\n * line in the log for every file anyone ever uploads, which is how a warning\n * stops being read.\n */\nlet warnedAboutUnscopedUpload = false;\nfunction warnUnscopedUploadOnce(): void {\n if (warnedAboutUnscopedUpload) return;\n warnedAboutUnscopedUpload = true;\n console.warn(\n \"[gemi/ai] An upload had no attachment scope, so its bytes were sent to the model provider only and no attachment id was minted — a tool cannot forward this file. Guard the route with auth, send a `threadId` with the upload, or override `attachmentScope()`.\",\n );\n}\n\n// --- routing -------------------------------------------------------------\n//\n// `agent()` itself belongs on ApiRouter next to `resource()`, which is the\n// method it works like: one call, several routes, all of them the controller's.\n// The types are declared here because they are the ai module's contract, not\n// the router's.\n//\n// class Api extends ApiRouter {\n// routes = {\n// \"/chat\": this.agent(ChatAgentController),\n// };\n// }\n//\n// POST /chat → stream every client turn\n// POST /chat/attach → attach reattach to a run in progress\n// POST /chat/stop → stop explicit cancel\n// POST /chat/files → upload attachments\n//\n// Mounting under a single path is what gives the client one key to name. The\n// agent's tool types ride along on `AgentRoute`, so `useChat(\"/chat\")` gets them\n// out of the existing `RPC` interface — no second augmentation to generate, and\n// renaming the route moves the client key with it.\n\nexport type AgentRouteMethod = \"stream\" | \"attach\" | \"stop\" | \"upload\";\n\nexport type AgentMiddlewareConfig = Partial<Record<AgentRouteMethod, MiddlewareInput>>;\n\n/**\n * What `this.agent(Controller)` returns. `T` is unconstrained so that mounting\n * the route never resolves the controller (#774): an agent whose tools are\n * routes of the same api would otherwise resolve the api's route table from\n * inside it. That `T` is an `AgentController` class is checked when the route\n * is mounted: `this.agent()` throws otherwise.\n */\nexport type AgentRoute<T> = {\n __internal_brand: \"AgentRoute\";\n controller: T;\n middleware(config: AgentMiddlewareConfig): AgentRoute<T>;\n};\n\n/** What `CreateRPC` should produce for an agent route: enough for the client to\n * type its messages, and nothing that drags server code into the bundle. */\nexport type AgentRouteRPC<T extends new () => AgentController<any, any>> = {\n __agent: true;\n tools: InstanceType<T>[\"agent\"] extends AnyAgent\n ? ToolShapesOf<InstanceType<T>[\"agent\"][\"tools\"]>\n : ToolShapes;\n output: unknown;\n /**\n * The controller's `Body`, so `useChat` can check what it sends against what\n * the controller declared.\n *\n * Read off the phantom key rather than by matching the class, which is what\n * made this fail: `Body` used to reach the instance type only through\n * `instructions`'s second parameter, and a controller overriding\n * `instructions(req)` — the pre-existing signature, so every existing\n * override — gave inference nothing to work with and got the open record.\n */\n body: InstanceType<T> extends { [BODY]?: infer B } ? B : Record<string, unknown>;\n};\n\n/** The longest delay `setTimeout` keeps; past it the runtime fires in ~1ms. */\nconst MAX_TIMEOUT_MS = 2 ** 31 - 1;\n\n/**\n * Settles when `work` does or after `ms`, whichever is first, and never\n * rejects. For how long the request waits on the app's code, not for the code\n * itself, which runs on either way.\n *\n * An `ms` a timer cannot hold — `Infinity` is what \"no bound\" reads as — is\n * no bound. Handed to `setTimeout` it would fire at once, and the request\n * would end before the hooks it was raised for.\n */\nfunction within(work: Promise<void>, ms: number): Promise<void> {\n const settled = work.then(\n () => {},\n () => {},\n );\n if (!(ms <= MAX_TIMEOUT_MS)) {\n return settled;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<void>((resolve) => {\n timer = setTimeout(resolve, ms);\n });\n return Promise.race([settled, timeout]).finally(() => clearTimeout(timer));\n}\n\nlet warnedInMemoryNonces = false;\n\n/**\n * Once per process, in production: a stateless chat whose answers are spent\n * only in this process's memory. Correct for a single instance, which is why\n * it is a warning; with several, a rewound history replays an approval once\n * per instance (#445).\n */\nfunction warnInMemoryNonces(nonces: NonceStore): void {\n if (warnedInMemoryNonces || process.env.NODE_ENV !== \"production\") return;\n if (!(nonces instanceof MemoryNonceStore)) return;\n warnedInMemoryNonces = true;\n console.warn(\n \"[gemi/ai] A stateless agent chat is spending approval nonces in process memory. \" +\n \"With more than one instance a replayed approval is accepted once per instance. \" +\n \"Set `nonces = new RedisNonceStore()` (or your own NonceStore) on the AgentController.\",\n );\n}\n\n/** Whether any message holds a tool result still waiting on a background job. */\nfunction hasRunningResult(messages: AgentMessage[]): boolean {\n return messages.some((message) =>\n message.content.some((part) => part.type === \"tool-result\" && part.status === \"running\"),\n );\n}\n"
|
|
39
30
|
],
|
|
40
|
-
"mappings": "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",
|
|
41
|
-
"debugId": "
|
|
31
|
+
"mappings": "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",
|
|
32
|
+
"debugId": "8C6BA69BA7D7181C64756E2164756E21",
|
|
42
33
|
"names": []
|
|
43
34
|
}
|