@opengeni/runtime 0.3.0 → 0.4.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/index.js CHANGED
@@ -95,11 +95,11 @@ import {
95
95
  timeoutAgentError,
96
96
  timeoutControlResponse,
97
97
  verifyStreamToken
98
- } from "./chunk-D5KU3QUC.js";
98
+ } from "./chunk-HGQ252FL.js";
99
99
 
100
100
  // src/index.ts
101
101
  import { AGENT_INSTRUCTIONS_CORE_PLACEHOLDER, collectSandboxEnvironment as collectSandboxEnvironment2, contextInputBudgetTokens, contextServerCompactThreshold, firstPartyMcpBaseUrl, resolveContextCompactionMode, resolveModelProvider, sandboxLifecycleHookIds } from "@opengeni/config";
102
- import { CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2, isClearedRunStateBlob, signDelegatedAccessToken } from "@opengeni/contracts";
102
+ import { CAPABILITY_DESCRIPTORS as CAPABILITY_DESCRIPTORS2, isClearedRunStateBlob, prefixedMcpToolName as sharedPrefixedMcpToolName, signDelegatedAccessToken } from "@opengeni/contracts";
103
103
  import {
104
104
  Agent,
105
105
  AgentsError,
@@ -116,6 +116,7 @@ import {
116
116
  setDefaultOpenAIClient,
117
117
  setDefaultOpenAIKey,
118
118
  setOpenAIResponsesTransport,
119
+ setTracingDisabled,
119
120
  webSearchTool,
120
121
  applyDiff
121
122
  } from "@openai/agents";
@@ -145,8 +146,11 @@ import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "
145
146
  import { dirname, isAbsolute, join, posix as posixPath, relative } from "path";
146
147
  import { fileURLToPath } from "url";
147
148
 
149
+ // src/screenshot-error-card.ts
150
+ var SCREENSHOT_FAILURE_CARD_IMAGE_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABVMAAAGYCAYAAABPvXKBAAAh90lEQVR42u3dMXLkxhJF0VnEGDQQXLY2CaedtkcLkEJBBaqrXmYe43j6bDZQKGTd+RH89df39x8AAAAAAP7bLxcBAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAgMCY+n7dSyV9bpfvdur7Pvnc1Wsy/eGtuNam7RHp63nade7yrE57fk89R9Pev4ZiAAAQU8VUMVVMFWPEVPuVmCqmiqliKgAAiKliqpgqpooxIpCYKqaKqWKqmAoAAGKqmCqmiqliqpgqpoqpnl8xVUwFAAAxVUwVU8VUMVVMFVPFVM+vmCqmAgCAmBp9uKn4uRUPkUmH1y4x1Xq+S34P1/lu848Xnt95P8/9FVgBAEBMFZ/EVDFV5PPzxFTPr5/n/oqpAAAgpopPYqqYaj2LQGKqmGrdmzfEVAAAEFMdbsRUMdV6FoHEVDHVujdviKkAACCm+lwxVUy1nkUgMVVMFVNdZzEVAADEVIcbMfXg53aJO9azCCSmiqnWvXlDTAUAADHV54qpYqr1LAKJqWKqmCqmiqkAACCmOtyIqWKq9Symus5iqtgmpoqpAAAgpjrciBNiqhgjpoqpYqrnV0x1fwEAQEx1yBBTxVQxRkwVU8VUz6+Y6v4CAABbY+qTv8Re8a+zP/luq7/vtM8VU/PX85P7sWNdiam9942k57fidRZTa74HxVQAABBTHap8rpgqpoqpYqqYKqZ674upAAAgpoqpYqqYKqaKqWKqmCqmiqliKgAAiKliqpgqpoqpYqqYKqaKqWKqmAoAAGKqmCpqiqliqpgqpoqpYqqYKqYCAICYWi4qdfkr8/6K8frPrRhopv216Gn3I/06izae34k/z/0VUwEAQEwVUx0ixVQxVaQSUz2/fp77K6YCAICYKqY6RIqpYqqYKqaKqWKq96DnEgAAxFQx1SFSTBVTxVQxVUwVP70HPZcAACCmiqkOkWKqw7qYKqaKqdap6yymAgCAmCqmxv9vHSK/xVQxVUwdsF95fsVU99dzCQAAYqqY6hAppoqpYqqYKqaKqd6DYioAAIipYqpDpEOkmCqmiqliqvjpPSimAgCAmCqmiqkOka6z+yGmiqnWqZjqPQgAAGKqmCqmOkS6zmKqmCra2CfFVO9BAAAQUx8O50+k/y5JUeTU9+18ndMDTef1PC2O7dgnp+1XYqr3kc+t8cwAAICYKqY6vIqpYqqYKqaKqWKqqCmmAgCAmCqmOryKqWKqmCqmiqliqveRmAoAAGKqmCqmiqliqpgqpoqpYqr3kZgKAACIqWKqmCqmiqliqpgqpnof+VxDMQAAhMRUAAAAAAAxFQAAAABATAUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAoGJM/fp9/fmk9+v+uJ9+7urvkfR9Tzn13ZKus/Wcf53T17Nn+tz9PfUcdb6XSWv31M+b9h60N817trz3a66rLvNkxes8bZ4E6E5MFVMdbsRUMdXwK6aKqWKqmGrecJ29F8RUMVVMBUBMFVMN2GKqmCqmOjSLqWKqmGrecJ29F6wrMVVMBUBMFZ8M2GKqmCqmeqbFVOtZTDVvuM6uvZgqpoqpAIiphgWHGzHVehZTPdNiqpgqpop85g3XXkw1T4qpAIyKqRUPQRUPzdPuW1KcSP/cHb+z5/cquR90eY4qHiK9V88Fn2n7Rud/6DHXeS94fl1n718AxFTDgsONmCqmOlQ5NDvMOcyJqQ7h5jrvBe9985X3r5gKIKYaFgzdhiMx1bDv0Oww5zAnprpv5g0x1XvffOX9K6YCiKlijKHbcCSmen7FVPfXdRZTxVT7hrnOe8HP8/61jwOIqV46hm7XWUz1/Iqp9g2HOTFVPDFvmOvcXzHV+9c+DiCmiqmGbte5zSHD0CimOjQ7zFnPa+6HGGPeMNd5L4ip3r/2cQDEVEO34VdM9fyKqQ7N9isxVUw1b5jr7Ffip/ev9y8AYqqh2+HGIcPQKKY6NDvMWc9iqphqrvNe8Py6zt6/AIiphm6HGzHV0CimOjQ7zDnMialiqrnOe0FMdZ29f4UMADHVsGDoFlNdF4cqh2aHOYc5MdUh3LzhveC9b77y/hVTAcTUoJfOajs+1+Em/zrv+Nz09dJ52Pf8OjQ7zImpYkzm/U16/3ovXOb2D1wr81XN59c+DiCmiqliqqFMTDXse37FVDFVTBVTxVTvBTFVTBVT7eMAiKliqpgqphr2Pb9iqpgqpoqpYqqYKqaKqWKqmAqAmGooE1PFVDFVTBVTxVQxVUwVU8VUMVVMFVPFVADEVEOZmCqmiqliqpgqpjrMialiqpgqpoqp5isxFQAx1V+r9Nd1h1zn9EO959fza98QU7vF1NX/YCWmmje8F9xf89WMf5yyjwMgphq6Db9iqufX8+vQLKaKqWKqecN7wXtBTBVTvX8BEFMNZQ43Yqqh0fPrkCGmiqliqpjqveC9IKaKqd6/AIiphjJDnpgq2lhXDs1iqsOcmCqmei94L4ipYqr1DICYKsY43Iipoo115dAspjrMiakO4d4L3gtiqphqPYupAGKqYcHQ7Tpv/77+2qzn1yFDTBVT+60rMdV7wXtBTJ1wndNn4PT79uQfCwEQUw1lhl8xVUz1/Do0i6liqpgqpnoveC/Y18RUMVVMBRBTDWUON2KqmGpdOTSLqWKqmOp96b3gvSCmiqnev2IqgJhqKHO4cTgUU60rh2YxVZSzrsRU7wXvBTFVTBVTxVQAMdWwYOgWU8VU68qhWUwVU60rMdV7wXvB/TVfialiKoCYalj4kPQhb8d3O3Wdk77vtMN6xevc5SCd/kxXXFed9ytzxBV1nTvH1M7P77RrL6aarzqdy5L2CDEVQEwVU8VUMVVMFVM902KqmCqmiqliqpgqpoqpYqqYCiCmiqliqjghpoqpnmkxVUwVU8VU84aYKqaar8RUMRVATBVTxVRxQkwVUwULMVVMFVPFVPOGmCqmmq/EVDEVQEwVU8VUMVVMNeyLqWKq/cocIabam8RUMVVMdS4TUwHEVAAAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVBcBAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxNQPeL/uj/vp567+Hknfd8fvkrRwXeea177zd1u9hqbd31Pvhc7vo1P399R67vIOOLWeDcWX5zdsvuo8TzqnXN4LBX6XinOstdZn3ugyX1U8LyCmiqmGI9dZTBVTxVTDkZhq2BdTxVQx1XvB/RVTxVRrTUx1XkBMNaSIqa6zmCqmiqmGI4cqw76YKqaKqc4pYqr3gphqrYmpzgueSzHVkCLyialiqpgqphqOxFSHZjFVTBVTnVPEVO8F731nCDFVTBVTxVRDisgnpoqpBiExVUwVUx1kxFQxVUwVU8VU7wUxVUwVU8VUMVVMbTGs+nkOQa7zzOuXdLjxffO/77TrbD37vuaIfdHB3Gke6rRfmeu8B60rn+u8kDlvIKb6eR4W19n1Myz4voZQ99f39X4TU60X5xTRy3vBujJPWldiqrlOTPXzPCyus+tnWPB9DaFiqvXs/SamWi/mIdHLdfZ9xVTrSkz1nhZTxU9DrcOm62foNhwZQsVU19n+LKaaO81Dopf3gu8rplpXrrOYKqaKlYZa68r1E1MN3YYjMdV1tj+LqWKqeUj0Mtf5vtaVOdZ5QUwVUw0phlpDlGFBTDUsGI7EVNdZTB3/Hjz131kv5iHRy3W2rsRU62rOdfZciqnip6HWunL9xFTDkeFITHWd7c9iqrnTPCR6eS/4vmKqOdZ1FlPFVLHSUGtduX5iqqHbcCSmus72ZzFVTDUP2a/Mdd6D1pXPdV4QU8VUQ4qh1hBlWBBTDQu+r5hqPYup5ggx1Txkv3LfvAetK5/rORJTxVRDip/nZec6i6mGBd/XdXZ/fV9zhJhqvYip7pv3gnVljvUciamMj6mrpT+kp77btJdd5+uc/hylf98ufzVy9TXo8n2nXWeHyLv1ujIUi6liav9zyrR9Y9r+PG2u67LWpp0XfK6YKqYaUkQ+MVVMFVMNR2KqmCqmiqkimpgqpoqpYqp5Q0x1XvAcialiqiFFTDX8us5iqpgqpjrciKliqpgqpjqkianmWDFVtBFTPUdiKmKqmCqmus5iqpgqpjrciKliqgFbTBVTxVRzrAgkpoqpniMxFTFVTBVTXWcxVUw1dDvciKliqpgqpoqpziliqggkpoqpniMx1awnpvp5zf9K4bTv4a/bux/ik+tc5TqLqTW/b/rhq/McUfEfQ8TU3ucK9+1u/XxYV9ap52jmecE/nIupYqqoJFaKqWKqodt1FlOtZzFVTDXHmodELxHIuhJTxVTnBTFVTBU/RSXfw+/nfhi6XWcx1XUWU8VUMVVMFb1EIO9BzBvOZWKqmGpIEZXEVL+f72voFlPFVNdZTBVTxVQx1X4lpnoPCi3mDc+RmCqmGlJEJTHV72fd+1yxTUwVUx1uxFQxVZQTU0Uq84aYKqZ6jsRUxFRDqJjq97PuvbTFJ9fZ/R30fXf8zuaI3odSUU5M7X7fuvzVdetKTPUcOS+Is2Kqnyfyuc6eSy9PQ7frLKb6vmKqmOp9bh4SvUQg60pM9Rw5L4ipYqqYKiqJlWKqmGrodp3FVOtZTPUeNMdaB6KXCGRdialiqvOCmCqmip+iku/h93M/vLRdZzHVdRZTRTQx1ToQvcRU+xXmDecyMVVMNaSISmKq38/39bliqhjjOoup5ggxVZSzX4mp3oMii3nDcySmiqmGlAWb3Go7PrfiS8d1FlM7vTxPref0l3bS8zvtOtufPb8Tw9q059c9d07pNNs6D1pXFeb29N/Fc2SuE1PFVA+9mOo6i6liqpjqOoupYqqYKqaKqc4pYqqYal2JqdaVuU5MFVM99CKf6yymiqliquFITBVTxVQxVUx1ThG9nAetKzHVunJeEFPFVC9Pkc919lyKqV7ahiMxVUwVU8VUMdU8JHq5zr6vmCqmOi+IqWKqIUXkE1MdHsRUL23DkZgqpoqp3oNiqnUgeompopeYKqaKqWKqmAoAAAAAIKYCAAAAAIipAAAAAACIqQAAAAAAYioAAAAAgJgKAAAAACCmAgAAAACIqQAAAAAAYioAAAAAgJgKAAAAACCmuhAAAAAAAGIqAAAAAICYCgAAAAAgpgIAAAAAiKkAAAAAAGIqAAAAAICYCgAAAAAgpgIAAAAAIKYCAAAAAIipAAAAAABiKgAAAACAmAoAAAAAIKYCAAAAAIipAAAAAABiKgAAAAAAYioAAAAAgJgKAAAAACCmAgAAAACIqQAAAAAAYioAAAAAgJj6L96ve6lTv0v6jdxxrZKu8+p11eWep1/7iuu54r386fc9dZ09vzWf31P3t+Jz1Pn5nbZPps+2nfemitcgfc6Ztm8AgJgqpoqpYoyYKhKIqZ5fMVVMtU+KqWKqmCqmAoCYKqaKqWKqmCoSiKmeXzFVTBVFxFR7k5gqpgKAmCqmiqliqhgjpoqpnl8xVUwVU8VUMVVMFVMBQEwVU8VUMdWBR0wVU8VUMVVMFVPFVDFVTBVTHbABEFMLRz6HjD1DXvp17jLknfoenl//aFLh/np+7Ruuc6+YZY6Yd/3sV/lzu3AKAGKqmCqmijGeX4dcMdXza98QU+2TApLnV0z1LACAmCqmiqkOh55f68Ch2fNr3xBTxVTvD8+vmCqmAoCYKsaIqSKaKGIdiKmeX/uG6yymen94fsVUMRUAxFQxRkx1CHLIsA7EVHHC54qpYqo5QkwVU8VUABBTxZiA63zqv3MIEkV2DfGdh30x1X2zb4ipVd7n9kn7lZiaN497TwOAmCqmiqliqpgqptqfPb/2DddZPDFHeH7FVPsBAIipYqqY6hAkpjoAiKnum88VU8VUc4SYKqaKqQAgpoqpYqpDkCgipoqp4oTPFWPEVDHV9bNfiakAIKaKqWKqQ5AoIqaKqQ5pIp8YI6baJ10/MVVMBQAxVUwVU8XU4Hu+46/Drub+Zj0fO+5v0hqa9vymf7ek/ari54one75H5/0qfT2nf9+KkVQ4BQAxVUwVU8VUMVVMFVM9v2KqmCqmiqliqpgqpgKAmCqmiqlim5gqpoqpYqqY6nPFVDFVTBVTxVQAEFPFVDFVTBVT3V8xVUwVJ8RUMVVMFVPFVDEVAMRUMVVMFVPFVDFVTBVTxVQxVUwVU8VUMVVMBQAxVUwtfnjYMQyKqVfr+O7++ivV/kpw/+fXe7rP5077hwq/n/dCp++bFHEBQEw1pIipYqoY4/6KqWKq59f+IqaKqX4/MVVM9Z4GADFVTBVTDYNiqpgqpnp+7S9iqpjq9/NeEFO9pwFATBVtxFSxTUwVUx2aPb9iqpgqpoqp3gtiqpgKAGKqmCqmim1ih/srpiKmiqliqlhpbvd9xVQAEFMd0lxnsU1MdX/FVM+lOHH0fyviXmKq309MHTA/J+2xnf9RBwAx1ZBi+BXbxBj3V0wVUz2/YqqYKqb6/exXYqqYCgBiquFXbBNj3F8xVUz1/IqpYqqY6vcTU8VUMRUAxFQx1XU2lLm/YqpDs+dXTBVTxVS/n/eC+VlMBQAxVUx1ncU291dMFVM9v2KqmGo/FVPNk+ZnMRUA2sfUJ079LiLLXfI6dz4c7rjOYqrnfNdhLuld4T14b/lr0V3WVdLnTot8Fe+veePyHPk/QYipAIipYqrIIqaKqWKqmCqmiqliqpgqpoqpYqrPFVMBEFMdIsVUMdXhRkz1nIup3oNiqpgqpoqpYqqYKqYCgJgqpoqpYqqYKqaKqd6DYqqYKqaKqWKqmCqmAoCYKqaKqWKqmCqmiqliqpgqpoqpYqqYKmqKqQBQKaYCAAAAAIipAAAAAABiKgAAAAAAYioAAAAAgJgKAAAAACCmAgAAAACIqQAAAAAAYioAAAAAgJgKAAAAACCmAgAAAACIqQAAAAAAiKkAAAAAAGIqAAAAAICYCgAAAAAgpgIAAAAAiKkAAAAAAGIqAAAAAICYCgAAAACAmAoAAAAAIKYCAAAAAIipAAAAAABiKgAAAACAmAoAAAAAIKYCAAAAAIipAAAAAACIqQAAAAAAYioAAAAAgJgKAAAAACCmAgAAAACIqQAAAAAAYuo/vV/3x6V/7o4beepzT+lyf9PXc9L9PfXzpu1XXdZQ+nPU+TonPUfT9ufO19m8Yd6oujfZN7Kuc8W1VnF+dp3z92fzZP51tp6z17iYKqbaSB1uxFQxVUwVU8VUMVVMNW+YN8RUMVXkE1PFVPOkmGreEFPFVDHV4UZMFVMNZWKqmCqmiqnmDfOGmCqmiqliqvhknhRTzRtiqpgqpjrciKliqpgqphp+7c9iqnnDvCGmiqliqpgqPpknxVQxVUwVU8VUhxuHGzFVTBVTDb/2ZzHVvGHeEFPFVDFVTBWfxFQx1XoeFVOnbf5i6iXKbdps3Lc+17nL53Ye1Fxn69m+8Zl/nPLesp7dN+cj+3Pm9/V/vngWgdxf82SF++sfdcRUhxsx1eHGfTN0i3z2DcOvfUNMtW+YN+z39mff17whprq/nl8xVUwVNcVUhxuHG0O3fde+Yfi1b4ip9g3zhvtmfxZTxTYx1f31/IqpYqphQUw1JDvcGLrFVOvP8GvfEFO9t8wb7pvzkf1ZbBNT3V/Pr5gqphoWxFTryuHGdTYsWH+GX/uG6yymWs/um/OR/VlMFVPdX/uV9SymOtT7XEOyw42XmH1DTHWdDb/2De8t84b75v1hPQfet87Pfvq6OvXfmSftV9apmOrhE1MNyQ43hm77rn3D8GvfEFPtG+YN9835SEwVU8VU86T9SkwVUw0LYqp15XDjOhv2rT/Dr31DTPXesp7dN+cj+7OYKqaKVPYrMVVMNSyIqdaVw43rbFgQUw2/hl8x1XvLenbfnI/sz2KqmCpS2a/EVDHVod7nGpIdbrzE7BtiqutsPds3vLfMG+6b94f1LKY6L4hU5kkxVUxtvRk+IaYakj+xrlb/lb3V69nh5jq2b3T+XOvP8Lvrczvvz+nX2bxh3jBv1Njvp805nd9H/vH73D4pUmXtz13mus7rWUwVU8VUQ7LDjZgqpoqpYqqYKhKIqeYN84aY6lwmpoqpIpWYKqaKqYZQMdXhxuHG4UZMFVPFVDFVTBVTzRvmDTFVTBVTxVQxVUwVU61TMVVMdbhxuHG4ccgQUx2uxVQxVUw1b5g3xFQxVUwVU8VUMVVMtU7FVC9tMdXhxuFGTBVTHa7FVDFVTDVvmDfs9+YcMVVMFVPFVDHVOhVTRU0x1V/X9dd1/dXr3/4qt31DTPXXou0b9g33zX3Lv372SevKe/8zkc/+kv/X7a1nMVU88blesg437puYav05BDm8mjfsG+YN981+b5+0rsQ2MVVMFVPFVMOMl7Yh2eHGfXPIsP4cgrwHRQL7hnnDfbPf2yetK8+vmOr+iqliqpjqpS2mOty4b6KD9ecQJKaKBPYN+4b7Zr8351hXYqqYKqaKqWKqmCpqiqkON+6b6GD92TfEVDHVvmHfcN/s92KqmCqmiqnmSTFVTBVTvTzFVMOMw42YWuavZFp/DkFiqnnDvmHecN/s9/ZJ68p7v8/nur93yRlpWhQWU8VUMdUw4/6KqaKI9Wf4tT+LqfYN84b7JqZ6H4mp4pP9RUwVU8VU8URMta4cbuwHooj1Z/g1dIup9g3r2X0TU+2T1pX3vpgqplpXYqp4IqZ6yTrc2A/EVOvP8CummjfsG+YN981+b5+0rrz3xVQxVUwVU710fK4h2eHGfXPIEEUMFQ6v3vv2DfOGecN+b5+0rsQ20cv9FVPF1EEPy2o+10v25CY37f7u+G6nrmnSvmE43/M97MV91nPS/mzfMG+YN/L2ps7nhYpR0z5p3+0UU82TvedJMVVMFVPFVIcbhxsx1bAvpoqpYqqYat8wb4ipYqqYKk6IqWKqeVJMFVPFVDHVS9bhRkwVUw3nYqrhV0y1b5g3xFQxVUwVJ8RUMdU8KaaKqWKqmOol63AjpoqphnMx1fArpto3zBtiqpgqpooT9l0x1TwpptqvxFQxVUx1uBFTHaoM52Kq4VdMtW+YN8RUMVVMFVPtu2KqedK6sl+Vi6kAAAAAAMnEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUFwIAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADE1B3er3uppM/t8t1Ofd8nn7t6TSY9qNPWVZdrYE+87Bth195+1fu9v2M9ey9creerpPdg57kOABBTxVSHSDHVM+PQLAiIqWKqdSWm2sPEVDEVABBTHbTEVDFVnHBo9t3EVDHVuhJTvRfEVDEVAEBMFVPFVDFVTBVTxVQx1X4lpoqpYqqYCgAgpoqpYqqYKqaKqdaVmGq/ElPFVDFVTHXwAwDKxNRTw0yXzz0VCSpe56Qh3rry/J68zl3+UWLHz9uxb0w71NuvsqLmjmehcxwzH+SvZ/suACCm+lzRS0y1rjy/YqqYKqaKqWKqmCqmiqkAgJgqxjhEiqnWledXTBVTxVT7lZhqnhRTxVQAQEw1/DpEiqnWledXTBVTxVT7lZgqpoqpYioAIKYafh0ixVRxwvMrpoqpYqr9SkwVUz1vYioAIKaKIg6RTa9zl9hhXXl+xdS86yKm2q+sUzFVTLXvAgBiqijiECmmOixZV2KqQ71Dvf3KOhVTzQfWMwCAmOpQJaaKqdaVmCqmOtR7jsRUMVVMtZ4BAMRUhyrXWUy1rlxn8cSh3n5l37AfiKnWs5gKAIipYozoJaZaV66zmOpQL6aKqWKqmGrfte8CAK1j6teDv9hZ8a94Pvluq7/vtM+dFlPd33l/lTv9OjvUr99fdvzVdfuV92DV+LnjOid9rn1XTAUAxFQx1SFSTHV/xVQx1aFeTPUeFFPFVPuumAoAiKliqkOkmGpdialiqkO9mOo9KKaKqWKqmAoAiKliqsOcQ6Q4IaaKqQ71Yqr9yntQTBVTxVQAQEwVUx0iHSLFCTFVTHWoF1PtV96DYqqYKqYCAETE1C9/1ddfuT34uV3ihHXlr3KLnzX2jS7PpX3j8vxap+Jn4PNRca4DAMRUMVX0ElOtK4dcMVVMFVPtG55f69R9E1MBADFVTBW9xFQx1boSU8VUMdW+IaZap2KqmAoAIKY6VImpYqp1Jab6eWKq51dMtU7FVDEVAEBMdahyGBFTrSsx1aFeTBWp7M9iqpgqpjr4AQBiavGYmvS/dRjpfeizruYdIh3q+9xfkWreP+553qxT+2TdfzwDAMRUMVX0chgRU60rMdXPE1PFVDHVOhVTxVQxFQAQUx2qHEbEVOtKTHWoF1M9v/Zn69T8Yp8UUwEAMdWhyuHVoc+6ElMd6kUCkcr+7L3qPWOfFFMBADFVTHV4deizrsRUMUYkEKm898VU7xn7pJgKALSLqT8dSHYMLjt+l6Qh9NT37Xyduxz60u9v0l5y6jMq3t9T97LzYb3ioT4pUk1775s3vHu8B8VUAEBMFVPFVDFVTBVTxVQxVUy1rswb3j3eg2IqACCmiqkON2KqmCqmiqliqpgqpoqpYqqYKqYCAGKqmOpwI6aKqWKqmGrfEFPFVDFVTBVTxVQAQEwVUx1uRBEx1YFWTBVTxVQxVUwVU8VUMRUAEFMBAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAQEwFAAAAABBTAQAAAADEVAAAAAAAMRUAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAADEVAAAAAEBMBQAAAAAQUwEAAAAAxFQAAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAEFMBAAAAAMRUAAAAAAAxFQAAAABATAUAAAAAQEwFAAAAAPh//gZFPTu5uGIZdgAAAABJRU5ErkJggg==";
151
+
148
152
  // src/history-sanitizer.ts
149
- var RESULT_TYPE_BY_CALL_TYPE = {
153
+ var TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE = {
150
154
  function_call: "function_call_result",
151
155
  computer_call: "computer_call_result",
152
156
  shell_call: "shell_call_output",
@@ -159,6 +163,7 @@ var RESULT_TYPE_BY_CALL_TYPE = {
159
163
  // additionally ride providerData (see callIdOf).
160
164
  tool_search_call: "tool_search_output"
161
165
  };
166
+ var RESULT_TYPE_BY_CALL_TYPE = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
162
167
  var RESULT_TYPES = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE));
163
168
  function itemType(item) {
164
169
  if (!item || typeof item !== "object") {
@@ -466,7 +471,6 @@ function rewriteComputerCallsToActionsOnly(body) {
466
471
  }
467
472
  return changed;
468
473
  }
469
- var EMPTY_IMAGE_URL_PLACEHOLDER = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/iZk9HQAAAABJRU5ErkJggg==";
470
474
  function rewriteEmptyComputerCallOutputImageUrls(body) {
471
475
  if (!body || typeof body !== "object") {
472
476
  return false;
@@ -491,7 +495,7 @@ function rewriteEmptyComputerCallOutputImageUrls(body) {
491
495
  const out = output;
492
496
  const imageUrl = out.image_url;
493
497
  if (typeof imageUrl !== "string" || imageUrl.length === 0) {
494
- out.image_url = EMPTY_IMAGE_URL_PLACEHOLDER;
498
+ out.image_url = SCREENSHOT_FAILURE_CARD_IMAGE_URL;
495
499
  changed = true;
496
500
  }
497
501
  }
@@ -792,7 +796,10 @@ function installCodexToolSearch(agent, connectorNamespaces = NO_NAMESPACES) {
792
796
  var COMPACTION_SUMMARY_MARKER = "opengeni_context_summary";
793
797
  var SUMMARY_BUFFER_TOKENS = 2e4;
794
798
  var COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
795
- var CLIENT_COMPACTION_TRIGGER_FRACTION = 0.9;
799
+ var DEFAULT_COMPACTION_THRESHOLD_RATIO = 0.6;
800
+ var MIN_COMPACTION_THRESHOLD_RATIO = 0.3;
801
+ var MAX_COMPACTION_THRESHOLD_RATIO = 0.9;
802
+ var COMPACTION_FALLBACK_TARGET_RATIO = 0.5;
796
803
  var COMPACTION_PROMPT = [
797
804
  "You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.",
798
805
  "",
@@ -806,12 +813,7 @@ var COMPACTION_PROMPT = [
806
813
  ].join("\n");
807
814
  var SUMMARY_PREFIX = "Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:";
808
815
  var USER_MESSAGE_TRUNCATION_MARKER = "\n[... middle truncated for context compaction ...]\n";
809
- var RESULT_TYPE_BY_CALL_TYPE2 = {
810
- function_call: "function_call_result",
811
- computer_call: "computer_call_result",
812
- shell_call: "shell_call_output",
813
- apply_patch_call: "apply_patch_call_output"
814
- };
816
+ var RESULT_TYPE_BY_CALL_TYPE2 = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
815
817
  var RESULT_TYPES2 = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE2));
816
818
  function itemType2(item) {
817
819
  if (!item || typeof item !== "object") {
@@ -849,12 +851,12 @@ function estimateTokens(items) {
849
851
  }
850
852
  return total;
851
853
  }
854
+ function clampCompactionThresholdRatio(value) {
855
+ const numeric = typeof value === "number" && Number.isFinite(value) ? value : DEFAULT_COMPACTION_THRESHOLD_RATIO;
856
+ return Math.min(MAX_COMPACTION_THRESHOLD_RATIO, Math.max(MIN_COMPACTION_THRESHOLD_RATIO, numeric));
857
+ }
852
858
  function clientCompactionThresholdTokens(input) {
853
- const available = Math.max(
854
- 0,
855
- input.contextWindowTokens - input.contextReservedOutputTokens - SUMMARY_BUFFER_TOKENS
856
- );
857
- return Math.floor(available * CLIENT_COMPACTION_TRIGGER_FRACTION);
859
+ return Math.floor(Math.max(0, input.contextWindowTokens) * clampCompactionThresholdRatio(input.contextCompactionThresholdRatio));
858
860
  }
859
861
  function decideClientCompaction(input) {
860
862
  const thresholdTokens = clientCompactionThresholdTokens(input);
@@ -956,6 +958,58 @@ function buildCompactionReplacementHistory(items, summaryBody) {
956
958
  history.push(buildSummaryItem(summaryBody));
957
959
  return history;
958
960
  }
961
+ function buildDeterministicFallbackCompactionHistory(input) {
962
+ const sourceTokens = Math.max(1, estimateTokens(input.items));
963
+ const requestedTarget = typeof input.targetTokens === "number" && input.targetTokens > 0 ? Math.floor(input.targetTokens) : Math.floor(sourceTokens * COMPACTION_FALLBACK_TARGET_RATIO);
964
+ const targetTokens = Math.max(1, Math.min(requestedTarget, Math.max(1, sourceTokens - 1)));
965
+ const summaryItem = buildSummaryItem([
966
+ "Non-LLM context compaction fallback.",
967
+ input.cause ? `Summarizer failure: ${input.cause}` : "Summarizer failure: unavailable.",
968
+ "Older assistant, tool, reasoning, and image history was dropped deterministically.",
969
+ "Retained context above is limited to initial instructions and the most recent user messages that fit the fallback budget; oversized retained messages may be middle-truncated."
970
+ ].join("\n"));
971
+ const summaryTokens = estimateItemTokens(summaryItem);
972
+ let remaining = Math.max(0, targetTokens - summaryTokens);
973
+ const retainedInstructions = [];
974
+ for (const item of input.items) {
975
+ if (!isInitialInstructionMessage(item)) {
976
+ if (isUserMessage(item)) {
977
+ break;
978
+ }
979
+ continue;
980
+ }
981
+ if (remaining <= 0) {
982
+ break;
983
+ }
984
+ const capped = compactMessageToEstimatedItemBudget(item, Math.min(2e3, remaining));
985
+ if (!capped) {
986
+ continue;
987
+ }
988
+ const tokens = estimateItemTokens(capped);
989
+ if (tokens <= remaining) {
990
+ retainedInstructions.push(capped);
991
+ remaining -= tokens;
992
+ }
993
+ }
994
+ const retainedUsers = [];
995
+ for (let index = input.items.length - 1; index >= 0 && remaining > 0; index -= 1) {
996
+ const item = input.items[index];
997
+ if (!isUserMessage(item) || isCompactionSummary(item)) {
998
+ continue;
999
+ }
1000
+ const capped = compactMessageToEstimatedItemBudget(item, Math.min(COMPACT_USER_MESSAGE_MAX_TOKENS, remaining));
1001
+ if (!capped) {
1002
+ continue;
1003
+ }
1004
+ const tokens = estimateItemTokens(capped);
1005
+ if (tokens <= remaining) {
1006
+ retainedUsers.push(capped);
1007
+ remaining -= tokens;
1008
+ }
1009
+ }
1010
+ retainedUsers.reverse();
1011
+ return [...retainedInstructions, ...retainedUsers, summaryItem];
1012
+ }
959
1013
  function buildSummaryItem(summaryBody) {
960
1014
  const trimmed = summaryBody.trim();
961
1015
  return {
@@ -967,15 +1021,38 @@ ${trimmed}`,
967
1021
  };
968
1022
  }
969
1023
  function compactUserMessage(item) {
1024
+ return compactMessageToTokenBudget(item, COMPACT_USER_MESSAGE_MAX_TOKENS);
1025
+ }
1026
+ function compactMessageToTokenBudget(item, maxTokens) {
970
1027
  const text = messageText(item);
971
1028
  const next = { ...item };
972
- if (estimatedTextTokens(text) > COMPACT_USER_MESSAGE_MAX_TOKENS) {
973
- next.content = truncateMiddleByEstimatedTokens(text, COMPACT_USER_MESSAGE_MAX_TOKENS);
1029
+ if (estimatedTextTokens(text) > maxTokens) {
1030
+ next.content = truncateMiddleByEstimatedTokens(text, maxTokens);
974
1031
  return next;
975
1032
  }
976
1033
  next.content = contentWithoutImages(item);
977
1034
  return next;
978
1035
  }
1036
+ function compactMessageToEstimatedItemBudget(item, maxItemTokens) {
1037
+ if (maxItemTokens <= 0) {
1038
+ return null;
1039
+ }
1040
+ const overheadTokens = estimateItemTokens({ ...item, content: "" });
1041
+ let contentBudget = Math.max(0, maxItemTokens - overheadTokens);
1042
+ for (let attempt = 0; attempt < 6; attempt += 1) {
1043
+ const capped = compactMessageToTokenBudget(item, contentBudget);
1044
+ const estimated = estimateItemTokens(capped);
1045
+ if (estimated <= maxItemTokens) {
1046
+ return capped;
1047
+ }
1048
+ const overage = estimated - maxItemTokens;
1049
+ if (contentBudget <= 0) {
1050
+ break;
1051
+ }
1052
+ contentBudget = Math.max(0, contentBudget - Math.max(1, overage));
1053
+ }
1054
+ return null;
1055
+ }
979
1056
  function estimatedTextTokens(text) {
980
1057
  return Math.ceil(text.length / 4);
981
1058
  }
@@ -1026,8 +1103,29 @@ function messageText(item) {
1026
1103
  }
1027
1104
  return "";
1028
1105
  }
1029
- function renderCompactionPromptInputForChat(input) {
1030
- return input.map(renderItem).join("\n");
1106
+ function isInitialInstructionMessage(item) {
1107
+ const type = itemType2(item);
1108
+ const role = itemRole(item);
1109
+ return type === "message" && (role === "system" || role === "developer");
1110
+ }
1111
+ function renderCompactionPromptInputForChat(input, options = {}) {
1112
+ const rendered = input.map(renderItem);
1113
+ if (typeof options.maxEstimatedTokens !== "number" || options.maxEstimatedTokens <= 0) {
1114
+ return rendered.join("\n");
1115
+ }
1116
+ const maxChars = Math.max(1, Math.floor(options.maxEstimatedTokens * 4));
1117
+ const last = rendered.at(-1);
1118
+ const prefix = rendered.slice(0, -1);
1119
+ let kept = prefix.slice();
1120
+ while (kept.length > 0 && transcriptLength([...kept, last].filter((line) => line !== void 0)) > maxChars) {
1121
+ kept.shift();
1122
+ }
1123
+ const lines = [...kept, last].filter((line) => line !== void 0);
1124
+ const joined = lines.join("\n");
1125
+ if (joined.length <= maxChars) {
1126
+ return joined;
1127
+ }
1128
+ return truncateMiddleByChars(joined, maxChars);
1031
1129
  }
1032
1130
  function renderItem(item) {
1033
1131
  const type = itemType2(item) ?? "unknown";
@@ -1073,6 +1171,24 @@ function truncateForTranscript(text, max) {
1073
1171
  }
1074
1172
  return `${text.slice(0, max)}... (${text.length - max} more chars)`;
1075
1173
  }
1174
+ function transcriptLength(lines) {
1175
+ if (lines.length === 0) {
1176
+ return 0;
1177
+ }
1178
+ return lines.reduce((sum, line) => sum + line.length, 0) + Math.max(0, lines.length - 1);
1179
+ }
1180
+ function truncateMiddleByChars(text, maxChars) {
1181
+ if (text.length <= maxChars) {
1182
+ return text;
1183
+ }
1184
+ if (maxChars <= USER_MESSAGE_TRUNCATION_MARKER.length) {
1185
+ return USER_MESSAGE_TRUNCATION_MARKER.slice(0, maxChars);
1186
+ }
1187
+ const keepChars = maxChars - USER_MESSAGE_TRUNCATION_MARKER.length;
1188
+ const headChars = Math.ceil(keepChars / 2);
1189
+ const tailChars = Math.floor(keepChars / 2);
1190
+ return `${text.slice(0, headChars)}${USER_MESSAGE_TRUNCATION_MARKER}${text.slice(text.length - tailChars)}`;
1191
+ }
1076
1192
 
1077
1193
  // src/sandbox-computer.ts
1078
1194
  import { computerTool, tool } from "@openai/agents";
@@ -1091,6 +1207,7 @@ var SCROLL_NOTCH_PIXELS = 100;
1091
1207
  var SCROLL_MAX_CLICKS = 15;
1092
1208
  var SCREENSHOT_WARMUP_BUDGET_MS = 3e4;
1093
1209
  var SCREENSHOT_RETRY_DELAY_MS = 750;
1210
+ var SCREENSHOT_READ_CHUNK_BYTES = 98304;
1094
1211
  var KEYSYM = {
1095
1212
  ctrl: "ctrl",
1096
1213
  control: "ctrl",
@@ -1131,6 +1248,12 @@ var ComputerUnavailableError = class extends Error {
1131
1248
  this.name = "ComputerUnavailableError";
1132
1249
  }
1133
1250
  };
1251
+ var ScreenshotReadError = class extends Error {
1252
+ constructor(message) {
1253
+ super(message);
1254
+ this.name = "ScreenshotReadError";
1255
+ }
1256
+ };
1134
1257
  var ComputerReadOnlyError = class extends Error {
1135
1258
  constructor() {
1136
1259
  super("computer-use is read-only \u2014 write actions are disabled");
@@ -1234,6 +1357,9 @@ var SandboxComputer = class {
1234
1357
  return Buffer.from(bytes).toString("base64");
1235
1358
  } catch (error) {
1236
1359
  lastError = error;
1360
+ if (error instanceof ScreenshotReadError) {
1361
+ throw error;
1362
+ }
1237
1363
  } finally {
1238
1364
  await this.x(`rm -f ${f}`).catch(() => void 0);
1239
1365
  }
@@ -1246,34 +1372,66 @@ var SandboxComputer = class {
1246
1372
  }
1247
1373
  throw new ComputerUnavailableError("scrot produced an empty screenshot (display not up?)");
1248
1374
  }
1249
- // Read the screenshot PNG bytes by base64-ing the absolute /tmp path through the
1250
- // SAME command primitive (exec ?? execCommand) — NOT `session.readFile` (Modal
1375
+ // Run a read-only command over the SAME command primitive computer actions use
1376
+ // (exec ?? execCommand) and return its RAW stdout body — NOT `session.readFile` (Modal
1251
1377
  // path-validates against /workspace and rejects /tmp) and NOT `this.x()` (its
1252
- // `sandboxCommandOutput` parser drops the execCommand STRING body, returning ""
1253
- // — only the exec-object path has a structured body). We capture the RAW result,
1254
- // strip the execCommand banner ("…Output:\n<base64>"), strip whitespace, and
1255
- // decode. Binary-safe: base64 of the scrot is plain ASCII over stdout, no
1256
- // truncation (maxOutputTokens:null), mirroring recording.ts readRecordingBytes.
1257
- async readScreenshotBytes(path) {
1378
+ // `sandboxCommandOutput` parser drops the execCommand STRING body). exec exposes a
1379
+ // structured stdout; execCommand returns the formatted STRING, so we strip its banner
1380
+ // ("…Output:\n<body>") to recover the body.
1381
+ //
1382
+ // ROUTING-PROXY SEAM: when the selfhosted feature is on, the turn's box is wrapped in a
1383
+ // `RoutingSandboxSession`, which ALWAYS exposes an `exec` method — but for a Modal-backed
1384
+ // box (no native `exec`) that method internally falls back to `execCommand` and returns
1385
+ // the formatted STRING, not a `{output}` object. `sandboxCommandOutput` returns "" for a
1386
+ // string, so a naive `sandboxCommandOutput(await session.exec())` silently dropped the
1387
+ // whole screenshot body → empty read → "display not up" error card on EVERY Modal
1388
+ // computer-use turn once routing was enabled. So a STRING exec result is banner-stripped
1389
+ // exactly like the direct execCommand path; only a structured object goes to
1390
+ // sandboxCommandOutput.
1391
+ async readCmdRaw(cmd) {
1258
1392
  const args = {
1259
- cmd: `DISPLAY=${this.display} base64 ${path}`,
1393
+ cmd,
1260
1394
  ...this.runAs ? { runAs: this.runAs } : {},
1261
1395
  yieldTimeMs: ACTION_YIELD_MS,
1262
- // null disables the provider's output truncation so a full-screen PNG's
1263
- // base64 is never clipped (the SDK's truncateOutput passes through on null).
1396
+ // null disables the provider's TOKEN truncation; the byte cap this method chunks
1397
+ // around is a separate, lower-level exec-stdout buffer limit.
1264
1398
  maxOutputTokens: null
1265
1399
  };
1266
- let raw;
1267
1400
  if (typeof this.session.exec === "function") {
1268
- raw = sandboxCommandOutput(await this.session.exec(args));
1269
- } else if (typeof this.session.execCommand === "function") {
1270
- raw = stripExecBanner(await this.session.execCommand(args));
1271
- } else {
1272
- throw new ComputerUnavailableError("session cannot run commands (no exec/execCommand) \u2014 screenshots unavailable");
1401
+ const result = await this.session.exec(args);
1402
+ return typeof result === "string" ? stripExecBanner(result) : sandboxCommandOutput(result);
1403
+ }
1404
+ if (typeof this.session.execCommand === "function") {
1405
+ return stripExecBanner(await this.session.execCommand(args));
1406
+ }
1407
+ throw new ComputerUnavailableError("session cannot run commands (no exec/execCommand) \u2014 screenshots unavailable");
1408
+ }
1409
+ // Read the screenshot PNG bytes off the box. A SINGLE `base64 <file>` over Modal's
1410
+ // exec silently returns "" once the base64 exceeds the exec-stdout buffer cap (a full
1411
+ // desktop ~296 KB base64 trips it — the blank-frame incident). So we size the file
1412
+ // first, then base64 it in SCREENSHOT_READ_CHUNK_BYTES-sized, 3-byte-aligned chunks
1413
+ // (each read's base64 stays well under the cap) and reconstruct — validating the total
1414
+ // against the on-box size and failing LOUD on any short read rather than handing back a
1415
+ // truncated/blank frame. Binary-safe: base64 is plain ASCII over stdout.
1416
+ async readScreenshotBytes(path) {
1417
+ const sizeRaw = (await this.readCmdRaw(`wc -c < ${path} 2>/dev/null`)).replace(/[^0-9]/g, "");
1418
+ const fileSize = Number.parseInt(sizeRaw, 10);
1419
+ if (!Number.isFinite(fileSize) || fileSize <= 0) return new Uint8Array();
1420
+ const chunks = [];
1421
+ const nChunks = Math.ceil(fileSize / SCREENSHOT_READ_CHUNK_BYTES);
1422
+ for (let i = 0; i < nChunks; i++) {
1423
+ const raw = await this.readCmdRaw(
1424
+ `dd if=${path} bs=${SCREENSHOT_READ_CHUNK_BYTES} skip=${i} count=1 2>/dev/null | base64`
1425
+ );
1426
+ chunks.push(Buffer.from(raw.replace(/\s+/g, ""), "base64"));
1427
+ }
1428
+ const bytes = Buffer.concat(chunks);
1429
+ if (bytes.length !== fileSize) {
1430
+ throw new ScreenshotReadError(
1431
+ `screenshot read reconstructed ${bytes.length}B of ${fileSize}B (${nChunks} chunk(s), path=${path}) \u2014 a chunk was truncated by the exec-output cap; frame incomplete`
1432
+ );
1273
1433
  }
1274
- const b64 = raw.replace(/\s+/g, "");
1275
- if (b64.length === 0) return new Uint8Array();
1276
- return Uint8Array.from(Buffer.from(b64, "base64"));
1434
+ return new Uint8Array(bytes);
1277
1435
  }
1278
1436
  async click(xp, yp, button) {
1279
1437
  this.guardWrite();
@@ -1328,11 +1486,19 @@ var POINTER_BUTTON = {
1328
1486
  back: PointerButton.POINTER_BUTTON_UNSPECIFIED,
1329
1487
  forward: PointerButton.POINTER_BUTTON_UNSPECIFIED
1330
1488
  };
1489
+ var NATIVE_SCREENSHOT_WARMUP_BUDGET_MS = 6e3;
1490
+ var NATIVE_SCREENSHOT_RETRY_DELAY_MS = 400;
1491
+ function isTerminalCaptureDenial(error) {
1492
+ const msg = (error instanceof Error ? error.message : String(error ?? "")).toLowerCase();
1493
+ return msg.includes("screen recording") || msg.includes("permission is not granted") || msg.includes("consent");
1494
+ }
1331
1495
  var NativeDesktopComputer = class {
1332
1496
  environment;
1333
1497
  dimensions;
1334
1498
  session;
1335
1499
  readOnly;
1500
+ screenshotWarmupBudgetMs;
1501
+ screenshotRetryDelayMs;
1336
1502
  // The ENCODED vs NATIVE geometry of the MOST RECENT screenshot the model saw. The
1337
1503
  // model computes click coordinates in the encoded-pixel space of that screenshot;
1338
1504
  // when the agent downscaled the PNG to fit the transport budget, encoded < native,
@@ -1347,6 +1513,8 @@ var NativeDesktopComputer = class {
1347
1513
  this.dimensions = opts.dimensions ?? DEFAULT_DIMENSIONS;
1348
1514
  this.environment = opts.environment ?? "ubuntu";
1349
1515
  this.readOnly = opts.readOnly ?? false;
1516
+ this.screenshotWarmupBudgetMs = opts.screenshotWarmupBudgetMs ?? NATIVE_SCREENSHOT_WARMUP_BUDGET_MS;
1517
+ this.screenshotRetryDelayMs = opts.screenshotRetryDelayMs ?? NATIVE_SCREENSHOT_RETRY_DELAY_MS;
1350
1518
  }
1351
1519
  /** Rebind to a freshly resumed-by-id session after a box rollover / re-establish. */
1352
1520
  rebind(session) {
@@ -1376,13 +1544,36 @@ var NativeDesktopComputer = class {
1376
1544
  await this.session.desktopInput({ $case: "pointer", pointer: { x: n.x, y: n.y, action, button } });
1377
1545
  }
1378
1546
  async screenshot() {
1379
- const { png, width, height, nativeWidth, nativeHeight } = await this.session.screenshot();
1380
- if (png.length === 0) {
1381
- throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1547
+ let lastError;
1548
+ const deadline = Date.now() + this.screenshotWarmupBudgetMs;
1549
+ let attempt = 0;
1550
+ while (true) {
1551
+ if (attempt > 0) {
1552
+ await new Promise((r) => setTimeout(r, this.screenshotRetryDelayMs));
1553
+ }
1554
+ attempt++;
1555
+ try {
1556
+ const { png, width, height, nativeWidth, nativeHeight } = await this.session.screenshot();
1557
+ if (png.length === 0) {
1558
+ throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1559
+ }
1560
+ this.lastEncoded = [width, height];
1561
+ this.lastNative = [nativeWidth || width, nativeHeight || height];
1562
+ return Buffer.from(png).toString("base64");
1563
+ } catch (error) {
1564
+ lastError = error;
1565
+ if (isTerminalCaptureDenial(error)) break;
1566
+ }
1567
+ if (Date.now() + this.screenshotRetryDelayMs >= deadline) {
1568
+ break;
1569
+ }
1382
1570
  }
1383
- this.lastEncoded = [width, height];
1384
- this.lastNative = [nativeWidth || width, nativeHeight || height];
1385
- return Buffer.from(png).toString("base64");
1571
+ const reason = lastError instanceof Error ? lastError.message : String(lastError);
1572
+ console.warn(`[NativeDesktopComputer] screenshot failed after ${attempt} attempt(s): ${reason}`);
1573
+ if (lastError instanceof Error) {
1574
+ throw lastError;
1575
+ }
1576
+ throw new ComputerUnavailableError("native desktop screenshot returned an empty frame (display not up?)");
1386
1577
  }
1387
1578
  async click(x, y, button) {
1388
1579
  this.guardWrite();
@@ -1668,9 +1859,16 @@ function ensureReadableStreamFrom() {
1668
1859
  }
1669
1860
  });
1670
1861
  }
1862
+ var runtimeMetricsHooks = null;
1863
+ function configureRuntimeMetricsHooks(hooks) {
1864
+ runtimeMetricsHooks = hooks ?? null;
1865
+ }
1671
1866
  function createProductionAgentRuntime(overrides = {}) {
1672
1867
  return {
1673
- configure: configureOpenAI,
1868
+ configure: (settings) => {
1869
+ configureRuntimeMetricsHooks(overrides.metrics);
1870
+ configureOpenAI(settings);
1871
+ },
1674
1872
  // A test/override model shadows the registry routing entirely (the scripted
1675
1873
  // model used in worker tests is not in any provider's allow-list), so when
1676
1874
  // one is supplied resolveTurnModel reports "no resolution" and the caller
@@ -1689,7 +1887,7 @@ function createProductionAgentRuntime(overrides = {}) {
1689
1887
  serializeApprovals
1690
1888
  };
1691
1889
  }
1692
- function buildOpenAIClientFromSettings(settings) {
1890
+ function buildOpenAIClientFromSettings(settings, providerId = settings.openaiProvider) {
1693
1891
  if (settings.openaiProvider === "azure") {
1694
1892
  const baseURL = settings.azureOpenaiBaseUrl ?? azureDeploymentBaseUrl(settings);
1695
1893
  const apiKey = settings.azureOpenaiApiKey ?? settings.azureOpenaiAdToken ?? "azure-ad-token";
@@ -1704,13 +1902,14 @@ function buildOpenAIClientFromSettings(settings) {
1704
1902
  // seam — below the SDK responses converter, which always re-synthesizes BOTH
1705
1903
  // `action` and `actions` (rejected 400 "exactly one of action or actions").
1706
1904
  // See computerCallNormalizingFetch / rewriteComputerCallsToActionsOnly.
1707
- fetch: computerCallNormalizingFetch(globalThis.fetch)
1905
+ fetch: computerCallNormalizingFetch(instrumentedModelFetch(providerId, globalThis.fetch))
1708
1906
  });
1709
1907
  }
1710
1908
  return new OpenAI({
1711
1909
  apiKey: settings.openaiApiKey ?? process.env.OPENAI_API_KEY,
1712
1910
  ...settings.openaiBaseUrl ? { baseURL: settings.openaiBaseUrl } : {},
1713
- maxRetries: settings.openaiMaxRetries
1911
+ maxRetries: settings.openaiMaxRetries,
1912
+ fetch: instrumentedModelFetch(providerId, globalThis.fetch)
1714
1913
  });
1715
1914
  }
1716
1915
  var providerClientCache = /* @__PURE__ */ new Map();
@@ -1719,17 +1918,18 @@ function buildProviderClient(provider, settings) {
1719
1918
  if (cached) {
1720
1919
  return cached;
1721
1920
  }
1722
- const client = provider.builtin ? buildOpenAIClientFromSettings(settings) : provider.kind === "codex-subscription" ? new OpenAI({
1921
+ const client = provider.builtin ? buildOpenAIClientFromSettings(settings, provider.id) : provider.kind === "codex-subscription" ? new OpenAI({
1723
1922
  apiKey: provider.apiKey ?? "codex-subscription",
1724
1923
  ...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
1725
1924
  maxRetries: settings.openaiMaxRetries,
1726
- fetch: codexSubscriptionFetch(globalThis.fetch)
1925
+ fetch: codexSubscriptionFetch(instrumentedModelFetch(provider.id, globalThis.fetch))
1727
1926
  }) : new OpenAI({
1728
1927
  ...provider.apiKey ? { apiKey: provider.apiKey } : {},
1729
1928
  ...provider.baseUrl ? { baseURL: provider.baseUrl } : {},
1730
1929
  maxRetries: settings.openaiMaxRetries,
1731
1930
  ...provider.defaultQuery ? { defaultQuery: provider.defaultQuery } : {},
1732
- ...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {}
1931
+ ...provider.defaultHeaders ? { defaultHeaders: provider.defaultHeaders } : {},
1932
+ fetch: instrumentedModelFetch(provider.id, globalThis.fetch)
1733
1933
  });
1734
1934
  providerClientCache.set(provider.id, client);
1735
1935
  return client;
@@ -1797,6 +1997,7 @@ var CodexSubscriptionUnavailableError = class extends Error {
1797
1997
  };
1798
1998
  function configureOpenAI(settings) {
1799
1999
  setOpenAIResponsesTransport(settings.openaiResponsesTransport);
2000
+ setTracingDisabled(settings.disableOpenaiTracing || !settings.observabilityOtlpEndpoint);
1800
2001
  const router = new MultiProviderModelProvider(settings);
1801
2002
  if (settings.openaiProvider === "azure") {
1802
2003
  setDefaultOpenAIClient(buildOpenAIClientFromSettings(settings));
@@ -1811,17 +2012,56 @@ function configureOpenAI(settings) {
1811
2012
  }
1812
2013
  setDefaultModelProvider(router);
1813
2014
  }
2015
+ function instrumentedModelFetch(provider, inner) {
2016
+ return (async (input, init) => {
2017
+ if (!isModelCallFetch(input)) {
2018
+ return await inner(input, init);
2019
+ }
2020
+ const started = performance.now();
2021
+ try {
2022
+ const response = await inner(input, init);
2023
+ recordModelCallMetric(provider, response.ok ? "completed" : "failed", started);
2024
+ return response;
2025
+ } catch (error) {
2026
+ recordModelCallMetric(provider, "failed", started);
2027
+ throw error;
2028
+ }
2029
+ });
2030
+ }
2031
+ function isModelCallFetch(input) {
2032
+ const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
2033
+ if (typeof rawUrl !== "string" || rawUrl.length === 0) {
2034
+ return false;
2035
+ }
2036
+ try {
2037
+ const pathname = new URL(rawUrl, "http://opengeni.local").pathname;
2038
+ return pathname.endsWith("/responses") || pathname.endsWith("/chat/completions") || pathname.endsWith("/codex/responses");
2039
+ } catch {
2040
+ return /\/(?:codex\/)?responses(?:\?|$)|\/chat\/completions(?:\?|$)/.test(rawUrl);
2041
+ }
2042
+ }
2043
+ function recordModelCallMetric(provider, outcome, started) {
2044
+ const durationSeconds = Math.max(0, (performance.now() - started) / 1e3);
2045
+ try {
2046
+ runtimeMetricsHooks?.onModelCall?.({ provider, outcome, durationSeconds });
2047
+ } catch {
2048
+ }
2049
+ }
1814
2050
  async function summarizeForCompaction(settings, input, options = {}) {
1815
2051
  const client = options.client ?? buildOpenAIClientFromSettings(settings);
1816
2052
  const api = options.api ?? "responses";
1817
2053
  const model = options.model ?? settings.openaiModel;
1818
2054
  const maxTokens = options.maxOutputTokens ?? SUMMARY_BUFFER_TOKENS;
2055
+ const transcript = renderCompactionPromptInputForChat(
2056
+ input,
2057
+ typeof options.maxTranscriptTokens === "number" && options.maxTranscriptTokens > 0 ? { maxEstimatedTokens: options.maxTranscriptTokens } : {}
2058
+ );
1819
2059
  try {
1820
2060
  if (api === "chat") {
1821
2061
  const completion = await client.chat.completions.create({
1822
2062
  model,
1823
2063
  max_tokens: maxTokens,
1824
- messages: [{ role: "user", content: renderCompactionPromptInputForChat(input) }]
2064
+ messages: [{ role: "user", content: transcript }]
1825
2065
  });
1826
2066
  const text2 = completion.choices?.[0]?.message?.content;
1827
2067
  const trimmed2 = typeof text2 === "string" ? text2.trim() : "";
@@ -1834,13 +2074,13 @@ async function summarizeForCompaction(settings, input, options = {}) {
1834
2074
  // built-in path (api "responses"), so gate it on the built-in provider.
1835
2075
  ...settings.openaiProvider === "azure" ? {} : { store: false },
1836
2076
  max_output_tokens: maxTokens,
1837
- input
2077
+ input: transcript
1838
2078
  });
1839
2079
  const text = extractResponseOutputText(response);
1840
2080
  const trimmed = text.trim();
1841
2081
  return trimmed.length > 0 ? trimmed : null;
1842
2082
  } catch (error) {
1843
- console.error("context compaction summarize failed (compaction skipped this turn)", error);
2083
+ console.error("context compaction summarize failed", error);
1844
2084
  return null;
1845
2085
  }
1846
2086
  }
@@ -1916,7 +2156,13 @@ function appendGenesisTitleDirective(instructions, genesisTitleHint) {
1916
2156
  var agentFileDownloads = /* @__PURE__ */ new WeakMap();
1917
2157
  var agentRepositoryCloneHooks = /* @__PURE__ */ new WeakMap();
1918
2158
  var agentGitTokenSeed = /* @__PURE__ */ new WeakMap();
2159
+ var agentToolspaceTokenSeed = /* @__PURE__ */ new WeakMap();
1919
2160
  var agentActiveSandboxBackend = /* @__PURE__ */ new WeakMap();
2161
+ function mcpToolErrorOutput(error) {
2162
+ const details = error instanceof Error ? error.message : String(error);
2163
+ return { isError: true, content: [{ type: "text", text: `An error occurred while running the tool. Please try again. Error: ${details}` }] };
2164
+ }
2165
+ var mcpToolErrorFunction = ({ error }) => mcpToolErrorOutput(error);
1920
2166
  function buildOpenGeniAgent(settings, resources, options = {}) {
1921
2167
  const compactionMode = options.compactionMode ?? resolveContextCompactionMode(settings);
1922
2168
  const hostedWebSearch = options.hostedWebSearch ?? settings.webSearchEnabled;
@@ -1975,11 +2221,19 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
1975
2221
  // `new SandboxAgent({ ...baseConfig, ... })` path via the shared baseConfig
1976
2222
  // spread; the SDK concatenates these with MCP and sandbox capability tools.
1977
2223
  ...hostedTools.length ? { tools: hostedTools } : {},
1978
- ...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {}
2224
+ ...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {},
2225
+ // Surface FAILED MCP tool calls as `{ isError: true }` tool output (see
2226
+ // mcpToolErrorFunction / mcpToolErrorOutput) instead of the SDK's default
2227
+ // flat error string, so a thrown MCP failure (protocol error, auth, timeout,
2228
+ // tool-not-found) settles the timeline tool to "failed" rather than rendering
2229
+ // as success. Applies to every MCP server on this agent (session, first-party,
2230
+ // capability, codex_apps) since none set a server-level errorFunction.
2231
+ mcpConfig: { errorFunction: mcpToolErrorFunction }
1979
2232
  };
1980
2233
  if (settings.sandboxBackend === "none") {
1981
2234
  const agent2 = new Agent(baseConfig);
1982
2235
  maybeInstallCodexToolSearch(agent2, settings, options);
2236
+ applyMcpApprovalPolicy(agent2, settings);
1983
2237
  return agent2;
1984
2238
  }
1985
2239
  const runAs = sandboxRunAs(settings);
@@ -2002,7 +2256,11 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
2002
2256
  if (options.gitTokenSeed) {
2003
2257
  agentGitTokenSeed.set(agent, options.gitTokenSeed);
2004
2258
  }
2259
+ if (options.toolspaceTokenSeed) {
2260
+ agentToolspaceTokenSeed.set(agent, options.toolspaceTokenSeed);
2261
+ }
2005
2262
  maybeInstallCodexToolSearch(agent, settings, options);
2263
+ applyMcpApprovalPolicy(agent, settings);
2006
2264
  return agent;
2007
2265
  }
2008
2266
  function maybeInstallCodexToolSearch(agent, settings, options) {
@@ -2013,6 +2271,41 @@ function maybeInstallCodexToolSearch(agent, settings, options) {
2013
2271
  );
2014
2272
  }
2015
2273
  }
2274
+ function mcpToolRequiresApproval(policy, unprefixedName) {
2275
+ return policy === true || Array.isArray(policy) && policy.includes(unprefixedName);
2276
+ }
2277
+ function installMcpApprovalPolicy(agent, policies) {
2278
+ const listMcpTools = agent.getMcpTools.bind(agent);
2279
+ agent.getMcpTools = async (runContext) => {
2280
+ const tools = await listMcpTools(runContext);
2281
+ return tools.map((tool2) => {
2282
+ if (tool2.type !== "function") {
2283
+ return tool2;
2284
+ }
2285
+ const policy = policies.find((entry) => tool2.name.startsWith(entry.prefix));
2286
+ if (!policy) {
2287
+ return tool2;
2288
+ }
2289
+ const unprefixed = tool2.name.slice(policy.prefix.length);
2290
+ return mcpToolRequiresApproval(policy.requireApproval, unprefixed) ? { ...tool2, needsApproval: async () => true } : tool2;
2291
+ });
2292
+ };
2293
+ const originalClone = agent.clone?.bind(agent);
2294
+ if (originalClone) {
2295
+ agent.clone = (config) => {
2296
+ const cloned = originalClone(config);
2297
+ installMcpApprovalPolicy(cloned, policies);
2298
+ return cloned;
2299
+ };
2300
+ }
2301
+ }
2302
+ function applyMcpApprovalPolicy(agent, settings) {
2303
+ const policies = settings.mcpServers.filter((server) => server.requireApproval === true || Array.isArray(server.requireApproval) && server.requireApproval.length > 0).map((server) => ({ prefix: prefixedMcpToolName(server.id, ""), requireApproval: server.requireApproval })).sort((a, b) => b.prefix.length - a.prefix.length);
2304
+ if (policies.length === 0) {
2305
+ return;
2306
+ }
2307
+ installMcpApprovalPolicy(agent, policies);
2308
+ }
2016
2309
  function neutralizeStructuredToolTransport(capability) {
2017
2310
  const forceFunctionTransport = function() {
2018
2311
  this._modelInstance = void 0;
@@ -2062,6 +2355,8 @@ async function prepareAgentTools(settings, tools, options = {}) {
2062
2355
  throw new Error(`Unknown MCP server id: ${tool2.id}`);
2063
2356
  }
2064
2357
  const url = firstPartyMcpServerUrlForRun(settings, config, options.workspaceId) ?? config.url;
2358
+ const baseFetch = isCodexAppsMcpServer(config) ? codexAppsSanitizingFetch(globalThis.fetch, codexConnectorNamespaces) : globalThis.fetch;
2359
+ const fetchImpl = config.connectionRef ? connectionBrokerFetch(baseFetch, config, options) : baseFetch;
2065
2360
  const server = new PrefixedMcpServer(new MCPServerStreamableHttp({
2066
2361
  url,
2067
2362
  name: config.name ?? config.id,
@@ -2070,7 +2365,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
2070
2365
  // MCP SDK's strict Tool schema rejects (fails the turn during tools/list);
2071
2366
  // sanitize the response on the wire before validation. The namespace Set
2072
2367
  // also captures each tool's original connector namespace (P4 Part B.1).
2073
- ...isCodexAppsMcpServer(config) ? { fetch: codexAppsSanitizingFetch(globalThis.fetch, codexConnectorNamespaces) } : {},
2368
+ ...fetchImpl !== globalThis.fetch ? { fetch: fetchImpl } : {},
2074
2369
  ...await mcpServerRequestInit(settings, config, options),
2075
2370
  ...config.timeoutMs ? {
2076
2371
  timeout: config.timeoutMs,
@@ -2078,7 +2373,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
2078
2373
  } : {}
2079
2374
  }), config.id, config.allowedTools);
2080
2375
  const optional = tool2.optional === true;
2081
- return { server, bestEffort: isCodexAppsMcpServer(config) || optional, optional };
2376
+ return { server, bestEffort: isCodexAppsMcpServer(config) || optional || !!config.connectionRef, optional };
2082
2377
  }));
2083
2378
  const requiredServers = servers.filter((entry) => !entry.bestEffort).map((entry) => entry.server);
2084
2379
  const bestEffortServers = servers.filter((entry) => entry.bestEffort).map((entry) => entry.server);
@@ -2116,6 +2411,190 @@ async function prepareAgentTools(settings, tools, options = {}) {
2116
2411
  codexConnectorNamespaces
2117
2412
  };
2118
2413
  }
2414
+ function connectionBrokerFetch(baseFetch, config, options) {
2415
+ const connectionRef = config.connectionRef;
2416
+ if (!connectionRef) {
2417
+ return baseFetch;
2418
+ }
2419
+ return async (input, init) => {
2420
+ const request = await mcpRequestInfo(input, init);
2421
+ const first = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, false);
2422
+ if (first.status === "auth_needed") {
2423
+ return await authNeededFetchResponse(options, config.id, request, first, connectionRef);
2424
+ }
2425
+ const response = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, first.headers));
2426
+ if (response.status === 401) {
2427
+ const refreshed = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, true);
2428
+ if (refreshed.status === "auth_needed") {
2429
+ return await authNeededFetchResponse(options, config.id, request, refreshed, connectionRef);
2430
+ }
2431
+ const retry = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, refreshed.headers));
2432
+ if (retry.status === 403) {
2433
+ const auth = insufficientScopeAuth(retry.headers, connectionRef, refreshed.connectionId);
2434
+ return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : retry;
2435
+ }
2436
+ if (retry.status === 401) {
2437
+ return await authNeededFetchResponse(options, config.id, request, {
2438
+ status: "auth_needed",
2439
+ reason: "expired",
2440
+ providerDomain: connectionRef.providerDomain,
2441
+ connectionId: refreshed.connectionId,
2442
+ ...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
2443
+ ...connectionRef.resource ? { resource: connectionRef.resource } : {}
2444
+ }, connectionRef);
2445
+ }
2446
+ return retry;
2447
+ }
2448
+ if (response.status === 403) {
2449
+ const auth = insufficientScopeAuth(response.headers, connectionRef, first.connectionId);
2450
+ return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : response;
2451
+ }
2452
+ return response;
2453
+ };
2454
+ }
2455
+ async function resolveConnectionForRequest(options, serverId, connectionRef, toolName, forceRefresh) {
2456
+ if (!options.workspaceId || !options.resolveCredential) {
2457
+ return {
2458
+ status: "auth_needed",
2459
+ reason: "missing_connection",
2460
+ providerDomain: connectionRef.providerDomain,
2461
+ ...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
2462
+ ...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
2463
+ ...connectionRef.resource ? { resource: connectionRef.resource } : {}
2464
+ };
2465
+ }
2466
+ const request = {
2467
+ workspaceId: options.workspaceId,
2468
+ serverId,
2469
+ connectionRef,
2470
+ forceRefresh,
2471
+ ...toolName ? { toolName } : {},
2472
+ ...options.subjectId ? { subjectId: options.subjectId } : {}
2473
+ };
2474
+ try {
2475
+ return await options.resolveCredential(request);
2476
+ } catch {
2477
+ return {
2478
+ status: "auth_needed",
2479
+ reason: "refresh_failed",
2480
+ providerDomain: connectionRef.providerDomain,
2481
+ ...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
2482
+ ...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
2483
+ ...connectionRef.resource ? { resource: connectionRef.resource } : {}
2484
+ };
2485
+ }
2486
+ }
2487
+ function insufficientScopeAuth(headers, connectionRef, connectionId) {
2488
+ const challenge = parseWwwAuthenticate(headers.get("www-authenticate"));
2489
+ if (challenge.error !== "insufficient_scope") {
2490
+ return null;
2491
+ }
2492
+ return {
2493
+ status: "auth_needed",
2494
+ reason: "insufficient_scope",
2495
+ providerDomain: connectionRef.providerDomain,
2496
+ connectionId,
2497
+ ...challenge.scope?.length ? { scopes: challenge.scope } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
2498
+ ...challenge.resource ? { resource: challenge.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {}
2499
+ };
2500
+ }
2501
+ async function authNeededFetchResponse(options, serverId, request, auth, connectionRef) {
2502
+ const connectionId = auth.connectionId ?? connectionRef.connectionId;
2503
+ await publishAuthNeeded(options, {
2504
+ serverId,
2505
+ toolName: request.toolName ?? null,
2506
+ providerDomain: auth.providerDomain,
2507
+ reason: auth.reason,
2508
+ ...connectionId ? { connectionId } : {},
2509
+ ...auth.scopes ? { scopes: auth.scopes } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
2510
+ ...auth.resource ? { resource: auth.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {},
2511
+ ...auth.authorizationUrl ? { authorizationUrl: auth.authorizationUrl } : {},
2512
+ ...options.subjectId ? { subjectId: options.subjectId } : {}
2513
+ });
2514
+ if (request.method === "tools/call") {
2515
+ return mcpToolAuthNeededResponse(request.id);
2516
+ }
2517
+ return new Response("Authentication required for MCP server connection", { status: 401 });
2518
+ }
2519
+ async function publishAuthNeeded(options, payload) {
2520
+ try {
2521
+ await options.onAuthNeeded?.(payload);
2522
+ } catch {
2523
+ }
2524
+ }
2525
+ async function mcpRequestInfo(input, init) {
2526
+ const body = typeof init?.body === "string" ? init.body : input instanceof Request && (init?.method ?? input.method).toUpperCase() === "POST" ? await input.clone().text().catch(() => "") : "";
2527
+ if (!body) {
2528
+ return {};
2529
+ }
2530
+ try {
2531
+ const parsed = JSON.parse(body);
2532
+ const method = typeof parsed.method === "string" ? parsed.method : void 0;
2533
+ const id = typeof parsed.id === "string" || typeof parsed.id === "number" || parsed.id === null ? parsed.id : void 0;
2534
+ const toolName = method === "tools/call" && typeof parsed.params?.name === "string" ? parsed.params.name : void 0;
2535
+ return {
2536
+ ...method ? { method } : {},
2537
+ ...id !== void 0 ? { id } : {},
2538
+ ...toolName ? { toolName } : {}
2539
+ };
2540
+ } catch {
2541
+ return {};
2542
+ }
2543
+ }
2544
+ function withConnectionHeaders(input, init, authHeaders) {
2545
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
2546
+ for (const [name, value] of Object.entries(authHeaders)) {
2547
+ headers.set(name, value);
2548
+ }
2549
+ return { ...init, headers };
2550
+ }
2551
+ function fetchInputForAttempt(input) {
2552
+ return input instanceof Request ? input.clone() : input;
2553
+ }
2554
+ function parseWwwAuthenticate(header) {
2555
+ if (!header) {
2556
+ return {};
2557
+ }
2558
+ const bearerIndex = header.toLowerCase().indexOf("bearer");
2559
+ if (bearerIndex < 0) {
2560
+ return {};
2561
+ }
2562
+ const paramsText = header.slice(bearerIndex + "bearer".length);
2563
+ const params = {};
2564
+ const re = /([a-zA-Z_][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|[^,\s]+)/g;
2565
+ let match;
2566
+ while ((match = re.exec(paramsText)) !== null) {
2567
+ const raw = match[2];
2568
+ params[match[1].toLowerCase()] = raw.startsWith('"') ? raw.slice(1, -1).replace(/\\"/g, '"') : raw;
2569
+ }
2570
+ return {
2571
+ ...params.error ? { error: params.error } : {},
2572
+ ...params.scope ? { scope: params.scope.split(/\s+/).filter(Boolean) } : {},
2573
+ ...params.resource ? { resource: params.resource } : {}
2574
+ };
2575
+ }
2576
+ var MCP_AUTH_NEEDED_ERROR_CODE = -32001;
2577
+ var MCP_AUTH_NEEDED_MESSAGE = "Authentication required - a connection link was posted to the session.";
2578
+ function mcpToolAuthNeededResponse(id) {
2579
+ return new Response(JSON.stringify({
2580
+ jsonrpc: "2.0",
2581
+ id: id ?? null,
2582
+ error: {
2583
+ code: MCP_AUTH_NEEDED_ERROR_CODE,
2584
+ message: MCP_AUTH_NEEDED_MESSAGE
2585
+ }
2586
+ }), {
2587
+ status: 200,
2588
+ headers: { "content-type": "application/json" }
2589
+ });
2590
+ }
2591
+ function isAuthNeededMcpError(error) {
2592
+ if (!(error instanceof Error)) {
2593
+ return false;
2594
+ }
2595
+ const code = error.code;
2596
+ return code === MCP_AUTH_NEEDED_ERROR_CODE || error.message.includes(MCP_AUTH_NEEDED_MESSAGE);
2597
+ }
2119
2598
  async function mcpServerRequestInit(settings, config, options) {
2120
2599
  if (isCodexAppsMcpServer(config)) {
2121
2600
  return await codexAppsMcpRequestInit(settings);
@@ -2259,7 +2738,7 @@ function normalizeUrl(raw) {
2259
2738
  }
2260
2739
  }
2261
2740
  function prefixedMcpToolName(registryId, toolName) {
2262
- return `${registryId}__${toolName}`;
2741
+ return sharedPrefixedMcpToolName(registryId, toolName);
2263
2742
  }
2264
2743
  var PrefixedMcpServer = class {
2265
2744
  constructor(inner, registryId, allowedTools) {
@@ -2289,7 +2768,14 @@ var PrefixedMcpServer = class {
2289
2768
  if (!this.isAllowed(unprefixed)) {
2290
2769
  throw new Error(`MCP tool ${unprefixed} is not allowed for server ${this.name}`);
2291
2770
  }
2292
- return await this.inner.callTool(unprefixed, args, meta);
2771
+ try {
2772
+ return await this.inner.callTool(unprefixed, args, meta);
2773
+ } catch (error) {
2774
+ if (isAuthNeededMcpError(error)) {
2775
+ return { isError: true, content: [{ type: "text", text: MCP_AUTH_NEEDED_MESSAGE }] };
2776
+ }
2777
+ throw error;
2778
+ }
2293
2779
  }
2294
2780
  invalidateToolsCache() {
2295
2781
  return this.inner.invalidateToolsCache();
@@ -2500,15 +2986,18 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
2500
2986
  ...runAs2 ? { runAs: runAs2 } : {}
2501
2987
  }) : ownedClient;
2502
2988
  const ownedGitTokenSeed = gitTokenSeedForAgent(agent);
2989
+ const ownedToolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
2503
2990
  const ownedHooks = [
2504
2991
  ...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
2992
+ ...sandboxToolspaceTokenHooksForAgent(agent),
2505
2993
  ...sandboxRepositoryCloneHooksForAgent(agent)
2506
2994
  ];
2507
2995
  const ownedHookContext = {
2508
2996
  environment,
2509
2997
  ...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
2510
2998
  ...runAs2 ? { runAs: runAs2 } : {},
2511
- ...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {}
2999
+ ...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {},
3000
+ ...ownedToolspaceTokenSeed ? { toolspaceTokenSeed: ownedToolspaceTokenSeed } : {}
2512
3001
  };
2513
3002
  if (agentActiveSandboxBackend.get(agent) !== "selfhosted") {
2514
3003
  await runBeforeAgentStartHooks(setupSession, ownedHooks, ownedHookContext);
@@ -2552,14 +3041,17 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
2552
3041
  ...runAs ? { runAs } : {}
2553
3042
  }) : refreshedClient;
2554
3043
  const gitTokenSeed = gitTokenSeedForAgent(agent);
3044
+ const toolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
2555
3045
  const client = resourceClient ? withSandboxLifecycleHooks(resourceClient, [
2556
3046
  ...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
3047
+ ...sandboxToolspaceTokenHooksForAgent(agent),
2557
3048
  ...sandboxRepositoryCloneHooksForAgent(agent)
2558
3049
  ], {
2559
3050
  environment,
2560
3051
  ...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
2561
3052
  ...runAs ? { runAs } : {},
2562
- ...gitTokenSeed ? { gitTokenSeed } : {}
3053
+ ...gitTokenSeed ? { gitTokenSeed } : {},
3054
+ ...toolspaceTokenSeed ? { toolspaceTokenSeed } : {}
2563
3055
  }) : void 0;
2564
3056
  const sandboxSessionState = prepared.sandboxSessionState ?? (prepared.serializedRunStateForSandbox && client ? await restoredSandboxSessionState(await RunState.fromString(agent, prepared.serializedRunStateForSandbox), client) : void 0);
2565
3057
  const callModelInputFilter = composeCallModelInputFilters(
@@ -2582,7 +3074,6 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
2582
3074
  // every mid-turn follow-up.
2583
3075
  callModelInputFilter
2584
3076
  };
2585
- void settings.disableOpenaiTracing;
2586
3077
  if (client) {
2587
3078
  runOptions.sandbox = {
2588
3079
  client,
@@ -3234,6 +3725,16 @@ function sandboxRepositoryCloneHooksForAgent(agent) {
3234
3725
  function gitTokenSeedForAgent(agent) {
3235
3726
  return agentGitTokenSeed.get(agent);
3236
3727
  }
3728
+ function toolspaceTokenSeedForAgent(agent) {
3729
+ return agentToolspaceTokenSeed.get(agent);
3730
+ }
3731
+ function sandboxToolspaceTokenHooksForAgent(agent) {
3732
+ return toolspaceTokenSeedForAgent(agent) ? [{
3733
+ id: "toolspace-token",
3734
+ phase: "beforeAgentStart",
3735
+ run: runToolspaceTokenSeedHook
3736
+ }] : [];
3737
+ }
3237
3738
  function sandboxRepositoryCloneHooks(settings, resources, activeSandboxBackend = settings.sandboxBackend) {
3238
3739
  const repositories = resources.filter((resource) => resource.kind === "repository" && repositoryUsesSandboxClone(settings, resource, activeSandboxBackend));
3239
3740
  if (repositories.length === 0) {
@@ -3404,6 +3905,49 @@ function repositoryCloneCommand(resources) {
3404
3905
  }
3405
3906
  return commands.join("\n");
3406
3907
  }
3908
+ function toolspaceTokenSeedCommand() {
3909
+ return [
3910
+ "set -eu",
3911
+ 'export HOME="${HOME:-/workspace}"',
3912
+ 'if [ -n "${OPENGENI_TOOLSPACE_TOKEN_SEED:-}" ]; then',
3913
+ ' seed_umask="$(umask)"',
3914
+ " umask 077",
3915
+ ' token_file="${OPENGENI_TOOLSPACE_TOKEN_FILE:-$HOME/.opengeni/toolspace-token}"',
3916
+ ' mkdir -p "$(dirname "$token_file")"',
3917
+ ` printf '%s' "$OPENGENI_TOOLSPACE_TOKEN_SEED" > "$token_file.tmp.$$"`,
3918
+ ' mv -f "$token_file.tmp.$$" "$token_file"',
3919
+ ' umask "$seed_umask"',
3920
+ "fi"
3921
+ ].join("\n");
3922
+ }
3923
+ async function runToolspaceTokenSeedHook(session, context) {
3924
+ if (!context.toolspaceTokenSeed) {
3925
+ return;
3926
+ }
3927
+ const command = `export OPENGENI_TOOLSPACE_TOKEN_SEED=${shellQuote(context.toolspaceTokenSeed)}
3928
+ ${toolspaceTokenSeedCommand()}`;
3929
+ if (session.exec) {
3930
+ const result = await session.exec({
3931
+ cmd: command,
3932
+ workdir: "/workspace",
3933
+ ...context.runAs ? { runAs: context.runAs } : {},
3934
+ yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
3935
+ maxOutputTokens: 4e3
3936
+ });
3937
+ assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
3938
+ } else if (session.execCommand) {
3939
+ const result = await session.execCommand({
3940
+ cmd: command,
3941
+ workdir: "/workspace",
3942
+ ...context.runAs ? { runAs: context.runAs } : {},
3943
+ yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
3944
+ maxOutputTokens: 4e3
3945
+ });
3946
+ assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
3947
+ } else {
3948
+ throw new Error("Sandbox session does not support command execution");
3949
+ }
3950
+ }
3407
3951
  async function runRepositoryCloneHook(session, resources, context = { environment: {} }) {
3408
3952
  const payload = { name: "repository-clone", repositoryCount: resources.length };
3409
3953
  await context.onRuntimeEvent?.({ type: "sandbox.operation.started", payload });
@@ -3752,7 +4296,6 @@ function approvalIdentifier(item) {
3752
4296
  export {
3753
4297
  ActiveBackendUnresolvableError,
3754
4298
  CAPABILITY_DESCRIPTORS,
3755
- CLIENT_COMPACTION_TRIGGER_FRACTION,
3756
4299
  COMPACTION_PROMPT,
3757
4300
  COMPACTION_SUMMARY_MARKER,
3758
4301
  COMPACT_USER_MESSAGE_MAX_TOKENS,
@@ -3766,12 +4309,15 @@ export {
3766
4309
  ComputerReadOnlyError,
3767
4310
  ComputerUnavailableError,
3768
4311
  ComputerUseCapability,
4312
+ DEFAULT_COMPACTION_THRESHOLD_RATIO,
3769
4313
  DEFAULT_DESKTOP_GEOMETRY,
3770
4314
  DESKTOP_STREAM_PORT,
3771
4315
  DISPLAY_STACK_TIMEOUT_MS,
3772
4316
  DisplayStackError,
3773
4317
  DisplayStackUnsupportedError,
3774
4318
  GENESIS_TITLE_DIRECTIVE,
4319
+ MAX_COMPACTION_THRESHOLD_RATIO,
4320
+ MIN_COMPACTION_THRESHOLD_RATIO,
3775
4321
  MaxTurnsExceededError2 as MaxTurnsExceededError,
3776
4322
  MockAgentResponder,
3777
4323
  MultiProviderModelProvider,
@@ -3819,6 +4365,7 @@ export {
3819
4365
  buildAgentCapabilities,
3820
4366
  buildCompactionPromptInput,
3821
4367
  buildCompactionReplacementHistory,
4368
+ buildDeterministicFallbackCompactionHistory,
3822
4369
  buildDisplayStackScript,
3823
4370
  buildManifest,
3824
4371
  buildModelInstance,
@@ -3830,11 +4377,13 @@ export {
3830
4377
  buildSummaryItem,
3831
4378
  buildTerminalServerScript,
3832
4379
  callModelInputFilterForSettings,
4380
+ clampCompactionThresholdRatio,
3833
4381
  clientCompactionThresholdTokens,
3834
4382
  collectSandboxEnvironment,
3835
4383
  composeAgentInstructions,
3836
4384
  computerUse,
3837
4385
  configureOpenAI,
4386
+ configureRuntimeMetricsHooks,
3838
4387
  contentTypeForCodec,
3839
4388
  contextRobustnessFilterForSettings,
3840
4389
  coreInstructions,
@@ -3870,6 +4419,7 @@ export {
3870
4419
  makeActiveBackendResolver,
3871
4420
  materializeSandboxFileDownloads,
3872
4421
  maxTurnsExceededRunState,
4422
+ mcpToolErrorOutput,
3873
4423
  mintStreamToken,
3874
4424
  modalSandboxAttributionEnvironment,
3875
4425
  modalSandboxAttributionTags,
@@ -3902,6 +4452,7 @@ export {
3902
4452
  runAzureCliLoginHook,
3903
4453
  runBeforeAgentStartHooks,
3904
4454
  runRepositoryCloneHook,
4455
+ runToolspaceTokenSeedHook,
3905
4456
  sandboxCommandExitCode,
3906
4457
  sandboxCommandOutput,
3907
4458
  sandboxCommandStillRunning,
@@ -3930,6 +4481,7 @@ export {
3930
4481
  terminateModalSandboxById,
3931
4482
  timeoutAgentError,
3932
4483
  timeoutControlResponse,
4484
+ toolspaceTokenSeedCommand,
3933
4485
  verifyStreamToken,
3934
4486
  withManifestRefreshOnResume,
3935
4487
  withSandboxFileDownloads,