@opengeni/runtime 0.3.1 → 0.5.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/LICENSE +190 -0
- package/dist/{chunk-HGQ252FL.js → chunk-Q36E4MDM.js} +17 -2
- package/dist/chunk-Q36E4MDM.js.map +1 -0
- package/dist/{index-CSGkld-v.d.ts → index-BrdnxaAW.d.ts} +5 -3
- package/dist/index.d.ts +106 -9
- package/dist/index.js +483 -36
- package/dist/index.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -1
- package/dist/sandbox/index.js +1 -1
- package/package.json +6 -8
- package/src/context-compaction.ts +164 -16
- package/src/history-sanitizer.ts +2 -1
- package/src/index.ts +574 -19
- package/src/sandbox/selfhosted/session.ts +32 -4
- package/dist/chunk-HGQ252FL.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -95,11 +95,11 @@ import {
|
|
|
95
95
|
timeoutAgentError,
|
|
96
96
|
timeoutControlResponse,
|
|
97
97
|
verifyStreamToken
|
|
98
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-Q36E4MDM.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,
|
|
@@ -150,7 +150,7 @@ import { fileURLToPath } from "url";
|
|
|
150
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
151
|
|
|
152
152
|
// src/history-sanitizer.ts
|
|
153
|
-
var
|
|
153
|
+
var TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE = {
|
|
154
154
|
function_call: "function_call_result",
|
|
155
155
|
computer_call: "computer_call_result",
|
|
156
156
|
shell_call: "shell_call_output",
|
|
@@ -163,6 +163,7 @@ var RESULT_TYPE_BY_CALL_TYPE = {
|
|
|
163
163
|
// additionally ride providerData (see callIdOf).
|
|
164
164
|
tool_search_call: "tool_search_output"
|
|
165
165
|
};
|
|
166
|
+
var RESULT_TYPE_BY_CALL_TYPE = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
|
|
166
167
|
var RESULT_TYPES = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE));
|
|
167
168
|
function itemType(item) {
|
|
168
169
|
if (!item || typeof item !== "object") {
|
|
@@ -795,7 +796,10 @@ function installCodexToolSearch(agent, connectorNamespaces = NO_NAMESPACES) {
|
|
|
795
796
|
var COMPACTION_SUMMARY_MARKER = "opengeni_context_summary";
|
|
796
797
|
var SUMMARY_BUFFER_TOKENS = 2e4;
|
|
797
798
|
var COMPACT_USER_MESSAGE_MAX_TOKENS = 2e4;
|
|
798
|
-
var
|
|
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;
|
|
799
803
|
var COMPACTION_PROMPT = [
|
|
800
804
|
"You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.",
|
|
801
805
|
"",
|
|
@@ -809,12 +813,7 @@ var COMPACTION_PROMPT = [
|
|
|
809
813
|
].join("\n");
|
|
810
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:";
|
|
811
815
|
var USER_MESSAGE_TRUNCATION_MARKER = "\n[... middle truncated for context compaction ...]\n";
|
|
812
|
-
var RESULT_TYPE_BY_CALL_TYPE2 =
|
|
813
|
-
function_call: "function_call_result",
|
|
814
|
-
computer_call: "computer_call_result",
|
|
815
|
-
shell_call: "shell_call_output",
|
|
816
|
-
apply_patch_call: "apply_patch_call_output"
|
|
817
|
-
};
|
|
816
|
+
var RESULT_TYPE_BY_CALL_TYPE2 = TOOL_CALL_RESULT_TYPE_BY_CALL_TYPE;
|
|
818
817
|
var RESULT_TYPES2 = new Set(Object.values(RESULT_TYPE_BY_CALL_TYPE2));
|
|
819
818
|
function itemType2(item) {
|
|
820
819
|
if (!item || typeof item !== "object") {
|
|
@@ -852,12 +851,12 @@ function estimateTokens(items) {
|
|
|
852
851
|
}
|
|
853
852
|
return total;
|
|
854
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
|
+
}
|
|
855
858
|
function clientCompactionThresholdTokens(input) {
|
|
856
|
-
|
|
857
|
-
0,
|
|
858
|
-
input.contextWindowTokens - input.contextReservedOutputTokens - SUMMARY_BUFFER_TOKENS
|
|
859
|
-
);
|
|
860
|
-
return Math.floor(available * CLIENT_COMPACTION_TRIGGER_FRACTION);
|
|
859
|
+
return Math.floor(Math.max(0, input.contextWindowTokens) * clampCompactionThresholdRatio(input.contextCompactionThresholdRatio));
|
|
861
860
|
}
|
|
862
861
|
function decideClientCompaction(input) {
|
|
863
862
|
const thresholdTokens = clientCompactionThresholdTokens(input);
|
|
@@ -959,6 +958,58 @@ function buildCompactionReplacementHistory(items, summaryBody) {
|
|
|
959
958
|
history.push(buildSummaryItem(summaryBody));
|
|
960
959
|
return history;
|
|
961
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
|
+
}
|
|
962
1013
|
function buildSummaryItem(summaryBody) {
|
|
963
1014
|
const trimmed = summaryBody.trim();
|
|
964
1015
|
return {
|
|
@@ -970,15 +1021,38 @@ ${trimmed}`,
|
|
|
970
1021
|
};
|
|
971
1022
|
}
|
|
972
1023
|
function compactUserMessage(item) {
|
|
1024
|
+
return compactMessageToTokenBudget(item, COMPACT_USER_MESSAGE_MAX_TOKENS);
|
|
1025
|
+
}
|
|
1026
|
+
function compactMessageToTokenBudget(item, maxTokens) {
|
|
973
1027
|
const text = messageText(item);
|
|
974
1028
|
const next = { ...item };
|
|
975
|
-
if (estimatedTextTokens(text) >
|
|
976
|
-
next.content = truncateMiddleByEstimatedTokens(text,
|
|
1029
|
+
if (estimatedTextTokens(text) > maxTokens) {
|
|
1030
|
+
next.content = truncateMiddleByEstimatedTokens(text, maxTokens);
|
|
977
1031
|
return next;
|
|
978
1032
|
}
|
|
979
1033
|
next.content = contentWithoutImages(item);
|
|
980
1034
|
return next;
|
|
981
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
|
+
}
|
|
982
1056
|
function estimatedTextTokens(text) {
|
|
983
1057
|
return Math.ceil(text.length / 4);
|
|
984
1058
|
}
|
|
@@ -1029,8 +1103,29 @@ function messageText(item) {
|
|
|
1029
1103
|
}
|
|
1030
1104
|
return "";
|
|
1031
1105
|
}
|
|
1032
|
-
function
|
|
1033
|
-
|
|
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);
|
|
1034
1129
|
}
|
|
1035
1130
|
function renderItem(item) {
|
|
1036
1131
|
const type = itemType2(item) ?? "unknown";
|
|
@@ -1076,6 +1171,24 @@ function truncateForTranscript(text, max) {
|
|
|
1076
1171
|
}
|
|
1077
1172
|
return `${text.slice(0, max)}... (${text.length - max} more chars)`;
|
|
1078
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
|
+
}
|
|
1079
1192
|
|
|
1080
1193
|
// src/sandbox-computer.ts
|
|
1081
1194
|
import { computerTool, tool } from "@openai/agents";
|
|
@@ -1939,12 +2052,16 @@ async function summarizeForCompaction(settings, input, options = {}) {
|
|
|
1939
2052
|
const api = options.api ?? "responses";
|
|
1940
2053
|
const model = options.model ?? settings.openaiModel;
|
|
1941
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
|
+
);
|
|
1942
2059
|
try {
|
|
1943
2060
|
if (api === "chat") {
|
|
1944
2061
|
const completion = await client.chat.completions.create({
|
|
1945
2062
|
model,
|
|
1946
2063
|
max_tokens: maxTokens,
|
|
1947
|
-
messages: [{ role: "user", content:
|
|
2064
|
+
messages: [{ role: "user", content: transcript }]
|
|
1948
2065
|
});
|
|
1949
2066
|
const text2 = completion.choices?.[0]?.message?.content;
|
|
1950
2067
|
const trimmed2 = typeof text2 === "string" ? text2.trim() : "";
|
|
@@ -1957,13 +2074,13 @@ async function summarizeForCompaction(settings, input, options = {}) {
|
|
|
1957
2074
|
// built-in path (api "responses"), so gate it on the built-in provider.
|
|
1958
2075
|
...settings.openaiProvider === "azure" ? {} : { store: false },
|
|
1959
2076
|
max_output_tokens: maxTokens,
|
|
1960
|
-
input
|
|
2077
|
+
input: transcript
|
|
1961
2078
|
});
|
|
1962
2079
|
const text = extractResponseOutputText(response);
|
|
1963
2080
|
const trimmed = text.trim();
|
|
1964
2081
|
return trimmed.length > 0 ? trimmed : null;
|
|
1965
2082
|
} catch (error) {
|
|
1966
|
-
console.error("context compaction summarize failed
|
|
2083
|
+
console.error("context compaction summarize failed", error);
|
|
1967
2084
|
return null;
|
|
1968
2085
|
}
|
|
1969
2086
|
}
|
|
@@ -2033,13 +2150,22 @@ function appendSessionInstructions(composed, sessionInstructions) {
|
|
|
2033
2150
|
const trimmed = sessionInstructions?.trim();
|
|
2034
2151
|
return trimmed ? `${composed} ${trimmed}` : composed;
|
|
2035
2152
|
}
|
|
2153
|
+
function appendToolspaceInstructions(composed, toolspaceAvailable) {
|
|
2154
|
+
return toolspaceAvailable ? `${composed} ${TOOLSPACE_PROGRAMMATIC_DIRECTIVE}` : composed;
|
|
2155
|
+
}
|
|
2036
2156
|
function appendGenesisTitleDirective(instructions, genesisTitleHint) {
|
|
2037
2157
|
return genesisTitleHint ? `${instructions} ${GENESIS_TITLE_DIRECTIVE}` : instructions;
|
|
2038
2158
|
}
|
|
2039
2159
|
var agentFileDownloads = /* @__PURE__ */ new WeakMap();
|
|
2040
2160
|
var agentRepositoryCloneHooks = /* @__PURE__ */ new WeakMap();
|
|
2041
2161
|
var agentGitTokenSeed = /* @__PURE__ */ new WeakMap();
|
|
2162
|
+
var agentToolspaceTokenSeed = /* @__PURE__ */ new WeakMap();
|
|
2042
2163
|
var agentActiveSandboxBackend = /* @__PURE__ */ new WeakMap();
|
|
2164
|
+
function mcpToolErrorOutput(error) {
|
|
2165
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
2166
|
+
return { isError: true, content: [{ type: "text", text: `An error occurred while running the tool. Please try again. Error: ${details}` }] };
|
|
2167
|
+
}
|
|
2168
|
+
var mcpToolErrorFunction = ({ error }) => mcpToolErrorOutput(error);
|
|
2043
2169
|
function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
2044
2170
|
const compactionMode = options.compactionMode ?? resolveContextCompactionMode(settings);
|
|
2045
2171
|
const hostedWebSearch = options.hostedWebSearch ?? settings.webSearchEnabled;
|
|
@@ -2060,14 +2186,21 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
2060
2186
|
// Persona composition order (all one system-level instructions string):
|
|
2061
2187
|
// 1. workspace instructionsTemplate (or deployment default) with the
|
|
2062
2188
|
// non-bypassable CORE substituted at {{core}} — composeAgentInstructions,
|
|
2063
|
-
// 2. + the
|
|
2064
|
-
//
|
|
2065
|
-
//
|
|
2066
|
-
//
|
|
2067
|
-
// the
|
|
2189
|
+
// 2. + the generic programmatic-tool-calling (toolspace) directive, ONLY
|
|
2190
|
+
// when a toolspace token was minted for this turn (feature enabled + a
|
|
2191
|
+
// per-turn seed — the mint gate, which includes selfhosted turns since
|
|
2192
|
+
// they now receive the token too) — appendToolspaceInstructions,
|
|
2193
|
+
// 3. + the per-session persona instructions (session-specific, so it
|
|
2194
|
+
// refines both the workspace persona and the substrate note),
|
|
2195
|
+
// 4. + the one-shot genesis title directive (genesis turn only).
|
|
2196
|
+
// With no toolspace token, no session instructions, and no genesis hint this
|
|
2197
|
+
// is byte-identical to the historical composed instructions.
|
|
2068
2198
|
instructions: appendGenesisTitleDirective(
|
|
2069
2199
|
appendSessionInstructions(
|
|
2070
|
-
|
|
2200
|
+
appendToolspaceInstructions(
|
|
2201
|
+
composeAgentInstructions(options.instructionsTemplate ?? settings.agentInstructionsTemplate, options.workspaceEnvironment),
|
|
2202
|
+
settings.toolspaceEnabled && Boolean(options.toolspaceTokenSeed)
|
|
2203
|
+
),
|
|
2071
2204
|
options.sessionInstructions
|
|
2072
2205
|
),
|
|
2073
2206
|
options.genesisTitleHint
|
|
@@ -2098,11 +2231,19 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
2098
2231
|
// `new SandboxAgent({ ...baseConfig, ... })` path via the shared baseConfig
|
|
2099
2232
|
// spread; the SDK concatenates these with MCP and sandbox capability tools.
|
|
2100
2233
|
...hostedTools.length ? { tools: hostedTools } : {},
|
|
2101
|
-
...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {}
|
|
2234
|
+
...options.mcpServers?.length ? { mcpServers: options.mcpServers } : {},
|
|
2235
|
+
// Surface FAILED MCP tool calls as `{ isError: true }` tool output (see
|
|
2236
|
+
// mcpToolErrorFunction / mcpToolErrorOutput) instead of the SDK's default
|
|
2237
|
+
// flat error string, so a thrown MCP failure (protocol error, auth, timeout,
|
|
2238
|
+
// tool-not-found) settles the timeline tool to "failed" rather than rendering
|
|
2239
|
+
// as success. Applies to every MCP server on this agent (session, first-party,
|
|
2240
|
+
// capability, codex_apps) since none set a server-level errorFunction.
|
|
2241
|
+
mcpConfig: { errorFunction: mcpToolErrorFunction }
|
|
2102
2242
|
};
|
|
2103
2243
|
if (settings.sandboxBackend === "none") {
|
|
2104
2244
|
const agent2 = new Agent(baseConfig);
|
|
2105
2245
|
maybeInstallCodexToolSearch(agent2, settings, options);
|
|
2246
|
+
applyMcpApprovalPolicy(agent2, settings);
|
|
2106
2247
|
return agent2;
|
|
2107
2248
|
}
|
|
2108
2249
|
const runAs = sandboxRunAs(settings);
|
|
@@ -2125,7 +2266,11 @@ function buildOpenGeniAgent(settings, resources, options = {}) {
|
|
|
2125
2266
|
if (options.gitTokenSeed) {
|
|
2126
2267
|
agentGitTokenSeed.set(agent, options.gitTokenSeed);
|
|
2127
2268
|
}
|
|
2269
|
+
if (options.toolspaceTokenSeed) {
|
|
2270
|
+
agentToolspaceTokenSeed.set(agent, options.toolspaceTokenSeed);
|
|
2271
|
+
}
|
|
2128
2272
|
maybeInstallCodexToolSearch(agent, settings, options);
|
|
2273
|
+
applyMcpApprovalPolicy(agent, settings);
|
|
2129
2274
|
return agent;
|
|
2130
2275
|
}
|
|
2131
2276
|
function maybeInstallCodexToolSearch(agent, settings, options) {
|
|
@@ -2136,6 +2281,41 @@ function maybeInstallCodexToolSearch(agent, settings, options) {
|
|
|
2136
2281
|
);
|
|
2137
2282
|
}
|
|
2138
2283
|
}
|
|
2284
|
+
function mcpToolRequiresApproval(policy, unprefixedName) {
|
|
2285
|
+
return policy === true || Array.isArray(policy) && policy.includes(unprefixedName);
|
|
2286
|
+
}
|
|
2287
|
+
function installMcpApprovalPolicy(agent, policies) {
|
|
2288
|
+
const listMcpTools = agent.getMcpTools.bind(agent);
|
|
2289
|
+
agent.getMcpTools = async (runContext) => {
|
|
2290
|
+
const tools = await listMcpTools(runContext);
|
|
2291
|
+
return tools.map((tool2) => {
|
|
2292
|
+
if (tool2.type !== "function") {
|
|
2293
|
+
return tool2;
|
|
2294
|
+
}
|
|
2295
|
+
const policy = policies.find((entry) => tool2.name.startsWith(entry.prefix));
|
|
2296
|
+
if (!policy) {
|
|
2297
|
+
return tool2;
|
|
2298
|
+
}
|
|
2299
|
+
const unprefixed = tool2.name.slice(policy.prefix.length);
|
|
2300
|
+
return mcpToolRequiresApproval(policy.requireApproval, unprefixed) ? { ...tool2, needsApproval: async () => true } : tool2;
|
|
2301
|
+
});
|
|
2302
|
+
};
|
|
2303
|
+
const originalClone = agent.clone?.bind(agent);
|
|
2304
|
+
if (originalClone) {
|
|
2305
|
+
agent.clone = (config) => {
|
|
2306
|
+
const cloned = originalClone(config);
|
|
2307
|
+
installMcpApprovalPolicy(cloned, policies);
|
|
2308
|
+
return cloned;
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
function applyMcpApprovalPolicy(agent, settings) {
|
|
2313
|
+
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);
|
|
2314
|
+
if (policies.length === 0) {
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
installMcpApprovalPolicy(agent, policies);
|
|
2318
|
+
}
|
|
2139
2319
|
function neutralizeStructuredToolTransport(capability) {
|
|
2140
2320
|
const forceFunctionTransport = function() {
|
|
2141
2321
|
this._modelInstance = void 0;
|
|
@@ -2185,6 +2365,8 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2185
2365
|
throw new Error(`Unknown MCP server id: ${tool2.id}`);
|
|
2186
2366
|
}
|
|
2187
2367
|
const url = firstPartyMcpServerUrlForRun(settings, config, options.workspaceId) ?? config.url;
|
|
2368
|
+
const baseFetch = isCodexAppsMcpServer(config) ? codexAppsSanitizingFetch(globalThis.fetch, codexConnectorNamespaces) : globalThis.fetch;
|
|
2369
|
+
const fetchImpl = config.connectionRef ? connectionBrokerFetch(baseFetch, config, options) : baseFetch;
|
|
2188
2370
|
const server = new PrefixedMcpServer(new MCPServerStreamableHttp({
|
|
2189
2371
|
url,
|
|
2190
2372
|
name: config.name ?? config.id,
|
|
@@ -2193,7 +2375,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2193
2375
|
// MCP SDK's strict Tool schema rejects (fails the turn during tools/list);
|
|
2194
2376
|
// sanitize the response on the wire before validation. The namespace Set
|
|
2195
2377
|
// also captures each tool's original connector namespace (P4 Part B.1).
|
|
2196
|
-
...
|
|
2378
|
+
...fetchImpl !== globalThis.fetch ? { fetch: fetchImpl } : {},
|
|
2197
2379
|
...await mcpServerRequestInit(settings, config, options),
|
|
2198
2380
|
...config.timeoutMs ? {
|
|
2199
2381
|
timeout: config.timeoutMs,
|
|
@@ -2201,7 +2383,7 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2201
2383
|
} : {}
|
|
2202
2384
|
}), config.id, config.allowedTools);
|
|
2203
2385
|
const optional = tool2.optional === true;
|
|
2204
|
-
return { server, bestEffort: isCodexAppsMcpServer(config) || optional, optional };
|
|
2386
|
+
return { server, bestEffort: isCodexAppsMcpServer(config) || optional || !!config.connectionRef, optional };
|
|
2205
2387
|
}));
|
|
2206
2388
|
const requiredServers = servers.filter((entry) => !entry.bestEffort).map((entry) => entry.server);
|
|
2207
2389
|
const bestEffortServers = servers.filter((entry) => entry.bestEffort).map((entry) => entry.server);
|
|
@@ -2239,6 +2421,190 @@ async function prepareAgentTools(settings, tools, options = {}) {
|
|
|
2239
2421
|
codexConnectorNamespaces
|
|
2240
2422
|
};
|
|
2241
2423
|
}
|
|
2424
|
+
function connectionBrokerFetch(baseFetch, config, options) {
|
|
2425
|
+
const connectionRef = config.connectionRef;
|
|
2426
|
+
if (!connectionRef) {
|
|
2427
|
+
return baseFetch;
|
|
2428
|
+
}
|
|
2429
|
+
return async (input, init) => {
|
|
2430
|
+
const request = await mcpRequestInfo(input, init);
|
|
2431
|
+
const first = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, false);
|
|
2432
|
+
if (first.status === "auth_needed") {
|
|
2433
|
+
return await authNeededFetchResponse(options, config.id, request, first, connectionRef);
|
|
2434
|
+
}
|
|
2435
|
+
const response = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, first.headers));
|
|
2436
|
+
if (response.status === 401) {
|
|
2437
|
+
const refreshed = await resolveConnectionForRequest(options, config.id, connectionRef, request.toolName, true);
|
|
2438
|
+
if (refreshed.status === "auth_needed") {
|
|
2439
|
+
return await authNeededFetchResponse(options, config.id, request, refreshed, connectionRef);
|
|
2440
|
+
}
|
|
2441
|
+
const retry = await baseFetch(fetchInputForAttempt(input), withConnectionHeaders(input, init, refreshed.headers));
|
|
2442
|
+
if (retry.status === 403) {
|
|
2443
|
+
const auth = insufficientScopeAuth(retry.headers, connectionRef, refreshed.connectionId);
|
|
2444
|
+
return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : retry;
|
|
2445
|
+
}
|
|
2446
|
+
if (retry.status === 401) {
|
|
2447
|
+
return await authNeededFetchResponse(options, config.id, request, {
|
|
2448
|
+
status: "auth_needed",
|
|
2449
|
+
reason: "expired",
|
|
2450
|
+
providerDomain: connectionRef.providerDomain,
|
|
2451
|
+
connectionId: refreshed.connectionId,
|
|
2452
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2453
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2454
|
+
}, connectionRef);
|
|
2455
|
+
}
|
|
2456
|
+
return retry;
|
|
2457
|
+
}
|
|
2458
|
+
if (response.status === 403) {
|
|
2459
|
+
const auth = insufficientScopeAuth(response.headers, connectionRef, first.connectionId);
|
|
2460
|
+
return auth ? await authNeededFetchResponse(options, config.id, request, auth, connectionRef) : response;
|
|
2461
|
+
}
|
|
2462
|
+
return response;
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
async function resolveConnectionForRequest(options, serverId, connectionRef, toolName, forceRefresh) {
|
|
2466
|
+
if (!options.workspaceId || !options.resolveCredential) {
|
|
2467
|
+
return {
|
|
2468
|
+
status: "auth_needed",
|
|
2469
|
+
reason: "missing_connection",
|
|
2470
|
+
providerDomain: connectionRef.providerDomain,
|
|
2471
|
+
...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
|
|
2472
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2473
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2476
|
+
const request = {
|
|
2477
|
+
workspaceId: options.workspaceId,
|
|
2478
|
+
serverId,
|
|
2479
|
+
connectionRef,
|
|
2480
|
+
forceRefresh,
|
|
2481
|
+
...toolName ? { toolName } : {},
|
|
2482
|
+
...options.subjectId ? { subjectId: options.subjectId } : {}
|
|
2483
|
+
};
|
|
2484
|
+
try {
|
|
2485
|
+
return await options.resolveCredential(request);
|
|
2486
|
+
} catch {
|
|
2487
|
+
return {
|
|
2488
|
+
status: "auth_needed",
|
|
2489
|
+
reason: "refresh_failed",
|
|
2490
|
+
providerDomain: connectionRef.providerDomain,
|
|
2491
|
+
...connectionRef.connectionId ? { connectionId: connectionRef.connectionId } : {},
|
|
2492
|
+
...connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2493
|
+
...connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
function insufficientScopeAuth(headers, connectionRef, connectionId) {
|
|
2498
|
+
const challenge = parseWwwAuthenticate(headers.get("www-authenticate"));
|
|
2499
|
+
if (challenge.error !== "insufficient_scope") {
|
|
2500
|
+
return null;
|
|
2501
|
+
}
|
|
2502
|
+
return {
|
|
2503
|
+
status: "auth_needed",
|
|
2504
|
+
reason: "insufficient_scope",
|
|
2505
|
+
providerDomain: connectionRef.providerDomain,
|
|
2506
|
+
connectionId,
|
|
2507
|
+
...challenge.scope?.length ? { scopes: challenge.scope } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2508
|
+
...challenge.resource ? { resource: challenge.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {}
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
async function authNeededFetchResponse(options, serverId, request, auth, connectionRef) {
|
|
2512
|
+
const connectionId = auth.connectionId ?? connectionRef.connectionId;
|
|
2513
|
+
await publishAuthNeeded(options, {
|
|
2514
|
+
serverId,
|
|
2515
|
+
toolName: request.toolName ?? null,
|
|
2516
|
+
providerDomain: auth.providerDomain,
|
|
2517
|
+
reason: auth.reason,
|
|
2518
|
+
...connectionId ? { connectionId } : {},
|
|
2519
|
+
...auth.scopes ? { scopes: auth.scopes } : connectionRef.scopes ? { scopes: connectionRef.scopes } : {},
|
|
2520
|
+
...auth.resource ? { resource: auth.resource } : connectionRef.resource ? { resource: connectionRef.resource } : {},
|
|
2521
|
+
...auth.authorizationUrl ? { authorizationUrl: auth.authorizationUrl } : {},
|
|
2522
|
+
...options.subjectId ? { subjectId: options.subjectId } : {}
|
|
2523
|
+
});
|
|
2524
|
+
if (request.method === "tools/call") {
|
|
2525
|
+
return mcpToolAuthNeededResponse(request.id);
|
|
2526
|
+
}
|
|
2527
|
+
return new Response("Authentication required for MCP server connection", { status: 401 });
|
|
2528
|
+
}
|
|
2529
|
+
async function publishAuthNeeded(options, payload) {
|
|
2530
|
+
try {
|
|
2531
|
+
await options.onAuthNeeded?.(payload);
|
|
2532
|
+
} catch {
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
async function mcpRequestInfo(input, init) {
|
|
2536
|
+
const body = typeof init?.body === "string" ? init.body : input instanceof Request && (init?.method ?? input.method).toUpperCase() === "POST" ? await input.clone().text().catch(() => "") : "";
|
|
2537
|
+
if (!body) {
|
|
2538
|
+
return {};
|
|
2539
|
+
}
|
|
2540
|
+
try {
|
|
2541
|
+
const parsed = JSON.parse(body);
|
|
2542
|
+
const method = typeof parsed.method === "string" ? parsed.method : void 0;
|
|
2543
|
+
const id = typeof parsed.id === "string" || typeof parsed.id === "number" || parsed.id === null ? parsed.id : void 0;
|
|
2544
|
+
const toolName = method === "tools/call" && typeof parsed.params?.name === "string" ? parsed.params.name : void 0;
|
|
2545
|
+
return {
|
|
2546
|
+
...method ? { method } : {},
|
|
2547
|
+
...id !== void 0 ? { id } : {},
|
|
2548
|
+
...toolName ? { toolName } : {}
|
|
2549
|
+
};
|
|
2550
|
+
} catch {
|
|
2551
|
+
return {};
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
function withConnectionHeaders(input, init, authHeaders) {
|
|
2555
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
2556
|
+
for (const [name, value] of Object.entries(authHeaders)) {
|
|
2557
|
+
headers.set(name, value);
|
|
2558
|
+
}
|
|
2559
|
+
return { ...init, headers };
|
|
2560
|
+
}
|
|
2561
|
+
function fetchInputForAttempt(input) {
|
|
2562
|
+
return input instanceof Request ? input.clone() : input;
|
|
2563
|
+
}
|
|
2564
|
+
function parseWwwAuthenticate(header) {
|
|
2565
|
+
if (!header) {
|
|
2566
|
+
return {};
|
|
2567
|
+
}
|
|
2568
|
+
const bearerIndex = header.toLowerCase().indexOf("bearer");
|
|
2569
|
+
if (bearerIndex < 0) {
|
|
2570
|
+
return {};
|
|
2571
|
+
}
|
|
2572
|
+
const paramsText = header.slice(bearerIndex + "bearer".length);
|
|
2573
|
+
const params = {};
|
|
2574
|
+
const re = /([a-zA-Z_][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|[^,\s]+)/g;
|
|
2575
|
+
let match;
|
|
2576
|
+
while ((match = re.exec(paramsText)) !== null) {
|
|
2577
|
+
const raw = match[2];
|
|
2578
|
+
params[match[1].toLowerCase()] = raw.startsWith('"') ? raw.slice(1, -1).replace(/\\"/g, '"') : raw;
|
|
2579
|
+
}
|
|
2580
|
+
return {
|
|
2581
|
+
...params.error ? { error: params.error } : {},
|
|
2582
|
+
...params.scope ? { scope: params.scope.split(/\s+/).filter(Boolean) } : {},
|
|
2583
|
+
...params.resource ? { resource: params.resource } : {}
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
var MCP_AUTH_NEEDED_ERROR_CODE = -32001;
|
|
2587
|
+
var MCP_AUTH_NEEDED_MESSAGE = "Authentication required - a connection link was posted to the session.";
|
|
2588
|
+
function mcpToolAuthNeededResponse(id) {
|
|
2589
|
+
return new Response(JSON.stringify({
|
|
2590
|
+
jsonrpc: "2.0",
|
|
2591
|
+
id: id ?? null,
|
|
2592
|
+
error: {
|
|
2593
|
+
code: MCP_AUTH_NEEDED_ERROR_CODE,
|
|
2594
|
+
message: MCP_AUTH_NEEDED_MESSAGE
|
|
2595
|
+
}
|
|
2596
|
+
}), {
|
|
2597
|
+
status: 200,
|
|
2598
|
+
headers: { "content-type": "application/json" }
|
|
2599
|
+
});
|
|
2600
|
+
}
|
|
2601
|
+
function isAuthNeededMcpError(error) {
|
|
2602
|
+
if (!(error instanceof Error)) {
|
|
2603
|
+
return false;
|
|
2604
|
+
}
|
|
2605
|
+
const code = error.code;
|
|
2606
|
+
return code === MCP_AUTH_NEEDED_ERROR_CODE || error.message.includes(MCP_AUTH_NEEDED_MESSAGE);
|
|
2607
|
+
}
|
|
2242
2608
|
async function mcpServerRequestInit(settings, config, options) {
|
|
2243
2609
|
if (isCodexAppsMcpServer(config)) {
|
|
2244
2610
|
return await codexAppsMcpRequestInit(settings);
|
|
@@ -2382,7 +2748,7 @@ function normalizeUrl(raw) {
|
|
|
2382
2748
|
}
|
|
2383
2749
|
}
|
|
2384
2750
|
function prefixedMcpToolName(registryId, toolName) {
|
|
2385
|
-
return
|
|
2751
|
+
return sharedPrefixedMcpToolName(registryId, toolName);
|
|
2386
2752
|
}
|
|
2387
2753
|
var PrefixedMcpServer = class {
|
|
2388
2754
|
constructor(inner, registryId, allowedTools) {
|
|
@@ -2412,7 +2778,14 @@ var PrefixedMcpServer = class {
|
|
|
2412
2778
|
if (!this.isAllowed(unprefixed)) {
|
|
2413
2779
|
throw new Error(`MCP tool ${unprefixed} is not allowed for server ${this.name}`);
|
|
2414
2780
|
}
|
|
2415
|
-
|
|
2781
|
+
try {
|
|
2782
|
+
return await this.inner.callTool(unprefixed, args, meta);
|
|
2783
|
+
} catch (error) {
|
|
2784
|
+
if (isAuthNeededMcpError(error)) {
|
|
2785
|
+
return { isError: true, content: [{ type: "text", text: MCP_AUTH_NEEDED_MESSAGE }] };
|
|
2786
|
+
}
|
|
2787
|
+
throw error;
|
|
2788
|
+
}
|
|
2416
2789
|
}
|
|
2417
2790
|
invalidateToolsCache() {
|
|
2418
2791
|
return this.inner.invalidateToolsCache();
|
|
@@ -2531,6 +2904,7 @@ async function prepareRunInput(agent, input, options = {}) {
|
|
|
2531
2904
|
return { input: state };
|
|
2532
2905
|
}
|
|
2533
2906
|
var GENESIS_TITLE_DIRECTIVE = "This is the first turn of a new session. Before responding to the user, call the opengeni__set_session_title tool with a concise 3-7 word title that summarizes what this session is about, then address the user's request normally.";
|
|
2907
|
+
var TOOLSPACE_PROGRAMMATIC_DIRECTIVE = "Every tool on your MCP surface is also callable programmatically from the sandbox shell, so scripts can invoke tools without a model round trip per call. Run `ogtool list` to see the available tools and their input schemas (from tools/list), then `ogtool call <tool-name> '<json-args>'`; equivalently, POST MCP JSON-RPC to $OPENGENI_TOOLSPACE_URL with the bearer token read from $OPENGENI_TOOLSPACE_TOKEN_FILE. Prefer programmatic calls for loops, polling, and bulk filtering: their results stay in the sandbox and do not consume your context window. Tools that require human approval must still be invoked normally \u2014 called programmatically they return a typed error.";
|
|
2534
2908
|
var stripProviderItemIdsFilter = ({ modelData }) => ({
|
|
2535
2909
|
...modelData,
|
|
2536
2910
|
input: modelData.input.map((item) => {
|
|
@@ -2623,15 +2997,18 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2623
2997
|
...runAs2 ? { runAs: runAs2 } : {}
|
|
2624
2998
|
}) : ownedClient;
|
|
2625
2999
|
const ownedGitTokenSeed = gitTokenSeedForAgent(agent);
|
|
3000
|
+
const ownedToolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
|
|
2626
3001
|
const ownedHooks = [
|
|
2627
3002
|
...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
|
|
3003
|
+
...sandboxToolspaceTokenHooksForAgent(agent),
|
|
2628
3004
|
...sandboxRepositoryCloneHooksForAgent(agent)
|
|
2629
3005
|
];
|
|
2630
3006
|
const ownedHookContext = {
|
|
2631
3007
|
environment,
|
|
2632
3008
|
...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
|
|
2633
3009
|
...runAs2 ? { runAs: runAs2 } : {},
|
|
2634
|
-
...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {}
|
|
3010
|
+
...ownedGitTokenSeed ? { gitTokenSeed: ownedGitTokenSeed } : {},
|
|
3011
|
+
...ownedToolspaceTokenSeed ? { toolspaceTokenSeed: ownedToolspaceTokenSeed } : {}
|
|
2635
3012
|
};
|
|
2636
3013
|
if (agentActiveSandboxBackend.get(agent) !== "selfhosted") {
|
|
2637
3014
|
await runBeforeAgentStartHooks(setupSession, ownedHooks, ownedHookContext);
|
|
@@ -2641,6 +3018,11 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2641
3018
|
...runAs2 ? { runAs: runAs2 } : {}
|
|
2642
3019
|
});
|
|
2643
3020
|
}
|
|
3021
|
+
} else {
|
|
3022
|
+
const toolspaceHooks = sandboxToolspaceTokenHooksForAgent(agent);
|
|
3023
|
+
if (toolspaceHooks.length > 0) {
|
|
3024
|
+
await runBeforeAgentStartHooks(setupSession, toolspaceHooks, ownedHookContext);
|
|
3025
|
+
}
|
|
2644
3026
|
}
|
|
2645
3027
|
const decoratedClient = withSandboxLifecycleHooks(resourceClient2, ownedHooks, ownedHookContext);
|
|
2646
3028
|
const ownedFilter = composeCallModelInputFilters(
|
|
@@ -2675,14 +3057,17 @@ async function runAgentStream(agent, input, settings, overrides = {}) {
|
|
|
2675
3057
|
...runAs ? { runAs } : {}
|
|
2676
3058
|
}) : refreshedClient;
|
|
2677
3059
|
const gitTokenSeed = gitTokenSeedForAgent(agent);
|
|
3060
|
+
const toolspaceTokenSeed = toolspaceTokenSeedForAgent(agent);
|
|
2678
3061
|
const client = resourceClient ? withSandboxLifecycleHooks(resourceClient, [
|
|
2679
3062
|
...sandboxLifecycleHooksForIds(sandboxLifecycleHookIds(settings)),
|
|
3063
|
+
...sandboxToolspaceTokenHooksForAgent(agent),
|
|
2680
3064
|
...sandboxRepositoryCloneHooksForAgent(agent)
|
|
2681
3065
|
], {
|
|
2682
3066
|
environment,
|
|
2683
3067
|
...overrides.onRuntimeEvent ? { onRuntimeEvent: overrides.onRuntimeEvent } : {},
|
|
2684
3068
|
...runAs ? { runAs } : {},
|
|
2685
|
-
...gitTokenSeed ? { gitTokenSeed } : {}
|
|
3069
|
+
...gitTokenSeed ? { gitTokenSeed } : {},
|
|
3070
|
+
...toolspaceTokenSeed ? { toolspaceTokenSeed } : {}
|
|
2686
3071
|
}) : void 0;
|
|
2687
3072
|
const sandboxSessionState = prepared.sandboxSessionState ?? (prepared.serializedRunStateForSandbox && client ? await restoredSandboxSessionState(await RunState.fromString(agent, prepared.serializedRunStateForSandbox), client) : void 0);
|
|
2688
3073
|
const callModelInputFilter = composeCallModelInputFilters(
|
|
@@ -3356,6 +3741,16 @@ function sandboxRepositoryCloneHooksForAgent(agent) {
|
|
|
3356
3741
|
function gitTokenSeedForAgent(agent) {
|
|
3357
3742
|
return agentGitTokenSeed.get(agent);
|
|
3358
3743
|
}
|
|
3744
|
+
function toolspaceTokenSeedForAgent(agent) {
|
|
3745
|
+
return agentToolspaceTokenSeed.get(agent);
|
|
3746
|
+
}
|
|
3747
|
+
function sandboxToolspaceTokenHooksForAgent(agent) {
|
|
3748
|
+
return toolspaceTokenSeedForAgent(agent) ? [{
|
|
3749
|
+
id: "toolspace-token",
|
|
3750
|
+
phase: "beforeAgentStart",
|
|
3751
|
+
run: runToolspaceTokenSeedHook
|
|
3752
|
+
}] : [];
|
|
3753
|
+
}
|
|
3359
3754
|
function sandboxRepositoryCloneHooks(settings, resources, activeSandboxBackend = settings.sandboxBackend) {
|
|
3360
3755
|
const repositories = resources.filter((resource) => resource.kind === "repository" && repositoryUsesSandboxClone(settings, resource, activeSandboxBackend));
|
|
3361
3756
|
if (repositories.length === 0) {
|
|
@@ -3526,6 +3921,49 @@ function repositoryCloneCommand(resources) {
|
|
|
3526
3921
|
}
|
|
3527
3922
|
return commands.join("\n");
|
|
3528
3923
|
}
|
|
3924
|
+
function toolspaceTokenSeedCommand() {
|
|
3925
|
+
return [
|
|
3926
|
+
"set -eu",
|
|
3927
|
+
'export HOME="${HOME:-/workspace}"',
|
|
3928
|
+
'if [ -n "${OPENGENI_TOOLSPACE_TOKEN_SEED:-}" ]; then',
|
|
3929
|
+
' seed_umask="$(umask)"',
|
|
3930
|
+
" umask 077",
|
|
3931
|
+
' token_file="${OPENGENI_TOOLSPACE_TOKEN_FILE:-$HOME/.opengeni/toolspace-token}"',
|
|
3932
|
+
' mkdir -p "$(dirname "$token_file")"',
|
|
3933
|
+
` printf '%s' "$OPENGENI_TOOLSPACE_TOKEN_SEED" > "$token_file.tmp.$$"`,
|
|
3934
|
+
' mv -f "$token_file.tmp.$$" "$token_file"',
|
|
3935
|
+
' umask "$seed_umask"',
|
|
3936
|
+
"fi"
|
|
3937
|
+
].join("\n");
|
|
3938
|
+
}
|
|
3939
|
+
async function runToolspaceTokenSeedHook(session, context) {
|
|
3940
|
+
if (!context.toolspaceTokenSeed) {
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3943
|
+
const command = `export OPENGENI_TOOLSPACE_TOKEN_SEED=${shellQuote(context.toolspaceTokenSeed)}
|
|
3944
|
+
${toolspaceTokenSeedCommand()}`;
|
|
3945
|
+
if (session.exec) {
|
|
3946
|
+
const result = await session.exec({
|
|
3947
|
+
cmd: command,
|
|
3948
|
+
workdir: "/workspace",
|
|
3949
|
+
...context.runAs ? { runAs: context.runAs } : {},
|
|
3950
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
3951
|
+
maxOutputTokens: 4e3
|
|
3952
|
+
});
|
|
3953
|
+
assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
|
|
3954
|
+
} else if (session.execCommand) {
|
|
3955
|
+
const result = await session.execCommand({
|
|
3956
|
+
cmd: command,
|
|
3957
|
+
workdir: "/workspace",
|
|
3958
|
+
...context.runAs ? { runAs: context.runAs } : {},
|
|
3959
|
+
yieldTimeMs: SANDBOX_LIFECYCLE_COMMAND_TIMEOUT_MS,
|
|
3960
|
+
maxOutputTokens: 4e3
|
|
3961
|
+
});
|
|
3962
|
+
assertSandboxCommandSucceeded(result, "Toolspace token seed hook");
|
|
3963
|
+
} else {
|
|
3964
|
+
throw new Error("Sandbox session does not support command execution");
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3529
3967
|
async function runRepositoryCloneHook(session, resources, context = { environment: {} }) {
|
|
3530
3968
|
const payload = { name: "repository-clone", repositoryCount: resources.length };
|
|
3531
3969
|
await context.onRuntimeEvent?.({ type: "sandbox.operation.started", payload });
|
|
@@ -3874,7 +4312,6 @@ function approvalIdentifier(item) {
|
|
|
3874
4312
|
export {
|
|
3875
4313
|
ActiveBackendUnresolvableError,
|
|
3876
4314
|
CAPABILITY_DESCRIPTORS,
|
|
3877
|
-
CLIENT_COMPACTION_TRIGGER_FRACTION,
|
|
3878
4315
|
COMPACTION_PROMPT,
|
|
3879
4316
|
COMPACTION_SUMMARY_MARKER,
|
|
3880
4317
|
COMPACT_USER_MESSAGE_MAX_TOKENS,
|
|
@@ -3888,12 +4325,15 @@ export {
|
|
|
3888
4325
|
ComputerReadOnlyError,
|
|
3889
4326
|
ComputerUnavailableError,
|
|
3890
4327
|
ComputerUseCapability,
|
|
4328
|
+
DEFAULT_COMPACTION_THRESHOLD_RATIO,
|
|
3891
4329
|
DEFAULT_DESKTOP_GEOMETRY,
|
|
3892
4330
|
DESKTOP_STREAM_PORT,
|
|
3893
4331
|
DISPLAY_STACK_TIMEOUT_MS,
|
|
3894
4332
|
DisplayStackError,
|
|
3895
4333
|
DisplayStackUnsupportedError,
|
|
3896
4334
|
GENESIS_TITLE_DIRECTIVE,
|
|
4335
|
+
MAX_COMPACTION_THRESHOLD_RATIO,
|
|
4336
|
+
MIN_COMPACTION_THRESHOLD_RATIO,
|
|
3897
4337
|
MaxTurnsExceededError2 as MaxTurnsExceededError,
|
|
3898
4338
|
MockAgentResponder,
|
|
3899
4339
|
MultiProviderModelProvider,
|
|
@@ -3924,6 +4364,7 @@ export {
|
|
|
3924
4364
|
StreamTokenPayload,
|
|
3925
4365
|
TERMINAL_SERVER_TIMEOUT_MS,
|
|
3926
4366
|
TERMINAL_STREAM_PORT,
|
|
4367
|
+
TOOLSPACE_PROGRAMMATIC_DIRECTIVE,
|
|
3927
4368
|
TerminalServerError,
|
|
3928
4369
|
TerminalServerUnsupportedError,
|
|
3929
4370
|
USER_MESSAGE_TRUNCATION_MARKER,
|
|
@@ -3931,6 +4372,7 @@ export {
|
|
|
3931
4372
|
agentsErrorRunState,
|
|
3932
4373
|
appendGenesisTitleDirective,
|
|
3933
4374
|
appendSessionInstructions,
|
|
4375
|
+
appendToolspaceInstructions,
|
|
3934
4376
|
applyMissingManifestEntries,
|
|
3935
4377
|
assertDescriptorRegistryInvariants,
|
|
3936
4378
|
assertProviderRegistryInvariants,
|
|
@@ -3941,6 +4383,7 @@ export {
|
|
|
3941
4383
|
buildAgentCapabilities,
|
|
3942
4384
|
buildCompactionPromptInput,
|
|
3943
4385
|
buildCompactionReplacementHistory,
|
|
4386
|
+
buildDeterministicFallbackCompactionHistory,
|
|
3944
4387
|
buildDisplayStackScript,
|
|
3945
4388
|
buildManifest,
|
|
3946
4389
|
buildModelInstance,
|
|
@@ -3952,6 +4395,7 @@ export {
|
|
|
3952
4395
|
buildSummaryItem,
|
|
3953
4396
|
buildTerminalServerScript,
|
|
3954
4397
|
callModelInputFilterForSettings,
|
|
4398
|
+
clampCompactionThresholdRatio,
|
|
3955
4399
|
clientCompactionThresholdTokens,
|
|
3956
4400
|
collectSandboxEnvironment,
|
|
3957
4401
|
composeAgentInstructions,
|
|
@@ -3993,6 +4437,7 @@ export {
|
|
|
3993
4437
|
makeActiveBackendResolver,
|
|
3994
4438
|
materializeSandboxFileDownloads,
|
|
3995
4439
|
maxTurnsExceededRunState,
|
|
4440
|
+
mcpToolErrorOutput,
|
|
3996
4441
|
mintStreamToken,
|
|
3997
4442
|
modalSandboxAttributionEnvironment,
|
|
3998
4443
|
modalSandboxAttributionTags,
|
|
@@ -4025,6 +4470,7 @@ export {
|
|
|
4025
4470
|
runAzureCliLoginHook,
|
|
4026
4471
|
runBeforeAgentStartHooks,
|
|
4027
4472
|
runRepositoryCloneHook,
|
|
4473
|
+
runToolspaceTokenSeedHook,
|
|
4028
4474
|
sandboxCommandExitCode,
|
|
4029
4475
|
sandboxCommandOutput,
|
|
4030
4476
|
sandboxCommandStillRunning,
|
|
@@ -4053,6 +4499,7 @@ export {
|
|
|
4053
4499
|
terminateModalSandboxById,
|
|
4054
4500
|
timeoutAgentError,
|
|
4055
4501
|
timeoutControlResponse,
|
|
4502
|
+
toolspaceTokenSeedCommand,
|
|
4056
4503
|
verifyStreamToken,
|
|
4057
4504
|
withManifestRefreshOnResume,
|
|
4058
4505
|
withSandboxFileDownloads,
|