experimental-ash 0.35.0 → 0.36.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/docs/internals/context.md +6 -5
  3. package/dist/docs/internals/core-beliefs.md +2 -2
  4. package/dist/docs/internals/hooks.md +16 -11
  5. package/dist/docs/internals/mechanical-invariants.md +4 -4
  6. package/dist/docs/internals/testing.md +1 -1
  7. package/dist/docs/public/README.md +1 -1
  8. package/dist/docs/public/auth-and-route-protection.md +4 -4
  9. package/dist/docs/public/channels/{README.md → index.md} +2 -2
  10. package/dist/docs/public/channels/slack.md +3 -3
  11. package/dist/docs/public/cli-build-and-debugging.md +1 -1
  12. package/dist/docs/public/faqs.md +4 -5
  13. package/dist/docs/public/hooks.md +18 -23
  14. package/dist/docs/public/meta.json +4 -4
  15. package/dist/docs/public/sandbox.md +9 -11
  16. package/dist/docs/public/schedules.md +1 -1
  17. package/dist/docs/public/session-context.md +25 -27
  18. package/dist/docs/public/skills.md +3 -4
  19. package/dist/docs/public/subagents.md +1 -1
  20. package/dist/docs/public/tools.md +13 -17
  21. package/dist/docs/public/typescript-api.md +10 -11
  22. package/dist/src/channel/session.d.ts +3 -29
  23. package/dist/src/channel/session.js +1 -1
  24. package/dist/src/context/build-callback-context.d.ts +8 -0
  25. package/dist/src/context/build-callback-context.js +1 -0
  26. package/dist/src/context/hook-lifecycle.js +1 -1
  27. package/dist/src/execution/node-step.js +1 -1
  28. package/dist/src/execution/sandbox/bash-tool.d.ts +2 -1
  29. package/dist/src/execution/sandbox/bash-tool.js +1 -1
  30. package/dist/src/execution/sandbox/glob-tool.d.ts +2 -1
  31. package/dist/src/execution/sandbox/glob-tool.js +3 -3
  32. package/dist/src/execution/sandbox/grep-tool.d.ts +2 -1
  33. package/dist/src/execution/sandbox/grep-tool.js +3 -3
  34. package/dist/src/execution/sandbox/read-file-tool.d.ts +2 -1
  35. package/dist/src/execution/sandbox/read-file-tool.js +1 -1
  36. package/dist/src/execution/sandbox/write-file-tool.d.ts +2 -1
  37. package/dist/src/execution/sandbox/write-file-tool.js +1 -1
  38. package/dist/src/execution/tool-compaction.js +1 -1
  39. package/dist/src/harness/code-mode-approval.js +1 -1
  40. package/dist/src/harness/code-mode.js +1 -1
  41. package/dist/src/harness/tool-loop.js +1 -1
  42. package/dist/src/internal/application/package.js +1 -1
  43. package/dist/src/internal/workflow-bundle/builder.js +2 -2
  44. package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/index.js +1 -1
  45. package/dist/src/node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/runtime/manager.js +1 -0
  46. package/dist/src/node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/runtime/worker-source.js +408 -0
  47. package/dist/src/packages/ash-scaffold/src/channels.js +2 -12
  48. package/dist/src/packages/ash-scaffold/src/pnpm-workspace.js +11 -0
  49. package/dist/src/packages/ash-scaffold/src/project.js +1 -1
  50. package/dist/src/public/context/index.d.ts +3 -2
  51. package/dist/src/public/context/index.js +1 -1
  52. package/dist/src/public/definitions/callback-context.d.ts +22 -0
  53. package/dist/src/public/definitions/callback-context.js +1 -0
  54. package/dist/src/public/definitions/hook.d.ts +9 -49
  55. package/dist/src/public/definitions/tool.d.ts +14 -15
  56. package/dist/src/public/hooks/index.d.ts +1 -1
  57. package/dist/src/public/sandbox/index.d.ts +0 -1
  58. package/dist/src/public/sandbox/index.js +1 -1
  59. package/dist/src/public/skills/index.d.ts +0 -1
  60. package/dist/src/public/skills/index.js +1 -1
  61. package/dist/src/public/tools/defaults.js +1 -1
  62. package/dist/src/public/tools/define-bash-tool.js +1 -1
  63. package/dist/src/public/tools/define-glob-tool.js +1 -1
  64. package/dist/src/public/tools/define-grep-tool.js +1 -1
  65. package/dist/src/public/tools/define-read-file-tool.js +1 -1
  66. package/dist/src/public/tools/define-write-file-tool.js +1 -1
  67. package/dist/src/public/tools/index.d.ts +2 -1
  68. package/dist/src/public/tools/internal.d.ts +4 -0
  69. package/dist/src/public/tools/internal.js +1 -1
  70. package/dist/src/runtime/framework-tools/bash.js +1 -1
  71. package/dist/src/runtime/framework-tools/connection-search.js +1 -1
  72. package/dist/src/runtime/framework-tools/connection-tools.js +1 -1
  73. package/dist/src/runtime/framework-tools/file-state.d.ts +2 -2
  74. package/dist/src/runtime/framework-tools/file-state.js +1 -1
  75. package/dist/src/runtime/framework-tools/glob.js +1 -1
  76. package/dist/src/runtime/framework-tools/grep.js +1 -1
  77. package/dist/src/runtime/framework-tools/read-file.js +2 -2
  78. package/dist/src/runtime/framework-tools/todo.js +1 -1
  79. package/dist/src/runtime/framework-tools/write-file.js +1 -1
  80. package/dist/src/runtime/types.d.ts +2 -2
  81. package/package.json +2 -2
  82. package/dist/src/node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/runtime/manager.js +0 -1
  83. package/dist/src/node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/runtime/worker-source.js +0 -1153
  84. package/dist/src/node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/runtime-assets.js +0 -1
  85. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/approval-continuation.js +0 -0
  86. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/approval-response.js +0 -0
  87. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/code-mode-tool.js +0 -0
  88. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/continuation-capability.js +0 -0
  89. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/errors.js +0 -0
  90. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/fetch-policy.js +0 -0
  91. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/host-interrupt.js +0 -0
  92. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/interrupt-continuation.js +0 -0
  93. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/options.js +0 -0
  94. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/run-code-mode.js +0 -0
  95. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/runtime/max-workers.js +0 -0
  96. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/serialization.js +0 -0
  97. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/source-cache.js +0 -0
  98. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/telemetry.js +0 -0
  99. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/tool-invocation.js +0 -0
  100. /package/dist/src/node_modules/.pnpm/{experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_ → experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_}/node_modules/experimental-ai-sdk-code-mode/dist/tool-prompt.js +0 -0
@@ -1,17 +1,7 @@
1
- import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_ASH_RELEASE_AGE_EXCLUSION=` - experimental-ash`,WEB_SHARP_BUILD_POLICY=` sharp: false`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.35.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.154`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},s=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:s}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(s)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
1
+ import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.36.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.154`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
2
2
  import { slackChannel } from "experimental-ash/channels/slack";
3
3
 
4
4
  export default slackChannel({
5
5
  credentials: connectSlackCredentials("slack/${e}"),
6
6
  });
7
- `}function renderWebAppTemplate(e,t){return e.replaceAll(`__ASH_INIT_APP_NAME__`,t)}function findYamlBlockEnd(e,t){let n=t+1;for(;n<e.length;){let t=e[n]??``;if(t.length>0&&!t.startsWith(` `)&&!t.startsWith(` `))break;n+=1}return n}function withSharpBuildPolicy(e){let t=e.endsWith(`
8
- `)?e:`${e}\n`,n=t.split(`
9
- `),r=n.findIndex(e=>e===`allowBuilds:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}allowBuilds:\n${WEB_SHARP_BUILD_POLICY}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>/^\s+sharp:/.test(e)))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,WEB_SHARP_BUILD_POLICY),n.join(`
10
- `)}function withExperimentalAshReleaseAgeExclusion(e){let t=e.endsWith(`
11
- `)?e:`${e}\n`,n=t.split(`
12
- `),r=n.findIndex(e=>e===`minimumReleaseAgeExclude:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}minimumReleaseAgeExclude:\n${WEB_ASH_RELEASE_AGE_EXCLUSION}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>e.trim()===`- experimental-ash`))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,WEB_ASH_RELEASE_AGE_EXCLUSION),n.join(`
13
- `)}async function ensureWebPnpmWorkspacePolicy(e,t){if(!await pathExists(e))return await writeTextFile(e,t,{force:!0}),`written`;let i=await readFile(e,`utf8`),a=withExperimentalAshReleaseAgeExclusion(withSharpBuildPolicy(i));return a===i?`skipped`:(await writeFile(e,a,`utf8`),`written`)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,ash:n?.ash??WEB_DEFAULT_VERCEL_SERVICES.ash}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}function assertStampedVersion(e,t){if(t.startsWith(`__`))throw Error(`Channel scaffold received unstamped version token (${e}=${t}). Build @vercel/ash-scaffold before using its dist entrypoint.`)}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(e){let t=join(e.projectRoot,`package.json`),a=await pathExists(join(e.projectRoot,`app/page.tsx`));if(!e.force&&await hasPackageDependency(t,`next`))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=await patchWebPackageJson(t,resolveWebPackageVersions(e.webPackageVersions)),c=[],l=[],u=basename(resolve(e.projectRoot)),d=join(e.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(d)===`written`?c.push(d):l.push(d);let f=join(e.projectRoot,`pnpm-workspace.yaml`);await ensureWebPnpmWorkspacePolicy(f,`minimumReleaseAgeExclude:
14
- - experimental-ash
15
- allowBuilds:
16
- sharp: false
17
- `)===`written`?c.push(f):l.push(f);for(let[t,a]of Object.entries(WEB_APP_TEMPLATE_FILES)){let i=join(e.projectRoot,t);if(t===`agent/channels/ash.ts`&&!e.force&&await pathExists(i)){l.push(i);continue}await writeTextFile(i,renderWebAppTemplate(a,u),{force:!0}),c.push(i)}return{kind:`web`,action:a?`overwritten`:`created`,filesWritten:c,filesSkipped:l,packageJsonUpdated:o}}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let a=e.connectPackageVersion??`0.0.6-alpha.1`;assertStampedVersion(`connectPackageVersion`,a);let o=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,a),s=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);return await writeTextFile(t,buildSlackTemplate(s),{force:e.force}),{kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:o,slackConnectorSlug:s}}async function listAuthoredChannels(n){let r=join(n,`agent/channels`),i;try{i=await readdir(r,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let a=[];for(let n of i){if(n.isFile()){let t=getSupportedModuleBaseName(n.name);t!==null&&a.push(t);continue}if(n.isDirectory())try{(await readdir(join(r,n.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&a.push(n.name)}catch{}}return a.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,listAuthoredChannels,normalizeSlackConnectorSlug};
7
+ `}function renderWebAppTemplate(e,t){return e.replaceAll(`__ASH_INIT_APP_NAME__`,t)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,ash:n?.ash??WEB_DEFAULT_VERCEL_SERVICES.ash}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}function assertStampedVersion(e,t){if(t.startsWith(`__`))throw Error(`Channel scaffold received unstamped version token (${e}=${t}). Build @vercel/ash-scaffold before using its dist entrypoint.`)}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(e){let t=join(e.projectRoot,`package.json`),s=await pathExists(join(e.projectRoot,`app/page.tsx`));if(!e.force&&await hasPackageDependency(t,`next`))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let c=await patchWebPackageJson(t,resolveWebPackageVersions(e.webPackageVersions)),l=[],u=[],d=basename(resolve(e.projectRoot)),f=join(e.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(f)===`written`?l.push(f):u.push(f);let p=join(e.projectRoot,PNPM_WORKSPACE_PATH);await ensurePnpmWorkspacePolicy(p)===`written`?l.push(p):u.push(p);for(let[t,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(e.projectRoot,t);if(t===`agent/channels/ash.ts`&&!e.force&&await pathExists(a)){u.push(a);continue}await writeTextFile(a,renderWebAppTemplate(i,d),{force:!0}),l.push(a)}return{kind:`web`,action:s?`overwritten`:`created`,filesWritten:l,filesSkipped:u,packageJsonUpdated:c}}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let a=e.connectPackageVersion??`0.0.6-alpha.1`;assertStampedVersion(`connectPackageVersion`,a);let o=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,a),s=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);return await writeTextFile(t,buildSlackTemplate(s),{force:e.force}),{kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:o,slackConnectorSlug:s}}async function listAuthoredChannels(n){let r=join(n,`agent/channels`),i;try{i=await readdir(r,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let a=[];for(let n of i){if(n.isFile()){let t=getSupportedModuleBaseName(n.name);t!==null&&a.push(t);continue}if(n.isDirectory())try{(await readdir(join(r,n.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&a.push(n.name)}catch{}}return a.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,listAuthoredChannels,normalizeSlackConnectorSlug};
@@ -0,0 +1,11 @@
1
+ import{pathExists,writeTextFile}from"./files.js";import{readFile,writeFile}from"node:fs/promises";const PNPM_WORKSPACE_PATH=`pnpm-workspace.yaml`,PNPM_WORKSPACE_CONTENT=`minimumReleaseAgeExclude:
2
+ - experimental-ash
3
+ allowBuilds:
4
+ sharp: false
5
+ `,ASH_RELEASE_AGE_EXCLUSION=` - experimental-ash`,SHARP_BUILD_POLICY=` sharp: false`;function findYamlBlockEnd(e,t){let n=t+1;for(;n<e.length;){let t=e[n]??``;if(t.length>0&&!t.startsWith(` `)&&!t.startsWith(` `))break;n+=1}return n}function withSharpBuildPolicy(e){let t=e.endsWith(`
6
+ `)?e:`${e}\n`,n=t.split(`
7
+ `),r=n.findIndex(e=>e===`allowBuilds:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}allowBuilds:\n${SHARP_BUILD_POLICY}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>/^\s+sharp:/.test(e)))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,SHARP_BUILD_POLICY),n.join(`
8
+ `)}function withExperimentalAshReleaseAgeExclusion(e){let t=e.endsWith(`
9
+ `)?e:`${e}\n`,n=t.split(`
10
+ `),r=n.findIndex(e=>e===`minimumReleaseAgeExclude:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}minimumReleaseAgeExclude:\n${ASH_RELEASE_AGE_EXCLUSION}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>e.trim()===`- experimental-ash`))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,ASH_RELEASE_AGE_EXCLUSION),n.join(`
11
+ `)}async function ensurePnpmWorkspacePolicy(i){if(!await pathExists(i))return await writeTextFile(i,PNPM_WORKSPACE_CONTENT,{force:!0}),`written`;let o=await readFile(i,`utf8`),s=withExperimentalAshReleaseAgeExclusion(withSharpBuildPolicy(o));return s===o?`skipped`:(await writeFile(i,s,`utf8`),`written`)}export{PNPM_WORKSPACE_CONTENT,PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy};
@@ -1 +1 @@
1
- import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"./module-files.js";import"./files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{join}from"node:path";import{stat}from"node:fs/promises";new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),WEB_APP_TEMPLATE_FILES[`agent/channels/ash.ts`];async function isAshProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{isAshProject};
1
+ import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"./module-files.js";import"./files.js";import"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{join}from"node:path";import{stat}from"node:fs/promises";new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),WEB_APP_TEMPLATE_FILES[`agent/channels/ash.ts`];async function isAshProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{isAshProject};
@@ -6,8 +6,9 @@
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
- * import { defineState, getSession } from "experimental-ash/context";
9
+ * import { defineState } from "experimental-ash/context";
10
10
  * ```
11
11
  */
12
- export { getSession, type Session, type SessionAuth, type SessionAuthContext, type SessionParent, type SessionTurn, } from "#context/accessors.js";
12
+ export type { Session, SessionAuth, SessionAuthContext, SessionParent, SessionTurn, } from "#context/accessors.js";
13
13
  export { defineState, type StateHandle } from "#public/definitions/state.js";
14
+ export type { AshCallbackContext } from "#public/definitions/callback-context.js";
@@ -1 +1 @@
1
- import{getSession}from"#context/accessors.js";import{defineState}from"#public/definitions/state.js";export{defineState,getSession};
1
+ import{defineState}from"#public/definitions/state.js";export{defineState};
@@ -0,0 +1,22 @@
1
+ import type { SkillHandle } from "#execution/skills/types.js";
2
+ import type { SandboxSession } from "#shared/sandbox-session.js";
3
+ import type { SessionAuth, SessionParent, SessionTurn } from "#context/keys.js";
4
+ export type { SessionAuth, SessionParent, SessionTurn };
5
+ /**
6
+ * Shared runtime context available to all authored callbacks that run
7
+ * inside the ALS-scoped harness step (tools, hooks, channel events).
8
+ *
9
+ * Non-ALS callbacks (schedule `run`, sandbox `bootstrap`/`onSession`,
10
+ * instrumentation `setup`) do not receive this context — they get
11
+ * domain-specific arguments instead.
12
+ */
13
+ export interface AshCallbackContext {
14
+ readonly session: {
15
+ readonly id: string;
16
+ readonly auth: SessionAuth;
17
+ readonly turn: SessionTurn;
18
+ readonly parent?: SessionParent;
19
+ };
20
+ getSandbox(): Promise<SandboxSession>;
21
+ getSkill(identifier: string): SkillHandle;
22
+ }
@@ -0,0 +1 @@
1
+ export{};
@@ -1,16 +1,14 @@
1
1
  import type { ModelMessage } from "ai";
2
- import type { ContextAccessor } from "../../context/key.js";
3
2
  import type { HandleMessageStreamEvent } from "../../protocol/message.js";
3
+ import type { AshCallbackContext } from "./callback-context.js";
4
4
  import type { NamedSkillDefinition } from "./skill.js";
5
5
  /**
6
6
  * Context passed to every hook handler.
7
7
  *
8
- * Hook code reads and writes durable state through {@link ash}, the same
9
- * `ContextAccessor` used by tools, channels, and providers. The hooks
10
- * surface deliberately introduces no parallel state-patch channel — one
11
- * `AshContext`, one set of keys, one place to look when debugging.
8
+ * Extends {@link AshCallbackContext} with agent and channel metadata.
9
+ * `ctx` is always the last argument.
12
10
  */
13
- export interface HookContext {
11
+ export interface HookContext extends AshCallbackContext {
14
12
  readonly agent: {
15
13
  readonly name: string;
16
14
  readonly nodeId?: string;
@@ -19,27 +17,6 @@ export interface HookContext {
19
17
  readonly kind?: string;
20
18
  readonly continuationToken?: string;
21
19
  };
22
- readonly session: {
23
- readonly sessionId: string;
24
- };
25
- /**
26
- * Read/write access to durable and virtual context keys. Same accessor
27
- * tools, providers, and channels use.
28
- */
29
- readonly ash: ContextAccessor;
30
- }
31
- /**
32
- * Input passed to every lifecycle hook handler
33
- * (`lifecycle.session`, `lifecycle.turn`).
34
- */
35
- export interface LifecycleHookInput {
36
- readonly session: {
37
- readonly sessionId: string;
38
- };
39
- readonly turn: {
40
- readonly sequence: number;
41
- readonly turnId: string;
42
- };
43
20
  }
44
21
  /**
45
22
  * Result returned by a lifecycle hook (`lifecycle.session` or
@@ -67,25 +44,14 @@ export interface LifecycleHookResult {
67
44
  * Lifecycle hook signature shared by `lifecycle.session` and
68
45
  * `lifecycle.turn`.
69
46
  *
70
- * `lifecycle.session` runs once per durable session, before the first
71
- * model turn. The runtime sets `ash.sessionPrepared` before the chain
72
- * runs, so a thrown hook leaves the flag set and the chain does not
73
- * retry on the next turn — the throw fails the session terminally
74
- * (`session.failed`).
75
- *
76
- * `lifecycle.turn` runs once per fresh delivery (tool-loop continuations
77
- * and runtime-action resumes do not re-fire it). A thrown hook fails the
78
- * current turn (`turn.failed`) but the session keeps living.
47
+ * `ctx` is the sole argument session identity, auth, turn info,
48
+ * agent metadata, and channel metadata are all on `ctx`.
79
49
  */
80
- export type LifecycleHook = (input: LifecycleHookInput, ctx: HookContext) => void | LifecycleHookResult | Promise<void | LifecycleHookResult>;
50
+ export type LifecycleHook = (ctx: HookContext) => void | LifecycleHookResult | Promise<void | LifecycleHookResult>;
81
51
  /**
82
52
  * Side-effect-only handler for one accepted runtime stream event.
83
53
  *
84
- * Stream-event hooks run after Ash has accepted the event and written
85
- * it to the durable stream; their return values are ignored. Errors
86
- * propagate through the emit composer and fail the current turn
87
- * (`turn.failed`). Authors who want belt-and-suspenders semantics
88
- * wrap their body in `try`/`catch`.
54
+ * The typed event is the first argument, `ctx` is the last.
89
55
  */
90
56
  export type StreamEventHook<TEvent> = (event: TEvent, ctx: HookContext) => void | Promise<void>;
91
57
  /**
@@ -115,9 +81,6 @@ export type StreamEventHooks = {
115
81
  * stream-event subscribers (under `events:`), or both. The structural
116
82
  * split makes the contract explicit: `lifecycle:` can mutate the next
117
83
  * model call's context; `events:` is observe-only.
118
- *
119
- * Filenames carry stable identity for diagnostics and ordering; they
120
- * have no runtime semantics beyond identity.
121
84
  */
122
85
  export interface HookDefinition {
123
86
  readonly lifecycle?: LifecycleHooks;
@@ -127,8 +90,5 @@ export interface HookDefinition {
127
90
  * Identity-with-types helper. Authors export
128
91
  * `defineHook({ lifecycle: { session, turn }, events: { "session.started": … } })`
129
92
  * and receive a typed {@link HookDefinition}.
130
- *
131
- * `defineHook` runs no side effects — it exists purely so authors get
132
- * type checking and editor inference on the lifecycle and event keys.
133
93
  */
134
- export declare function defineHook(definition: HookDefinition): HookDefinition;
94
+ export declare function defineHook<T extends HookDefinition>(definition: T): T;
@@ -1,19 +1,12 @@
1
1
  import type { StandardJSONSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
2
2
  import type { ModelMessage } from "ai";
3
- import type { AshContext } from "#context/container.js";
4
- import type { HarnessSession } from "#harness/types.js";
5
- import type { PublicToolDefinitionWithExecuteFn } from "#shared/tool-definition.js";
3
+ import type { PublicToolDefinition } from "#shared/tool-definition.js";
4
+ import type { AshCallbackContext } from "#public/definitions/callback-context.js";
6
5
  /**
7
- * Input passed to a tool's {@link ToolDefinition.onCompact} hook.
8
- *
9
- * Hooks run inside the same `AshContext` scope as the surrounding harness
10
- * step, so they may read or mutate context state via {@link ctx}. The
11
- * {@link session} is the harness session as it stands immediately after
12
- * message-history compaction.
6
+ * Domain input passed to a tool's {@link ToolDefinition.onCompact} hook.
13
7
  */
14
- export interface CompactionHookInput {
15
- readonly ctx: AshContext;
16
- readonly session: HarnessSession;
8
+ export interface CompactionInput {
9
+ readonly history: readonly ModelMessage[];
17
10
  readonly signal: AbortSignal;
18
11
  }
19
12
  /**
@@ -85,6 +78,11 @@ export interface RetentionSummary {
85
78
  * pure — no external I/O.
86
79
  */
87
80
  export type ToolRetentionPolicy<TOutput = unknown> = "auto" | "keep" | ((output: TOutput) => RetentionSummary);
81
+ /**
82
+ * Authored tool context. Passed as the last argument to
83
+ * {@link ToolDefinition.execute}.
84
+ */
85
+ export type ToolContext = AshCallbackContext;
88
86
  /**
89
87
  * Public tool definition authored in `agent/tools/*.ts`.
90
88
  *
@@ -95,7 +93,8 @@ export type ToolRetentionPolicy<TOutput = unknown> = "auto" | "keep" | ((output:
95
93
  * `get-weather`. Authored definitions do not carry a `name` field —
96
94
  * identity is path-derived.
97
95
  */
98
- export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefinitionWithExecuteFn<TInput, TOutput> & {
96
+ export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefinition<TInput> & {
97
+ execute(input: TInput, ctx: ToolContext): Promise<TOutput> | TOutput;
99
98
  /**
100
99
  * Optional per-tool approval gate. When set, the function's return value
101
100
  * determines whether user approval is required before executing this tool.
@@ -133,7 +132,7 @@ export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefi
133
132
  * Return `void` (or `{}`) for "no change". Errors fail the compaction
134
133
  * step — do not swallow them.
135
134
  */
136
- onCompact?(input: CompactionHookInput): CompactionHookResult | Promise<CompactionHookResult> | void | Promise<void>;
135
+ onCompact?(input: CompactionInput, ctx: ToolContext): CompactionHookResult | Promise<CompactionHookResult> | void | Promise<void>;
137
136
  };
138
137
  /**
139
138
  * Defines a tool configuration.
@@ -141,7 +140,7 @@ export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefi
141
140
  export declare function defineTool<TSchema extends StandardJSONSchemaV1<unknown, unknown>, TOutput>(definition: {
142
141
  description: ToolDefinition<unknown, unknown>["description"];
143
142
  inputSchema: TSchema;
144
- execute: ToolDefinition<StandardJSONSchemaV1.InferOutput<TSchema>, TOutput>["execute"];
143
+ execute(input: StandardJSONSchemaV1.InferOutput<TSchema>, ctx: ToolContext): Promise<TOutput> | TOutput;
145
144
  needsApproval?: ToolDefinition<unknown, unknown>["needsApproval"];
146
145
  retentionPolicy?: ToolDefinition<unknown, TOutput>["retentionPolicy"];
147
146
  toModelOutput?: ToolDefinition<unknown, TOutput>["toModelOutput"];
@@ -6,4 +6,4 @@
6
6
  * authoring shape and {@link HookContext} for the runtime context every
7
7
  * handler receives.
8
8
  */
9
- export { type HookContext, type HookDefinition, type LifecycleHook, type LifecycleHookInput, type LifecycleHookResult, type LifecycleHooks, type StreamEventHook, type StreamEventHooks, defineHook, } from "../definitions/hook.js";
9
+ export { type HookContext, type HookDefinition, type LifecycleHook, type LifecycleHookResult, type LifecycleHooks, type StreamEventHook, type StreamEventHooks, defineHook, } from "../definitions/hook.js";
@@ -2,7 +2,6 @@
2
2
  * Sandbox authoring helpers for `agent/sandbox.ts` (or
3
3
  * `agent/sandbox/sandbox.ts` when paired with a `workspace/` folder).
4
4
  */
5
- export { getSandbox } from "#context/accessors.js";
6
5
  export { defineSandbox, type SandboxBootstrapContext, type SandboxBootstrapUseFn, type SandboxCommandResult, type SandboxDefinition, type SandboxProcess, type SandboxReadBinaryFileOptions, type SandboxReadFileOptions, type SandboxReadTextFileOptions, type SandboxRunOptions, type SandboxSession, type SandboxSpawnOptions, type SandboxSessionContext, type SandboxSessionUseFn, type SandboxWriteBinaryFileOptions, type SandboxWriteFileOptions, type SandboxWriteTextFileOptions, } from "#public/definitions/sandbox.js";
7
6
  export type { SandboxBackend, SandboxBackendCreateInput, SandboxBackendHandle, SandboxBackendPrewarmInput, SandboxBackendRuntimeContext, SandboxBackendSessionState, SandboxSeedFile, } from "#public/definitions/sandbox-backend.js";
8
7
  export { SandboxTemplateNotProvisionedError } from "#public/definitions/sandbox-backend.js";
@@ -1 +1 @@
1
- import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{getSandbox}from"#context/accessors.js";import{localBackend}from"#public/sandbox/backends/local.js";import{vercelBackend}from"#public/sandbox/backends/vercel.js";import{defineSandbox}from"#public/definitions/sandbox.js";import{defaultBackend}from"#public/sandbox/backends/default.js";export{SandboxTemplateNotProvisionedError,defaultBackend,defineSandbox,getSandbox,localBackend,vercelBackend};
1
+ import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{localBackend}from"#public/sandbox/backends/local.js";import{vercelBackend}from"#public/sandbox/backends/vercel.js";import{defineSandbox}from"#public/definitions/sandbox.js";import{defaultBackend}from"#public/sandbox/backends/default.js";export{SandboxTemplateNotProvisionedError,defaultBackend,defineSandbox,localBackend,vercelBackend};
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Skill authoring helpers and runtime accessors.
3
3
  */
4
- export { getSkill } from "#context/accessors.js";
5
4
  export type { SkillFile, SkillHandle } from "#execution/skills/types.js";
6
5
  export { defineSkill, type NamedSkillDefinition, type SkillDefinition, type SkillFileContent, type SkillPackageDefinition, } from "#public/definitions/skill.js";
@@ -1 +1 @@
1
- import{defineSkill}from"#public/definitions/skill.js";import{getSkill}from"#context/accessors.js";export{defineSkill,getSkill};
1
+ import{defineSkill}from"#public/definitions/skill.js";export{defineSkill};
@@ -1 +1 @@
1
- import{WEB_SEARCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-search.js";import{BASH_TOOL_DEFINITION}from"#runtime/framework-tools/bash.js";import{GLOB_TOOL_DEFINITION}from"#runtime/framework-tools/glob.js";import{GREP_TOOL_DEFINITION}from"#runtime/framework-tools/grep.js";import{READ_FILE_TOOL_DEFINITION}from"#runtime/framework-tools/read-file.js";import{SKILL_TOOL_DEFINITION}from"#runtime/framework-tools/skill.js";import{TODO_TOOL_DEFINITION}from"#runtime/framework-tools/todo.js";import{WEB_FETCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-fetch.js";import{WRITE_FILE_TOOL_DEFINITION}from"#runtime/framework-tools/write-file.js";import{toPublicToolDefinition}from"#public/tools/internal.js";const bash=toPublicToolDefinition(BASH_TOOL_DEFINITION),glob=toPublicToolDefinition(GLOB_TOOL_DEFINITION),grep=toPublicToolDefinition(GREP_TOOL_DEFINITION),readFile=toPublicToolDefinition(READ_FILE_TOOL_DEFINITION),writeFile=toPublicToolDefinition(WRITE_FILE_TOOL_DEFINITION),webFetch=toPublicToolDefinition(WEB_FETCH_TOOL_DEFINITION),todo=toPublicToolDefinition(TODO_TOOL_DEFINITION),loadSkill=toPublicToolDefinition(SKILL_TOOL_DEFINITION),webSearch={description:WEB_SEARCH_TOOL_DEFINITION.description,inputSchema:{},execute(){throw Error(`web_search is provider-managed and has no local execute. Override with defineTool() to provide a custom implementation.`)}};export{bash,glob,grep,loadSkill,readFile,todo,webFetch,webSearch,writeFile};
1
+ import{WEB_SEARCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-search.js";import{BASH_TOOL_DEFINITION}from"#runtime/framework-tools/bash.js";import{GLOB_TOOL_DEFINITION}from"#runtime/framework-tools/glob.js";import{GREP_TOOL_DEFINITION}from"#runtime/framework-tools/grep.js";import{READ_FILE_TOOL_DEFINITION}from"#runtime/framework-tools/read-file.js";import{SKILL_TOOL_DEFINITION}from"#runtime/framework-tools/skill.js";import{TODO_TOOL_DEFINITION}from"#runtime/framework-tools/todo.js";import{WEB_FETCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-fetch.js";import{WRITE_FILE_TOOL_DEFINITION}from"#runtime/framework-tools/write-file.js";import{toPublicToolDefinition}from"#public/tools/internal.js";const bash=toPublicToolDefinition(BASH_TOOL_DEFINITION),glob=toPublicToolDefinition(GLOB_TOOL_DEFINITION),grep=toPublicToolDefinition(GREP_TOOL_DEFINITION),readFile=toPublicToolDefinition(READ_FILE_TOOL_DEFINITION),writeFile=toPublicToolDefinition(WRITE_FILE_TOOL_DEFINITION),webFetch=toPublicToolDefinition(WEB_FETCH_TOOL_DEFINITION),todo=toPublicToolDefinition(TODO_TOOL_DEFINITION),loadSkill=toPublicToolDefinition(SKILL_TOOL_DEFINITION),webSearch={description:WEB_SEARCH_TOOL_DEFINITION.description,inputSchema:{},execute(e){throw Error(`web_search is provider-managed and has no local execute. Override with defineTool() to provide a custom implementation.`)}};export{bash,glob,grep,loadSkill,readFile,todo,webFetch,webSearch,writeFile};
@@ -1 +1 @@
1
- import{BASH_INPUT_SCHEMA}from"#runtime/framework-tools/bash.js";import{executeBashOnSandbox}from"#execution/sandbox/bash-tool.js";function defineBashTool(t={}){return{description:t.description??`Execute a shell command in the workspace sandbox.`,async execute(e){return executeBashOnSandbox(e)},inputSchema:BASH_INPUT_SCHEMA}}export{defineBashTool};
1
+ import{BASH_INPUT_SCHEMA}from"#runtime/framework-tools/bash.js";import{executeBashOnSandbox}from"#execution/sandbox/bash-tool.js";function defineBashTool(t={}){return{description:t.description??`Execute a shell command in the workspace sandbox.`,async execute(e,t){return executeBashOnSandbox(await t.getSandbox(),e)},inputSchema:BASH_INPUT_SCHEMA}}export{defineBashTool};
@@ -1 +1 @@
1
- import{GLOB_INPUT_SCHEMA}from"#runtime/framework-tools/glob.js";import{executeGlobOnSandbox}from"#execution/sandbox/glob-tool.js";function defineGlobTool(t={}){return{description:t.description??`Search for files by glob pattern in the workspace sandbox.`,async execute(e){return executeGlobOnSandbox(e)},inputSchema:GLOB_INPUT_SCHEMA}}export{defineGlobTool};
1
+ import{GLOB_INPUT_SCHEMA}from"#runtime/framework-tools/glob.js";import{executeGlobOnSandbox}from"#execution/sandbox/glob-tool.js";function defineGlobTool(t={}){return{description:t.description??`Search for files by glob pattern in the workspace sandbox.`,async execute(e,t){return executeGlobOnSandbox(await t.getSandbox(),e)},inputSchema:GLOB_INPUT_SCHEMA}}export{defineGlobTool};
@@ -1 +1 @@
1
- import{GREP_INPUT_SCHEMA}from"#runtime/framework-tools/grep.js";import{executeGrepOnSandbox}from"#execution/sandbox/grep-tool.js";function defineGrepTool(t={}){return{description:t.description??`Search file contents by pattern in the workspace sandbox.`,async execute(e){return executeGrepOnSandbox(e)},inputSchema:GREP_INPUT_SCHEMA}}export{defineGrepTool};
1
+ import{GREP_INPUT_SCHEMA}from"#runtime/framework-tools/grep.js";import{executeGrepOnSandbox}from"#execution/sandbox/grep-tool.js";function defineGrepTool(t={}){return{description:t.description??`Search file contents by pattern in the workspace sandbox.`,async execute(e,t){return executeGrepOnSandbox(await t.getSandbox(),e)},inputSchema:GREP_INPUT_SCHEMA}}export{defineGrepTool};
@@ -1 +1 @@
1
- import{clearReadFileState}from"#runtime/framework-tools/file-state.js";import{READ_FILE_INPUT_SCHEMA}from"#runtime/framework-tools/read-file.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file-tool.js";function defineReadFileTool(n={}){let r=n.onCompact??(({ctx:t})=>(clearReadFileState(t),{}));return{description:n.description??`Read a file from the workspace sandbox.`,async execute(e){return executeReadFileOnSandbox(e)},inputSchema:READ_FILE_INPUT_SCHEMA,onCompact:r}}export{defineReadFileTool};
1
+ import{clearReadFileState}from"#runtime/framework-tools/file-state.js";import{READ_FILE_INPUT_SCHEMA}from"#runtime/framework-tools/read-file.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file-tool.js";function defineReadFileTool(n={}){let r=n.onCompact??(()=>(clearReadFileState(),{}));return{description:n.description??`Read a file from the workspace sandbox.`,async execute(e,t){return executeReadFileOnSandbox(await t.getSandbox(),e)},inputSchema:READ_FILE_INPUT_SCHEMA,onCompact:r}}export{defineReadFileTool};
@@ -1 +1 @@
1
- import{WRITE_FILE_INPUT_SCHEMA}from"#runtime/framework-tools/write-file.js";import{executeWriteFileOnSandbox}from"#execution/sandbox/write-file-tool.js";function defineWriteFileTool(t={}){return{description:t.description??`Write a file to the workspace sandbox.`,async execute(e){return executeWriteFileOnSandbox(e)},inputSchema:WRITE_FILE_INPUT_SCHEMA}}export{defineWriteFileTool};
1
+ import{WRITE_FILE_INPUT_SCHEMA}from"#runtime/framework-tools/write-file.js";import{executeWriteFileOnSandbox}from"#execution/sandbox/write-file-tool.js";function defineWriteFileTool(t={}){return{description:t.description??`Write a file to the workspace sandbox.`,async execute(e,t){return executeWriteFileOnSandbox(await t.getSandbox(),e)},inputSchema:WRITE_FILE_INPUT_SCHEMA}}export{defineWriteFileTool};
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Tool authoring helpers for `agent/tools/*.ts` files.
3
3
  */
4
- export { type CompactionHookInput, type CompactionHookResult, type DisabledToolSentinel, defineTool, disableTool, isDisabledToolSentinel, type NeedsApprovalContext, type RetentionSummary, type ToolDefinition, type ToolModelOutput, type ToolRetentionPolicy, } from "#public/definitions/tool.js";
4
+ export { type CompactionInput, type CompactionHookResult, type DisabledToolSentinel, defineTool, disableTool, isDisabledToolSentinel, type NeedsApprovalContext, type RetentionSummary, type ToolDefinition, type ToolContext, type ToolModelOutput, type ToolRetentionPolicy, } from "#public/definitions/tool.js";
5
+ export { type AshCallbackContext } from "#public/definitions/callback-context.js";
5
6
  export { toolResultFrom, type MatchedConnectionResult, type MatchedToolResult, type ToolResultFromFn, } from "#public/tool-result-narrowing.js";
6
7
  export { type DefineBashToolInput, defineBashTool } from "#public/tools/define-bash-tool.js";
7
8
  export { type DefineGlobToolInput, defineGlobTool } from "#public/tools/define-glob-tool.js";
@@ -4,5 +4,9 @@ import type { ToolDefinition } from "#public/definitions/tool.js";
4
4
  * Converter that strips internal identity fields from a framework
5
5
  * {@link ResolvedToolDefinition} so it can be re-exported as a public
6
6
  * {@link ToolDefinition}.
7
+ *
8
+ * Framework tools have the internal `(input) => output` signature.
9
+ * The public {@link ToolDefinition.execute} expects `(input, ctx)`.
10
+ * This wrapper bridges the gap — `ctx` is trailing and omitted.
7
11
  */
8
12
  export declare function toPublicToolDefinition(definition: ResolvedToolDefinition): ToolDefinition;
@@ -1 +1 @@
1
- function toPublicToolDefinition(e){if(!e.execute)throw Error(`Tool "${e.name}" is client-side and cannot be re-exported publicly.`);let t=e.execute,n=e.inputSchema,r={description:e.description,execute:t,inputSchema:n??{}};return e.needsApproval!==void 0&&(r.needsApproval=e.needsApproval),e.onCompact!==void 0&&(r.onCompact=e.onCompact),r}export{toPublicToolDefinition};
1
+ function toPublicToolDefinition(e){if(!e.execute)throw Error(`Tool "${e.name}" is client-side and cannot be re-exported publicly.`);let t=e.execute,n=e.inputSchema,r={description:e.description,execute:e=>t(e),inputSchema:n??{}};return e.needsApproval!==void 0&&(r.needsApproval=e.needsApproval),e.onCompact!==void 0&&(r.onCompact=e.onCompact),r}export{toPublicToolDefinition};
@@ -1 +1 @@
1
- import{executeBashOnSandbox}from"#execution/sandbox/bash-tool.js";const BASH_INPUT_SCHEMA={additionalProperties:!1,properties:{command:{description:`The shell command to execute.`,type:`string`}},required:[`command`],type:`object`};async function executeBash(e){return executeBashOnSandbox(e)}const BASH_TOOL_DEFINITION={description:`Execute a shell command in the shared workspace environment.`,execute:executeBash,inputSchema:BASH_INPUT_SCHEMA,logicalPath:`ash:framework/bash`,name:`bash`,sourceId:`ash:bash-tool`,sourceKind:`module`};export{BASH_INPUT_SCHEMA,BASH_TOOL_DEFINITION};
1
+ import{requireSandboxSession}from"#execution/sandbox/require-sandbox.js";import{executeBashOnSandbox}from"#execution/sandbox/bash-tool.js";const BASH_INPUT_SCHEMA={additionalProperties:!1,properties:{command:{description:`The shell command to execute.`,type:`string`}},required:[`command`],type:`object`};async function executeBash(e){return executeBashOnSandbox(await requireSandboxSession(),e)}const BASH_TOOL_DEFINITION={description:`Execute a shell command in the shared workspace environment.`,execute:executeBash,inputSchema:BASH_INPUT_SCHEMA,logicalPath:`ash:framework/bash`,name:`bash`,sourceId:`ash:bash-tool`,sourceKind:`module`};export{BASH_INPUT_SCHEMA,BASH_TOOL_DEFINITION};
@@ -1 +1 @@
1
- import{requestCodeModeInterrupt}from"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/host-interrupt.js";import"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/index.js";import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,isCodeModeToolExecutionOptions,readCodeModeConnectionAuthContext,toCodeModeConnectionAuthArgs}from"#runtime/framework-tools/code-mode-connection-auth.js";import{qualifiedConnectionToolName}from"#runtime/framework-tools/connection-tools.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";const logger=createLogger(`framework.connection-search`),ConnectionRegistryKey=new ContextKey(`ash.connectionRegistry`),DiscoveredConnectionToolsKey=new ContextKey(`ash.discoveredConnectionTools`),CONNECTION_SEARCH_TOOL_DEFINITION={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. linear__list_issues) in your next response.`,execute:async(e,t)=>executeConnectionSearch(e,{codeMode:isCodeModeToolExecutionOptions(t),codeModeInterrupt:readCodeModeConnectionAuthContext(t)}),inputSchema:{additionalProperties:!1,properties:{connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`},keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`}},required:[`keywords`],type:`object`},logicalPath:`ash:framework/connection-search`,name:`connection_search`,onCompact({ctx:e}){return e.set(DiscoveredConnectionToolsKey,{byConnection:{}}),{}},sourceId:`ash:connection-search-tool`,sourceKind:`module`};async function executeConnectionSearch(t,r){let i=loadContext(),c=i.get(ConnectionRegistryKey);if(c===void 0)return[];await completePendingAuthorizations(c);let l=t.limit??10,u=tokenize(t.keywords),d=[],f=[],p=t.connection!==void 0&&t.connection!==``?c.getConnections().filter(e=>e.connectionName===t.connection):c.getConnections(),m={...i.get(DiscoveredConnectionToolsKey)?.byConnection},h=[];for(let n of p){if(r?.codeModeInterrupt?.resolution.status===`failed`&&r.codeModeInterrupt.payload.connectionName===n.connectionName){let{resolution:e}=r.codeModeInterrupt;f.push({connection:n.connectionName,description:n.description,error:e.reason,needsAuthorization:e.retryable});continue}let i;try{i=await c.getClient(n.connectionName).getToolMetadata()}catch(i){if(isConnectionAuthorizationRequiredError(i)){let i=resolveInteractiveAuth(c,n.connectionName);if(i&&r?.codeMode===!0&&requestCodeModeInterrupt({args:toCodeModeConnectionAuthArgs(t),connectionName:n.connectionName,kind:CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toolName:`connection_search`}),i){let e=getHookUrl(n.connectionName);if(e){let t=resolveConnectionPrincipal(n.connectionName,i);try{let{challenge:r,state:a}=await i.startAuthorization({callbackUrl:e,connection:{url:n.url??``},principal:t});h.push({name:n.connectionName,challenge:r,hookUrl:e,state:a})}catch(e){logger.warn(`startAuthorization failed`,{connection:n.connectionName,error:e instanceof Error?e:Error(String(e))})}}}f.push({connection:n.connectionName,description:n.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(i)){logger.warn(`connection authorization failed`,{connection:n.connectionName,reason:i.reason,retryable:i.retryable,error:i}),f.push({connection:n.connectionName,description:n.description,error:`Authorization failed for ${n.connectionName}: ${i.message}`});continue}let o=i instanceof Error?i.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:n.connectionName,error:i instanceof Error?i:Error(o)}),f.push({connection:n.connectionName,description:n.description,error:`Failed to load tools for "${n.connectionName}": ${o}`});continue}m[n.connectionName]=i;for(let e of i){let t=scoreMatch(u,e);t>0&&d.push({item:{connection:n.connectionName,description:e.description,inputSchema:e.inputSchema,qualifiedName:qualifiedConnectionToolName(n.connectionName,e.name),tool:e.name},score:t})}}if(i.set(DiscoveredConnectionToolsKey,{byConnection:m}),h.length>0)return requestAuthorization(h);d.sort((e,t)=>t.score-e.score);let g=d.slice(0,l).map(e=>e.item);return g.length>0?[...g,...f]:p.map(e=>f.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}async function completePendingAuthorizations(e){let t=loadContext();for(let n of e.getConnections()){let r=getAuthorizationResult(n.connectionName);if(!r)continue;let a=resolveInteractiveAuth(e,n.connectionName);if(!a)continue;let o=resolveConnectionPrincipal(n.connectionName,a),s=await a.completeAuthorization({callbackUrl:r.hookUrl,connection:{url:n.url??``},principal:o,request:r.callback,state:r.state});writeCachedToken(t,n.connectionName,principalKey(o),s)}}function tokenize(e){return e.toLowerCase().split(/[\s_\-./]+/).filter(e=>e.length>1)}function scoreMatch(e,t){let n=tokenize(t.name),r=tokenize(t.description),i=0;for(let t of e){for(let e of n)(e.includes(t)||t.includes(e))&&(i+=3);for(let e of r)(e.includes(t)||t.includes(e))&&(i+=1)}return i}function resolveInteractiveAuth(e,t){let n=e.getConnections().find(e=>e.connectionName===t);if(n?.authorization&&supportsInteractiveAuthorization(n.authorization))return n.authorization}export{CONNECTION_SEARCH_TOOL_DEFINITION,ConnectionRegistryKey,DiscoveredConnectionToolsKey,executeConnectionSearch,scoreMatch,tokenize};
1
+ import{requestCodeModeInterrupt}from"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/host-interrupt.js";import"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/index.js";import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,isCodeModeToolExecutionOptions,readCodeModeConnectionAuthContext,toCodeModeConnectionAuthArgs}from"#runtime/framework-tools/code-mode-connection-auth.js";import{qualifiedConnectionToolName}from"#runtime/framework-tools/connection-tools.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";const logger=createLogger(`framework.connection-search`),ConnectionRegistryKey=new ContextKey(`ash.connectionRegistry`),DiscoveredConnectionToolsKey=new ContextKey(`ash.discoveredConnectionTools`),CONNECTION_SEARCH_TOOL_DEFINITION={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. linear__list_issues) in your next response.`,execute:async(e,t)=>executeConnectionSearch(e,{codeMode:isCodeModeToolExecutionOptions(t),codeModeInterrupt:readCodeModeConnectionAuthContext(t)}),inputSchema:{additionalProperties:!1,properties:{connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`},keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`}},required:[`keywords`],type:`object`},logicalPath:`ash:framework/connection-search`,name:`connection_search`,onCompact(){return loadContext().set(DiscoveredConnectionToolsKey,{byConnection:{}}),{}},sourceId:`ash:connection-search-tool`,sourceKind:`module`};async function executeConnectionSearch(t,r){let i=loadContext(),c=i.get(ConnectionRegistryKey);if(c===void 0)return[];await completePendingAuthorizations(c);let l=t.limit??10,u=tokenize(t.keywords),d=[],f=[],p=t.connection!==void 0&&t.connection!==``?c.getConnections().filter(e=>e.connectionName===t.connection):c.getConnections(),m={...i.get(DiscoveredConnectionToolsKey)?.byConnection},h=[];for(let n of p){if(r?.codeModeInterrupt?.resolution.status===`failed`&&r.codeModeInterrupt.payload.connectionName===n.connectionName){let{resolution:e}=r.codeModeInterrupt;f.push({connection:n.connectionName,description:n.description,error:e.reason,needsAuthorization:e.retryable});continue}let i;try{i=await c.getClient(n.connectionName).getToolMetadata()}catch(i){if(isConnectionAuthorizationRequiredError(i)){let i=resolveInteractiveAuth(c,n.connectionName);if(i&&r?.codeMode===!0&&requestCodeModeInterrupt({args:toCodeModeConnectionAuthArgs(t),connectionName:n.connectionName,kind:CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toolName:`connection_search`}),i){let e=getHookUrl(n.connectionName);if(e){let t=resolveConnectionPrincipal(n.connectionName,i);try{let{challenge:r,state:a}=await i.startAuthorization({callbackUrl:e,connection:{url:n.url??``},principal:t});h.push({name:n.connectionName,challenge:r,hookUrl:e,state:a})}catch(e){logger.warn(`startAuthorization failed`,{connection:n.connectionName,error:e instanceof Error?e:Error(String(e))})}}}f.push({connection:n.connectionName,description:n.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(i)){logger.warn(`connection authorization failed`,{connection:n.connectionName,reason:i.reason,retryable:i.retryable,error:i}),f.push({connection:n.connectionName,description:n.description,error:`Authorization failed for ${n.connectionName}: ${i.message}`});continue}let o=i instanceof Error?i.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:n.connectionName,error:i instanceof Error?i:Error(o)}),f.push({connection:n.connectionName,description:n.description,error:`Failed to load tools for "${n.connectionName}": ${o}`});continue}m[n.connectionName]=i;for(let e of i){let t=scoreMatch(u,e);t>0&&d.push({item:{connection:n.connectionName,description:e.description,inputSchema:e.inputSchema,qualifiedName:qualifiedConnectionToolName(n.connectionName,e.name),tool:e.name},score:t})}}if(i.set(DiscoveredConnectionToolsKey,{byConnection:m}),h.length>0)return requestAuthorization(h);d.sort((e,t)=>t.score-e.score);let g=d.slice(0,l).map(e=>e.item);return g.length>0?[...g,...f]:p.map(e=>f.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}async function completePendingAuthorizations(e){let t=loadContext();for(let n of e.getConnections()){let r=getAuthorizationResult(n.connectionName);if(!r)continue;let a=resolveInteractiveAuth(e,n.connectionName);if(!a)continue;let o=resolveConnectionPrincipal(n.connectionName,a),s=await a.completeAuthorization({callbackUrl:r.hookUrl,connection:{url:n.url??``},principal:o,request:r.callback,state:r.state});writeCachedToken(t,n.connectionName,principalKey(o),s)}}function tokenize(e){return e.toLowerCase().split(/[\s_\-./]+/).filter(e=>e.length>1)}function scoreMatch(e,t){let n=tokenize(t.name),r=tokenize(t.description),i=0;for(let t of e){for(let e of n)(e.includes(t)||t.includes(e))&&(i+=3);for(let e of r)(e.includes(t)||t.includes(e))&&(i+=1)}return i}function resolveInteractiveAuth(e,t){let n=e.getConnections().find(e=>e.connectionName===t);if(n?.authorization&&supportsInteractiveAuthorization(n.authorization))return n.authorization}export{CONNECTION_SEARCH_TOOL_DEFINITION,ConnectionRegistryKey,DiscoveredConnectionToolsKey,executeConnectionSearch,scoreMatch,tokenize};
@@ -1 +1 @@
1
- import{requestCodeModeInterrupt}from"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/host-interrupt.js";import"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.9_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/index.js";import{isObject}from"#shared/guards.js";import{loadContext}from"#context/container.js";import"#runtime/framework-tools/connection-search.js";import{jsonSchema}from"ai";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toCodeModeConnectionAuthArgs}from"#runtime/framework-tools/code-mode-connection-auth.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";function qualifiedConnectionToolName(e,t){return`${e}__${t}`}async function resolveConnectionToolsFromState(e,n,r){let i={};for(let[a,o]of Object.entries(n.byConnection)){let n=r.authMode===`code-mode`&&r.codeModeMetadataOnlyConnectionNames?.has(a)===!0,s=n?void 0:await e.getClient(a).getTools(),c=e.getConnectionApproval(a);for(let l of o){let o=qualifiedConnectionToolName(a,l.name);if(r.existingToolNames?.has(o))continue;let u=s?.[l.name]??(n?createMetadataOnlyTool(l,o):void 0);if(u===void 0)continue;let d=!n&&c!==void 0?async e=>c({approvedTools:r.approvedTools??new Set,toolInput:isObject(e)?e:void 0,toolName:o}):void 0,f=e.getConnections().find(e=>e.connectionName===a),p=u.execute,m=r.authMode===`code-mode`?wrapCodeModeConnectionToolExecute({connectionDefinition:f,connectionName:a,originalExecute:p,toolName:l.name}):wrapConnectionToolExecute({connectionDefinition:f,connectionName:a,originalExecute:p,toolName:l.name});i[o]={...u,execute:m,needsApproval:d}}}return i}function createMetadataOnlyTool(e,t){return{description:e.description,execute:async()=>{throw Error(`Connection tool "${t}" cannot execute without authorization.`)},inputSchema:jsonSchema(e.inputSchema)}}function wrapCodeModeConnectionToolExecute(t){let{connectionDefinition:r,connectionName:a,originalExecute:o,toolName:m}=t;if(o===void 0)return;let h=r?.authorization&&supportsInteractiveAuthorization(r.authorization)?r.authorization:void 0,g=r?.url??``;return async(t,r)=>{if(h){let e=getAuthorizationResult(a);if(e){let t=loadContext(),r=resolveConnectionPrincipal(a,h),i=await h.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:g},principal:r,request:e.callback,state:e.state});writeCachedToken(t,a,principalKey(r),i)}}try{return await o(t,r)}catch(n){if(!isConnectionAuthorizationRequiredError(n)||!h)throw n;requestCodeModeInterrupt({args:toCodeModeConnectionAuthArgs(t),connectionName:a,kind:CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toolName:m})}}}function wrapConnectionToolExecute(e){let{connectionDefinition:t,connectionName:r,originalExecute:s}=e;if(s===void 0)return;let c=t?.authorization&&supportsInteractiveAuthorization(t.authorization)?t.authorization:void 0,m=t?.url??``;return async(e,t)=>{if(c){let e=getAuthorizationResult(r);if(e){let t=loadContext(),i=resolveConnectionPrincipal(r,c),a=await c.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:m},principal:i,request:e.callback,state:e.state});writeCachedToken(t,r,principalKey(i),a)}}try{return await s(e,t)}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!c)throw e;let t=getHookUrl(r);if(!t)throw e;let n=resolveConnectionPrincipal(r,c),{challenge:i,state:s}=await c.startAuthorization({callbackUrl:t,connection:{url:m},principal:n});return requestAuthorization([{name:r,challenge:i,hookUrl:t,state:s}])}}}export{qualifiedConnectionToolName,resolveConnectionToolsFromState,wrapCodeModeConnectionToolExecute,wrapConnectionToolExecute};
1
+ import{requestCodeModeInterrupt}from"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/host-interrupt.js";import"../../node_modules/.pnpm/experimental-ai-sdk-code-mode@1.0.10_ai@7.0.0-canary.154_zod@4.4.3_/node_modules/experimental-ai-sdk-code-mode/dist/index.js";import{isObject}from"#shared/guards.js";import{loadContext}from"#context/container.js";import"#runtime/framework-tools/connection-search.js";import{jsonSchema}from"ai";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toCodeModeConnectionAuthArgs}from"#runtime/framework-tools/code-mode-connection-auth.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";function qualifiedConnectionToolName(e,t){return`${e}__${t}`}async function resolveConnectionToolsFromState(e,n,r){let i={};for(let[a,o]of Object.entries(n.byConnection)){let n=r.authMode===`code-mode`&&r.codeModeMetadataOnlyConnectionNames?.has(a)===!0,s=n?void 0:await e.getClient(a).getTools(),c=e.getConnectionApproval(a);for(let l of o){let o=qualifiedConnectionToolName(a,l.name);if(r.existingToolNames?.has(o))continue;let u=s?.[l.name]??(n?createMetadataOnlyTool(l,o):void 0);if(u===void 0)continue;let d=!n&&c!==void 0?async e=>c({approvedTools:r.approvedTools??new Set,toolInput:isObject(e)?e:void 0,toolName:o}):void 0,f=e.getConnections().find(e=>e.connectionName===a),p=u.execute,m=r.authMode===`code-mode`?wrapCodeModeConnectionToolExecute({connectionDefinition:f,connectionName:a,originalExecute:p,toolName:l.name}):wrapConnectionToolExecute({connectionDefinition:f,connectionName:a,originalExecute:p,toolName:l.name});i[o]={...u,execute:m,needsApproval:d}}}return i}function createMetadataOnlyTool(e,t){return{description:e.description,execute:async()=>{throw Error(`Connection tool "${t}" cannot execute without authorization.`)},inputSchema:jsonSchema(e.inputSchema)}}function wrapCodeModeConnectionToolExecute(t){let{connectionDefinition:r,connectionName:a,originalExecute:o,toolName:m}=t;if(o===void 0)return;let h=r?.authorization&&supportsInteractiveAuthorization(r.authorization)?r.authorization:void 0,g=r?.url??``;return async(t,r)=>{if(h){let e=getAuthorizationResult(a);if(e){let t=loadContext(),r=resolveConnectionPrincipal(a,h),i=await h.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:g},principal:r,request:e.callback,state:e.state});writeCachedToken(t,a,principalKey(r),i)}}try{return await o(t,r)}catch(n){if(!isConnectionAuthorizationRequiredError(n)||!h)throw n;requestCodeModeInterrupt({args:toCodeModeConnectionAuthArgs(t),connectionName:a,kind:CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND,toolName:m})}}}function wrapConnectionToolExecute(e){let{connectionDefinition:t,connectionName:r,originalExecute:s}=e;if(s===void 0)return;let c=t?.authorization&&supportsInteractiveAuthorization(t.authorization)?t.authorization:void 0,m=t?.url??``;return async(e,t)=>{if(c){let e=getAuthorizationResult(r);if(e){let t=loadContext(),i=resolveConnectionPrincipal(r,c),a=await c.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:m},principal:i,request:e.callback,state:e.state});writeCachedToken(t,r,principalKey(i),a)}}try{return await s(e,t)}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!c)throw e;let t=getHookUrl(r);if(!t)throw e;let n=resolveConnectionPrincipal(r,c),{challenge:i,state:s}=await c.startAuthorization({callbackUrl:t,connection:{url:m},principal:n});return requestAuthorization([{name:r,challenge:i,hookUrl:t,state:s}])}}}export{qualifiedConnectionToolName,resolveConnectionToolsFromState,wrapCodeModeConnectionToolExecute,wrapConnectionToolExecute};
@@ -1,4 +1,4 @@
1
- import type { AshContext } from "#context/container.js";
1
+ import { type AshContext } from "#context/container.js";
2
2
  import { ContextKey } from "#context/key.js";
3
3
  /**
4
4
  * Per-file fingerprint stored after a successful `read_file` call. Used by
@@ -59,4 +59,4 @@ export declare function setReadFileStamp(ctx: AshContext, targetKey: string, sta
59
59
  * tool's `onCompact` hook and by authored `defineReadFileTool()` replacements
60
60
  * that keep the default compaction behavior.
61
61
  */
62
- export declare function clearReadFileState(ctx: AshContext): void;
62
+ export declare function clearReadFileState(): void;
@@ -1 +1 @@
1
- import{posix}from"node:path";import{createHash}from"node:crypto";import{ContextKey}from"#context/key.js";const ReadFileStateKey=new ContextKey(`ash.readFile`);function normalizeModelPath(t){return posix.normalize(t)}function buildReadFileTargetKey(e){return e}function createReadFileStamp(e){let n=createHash(`sha256`).update(e.content,`utf8`).digest(`hex`);return{byteLength:Buffer.byteLength(e.content,`utf8`),contentHash:n,filePath:e.filePath}}function setReadFileStamp(e,t,n){let r=e.ensure(ReadFileStateKey,()=>({byTarget:{}}));e.set(ReadFileStateKey,{byTarget:{...r.byTarget,[t]:n}})}function clearReadFileState(e){e.set(ReadFileStateKey,{byTarget:{}})}export{ReadFileStateKey,buildReadFileTargetKey,clearReadFileState,createReadFileStamp,normalizeModelPath,setReadFileStamp};
1
+ import{posix}from"node:path";import{createHash}from"node:crypto";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";const ReadFileStateKey=new ContextKey(`ash.readFile`);function normalizeModelPath(t){return posix.normalize(t)}function buildReadFileTargetKey(e){return e}function createReadFileStamp(e){let n=createHash(`sha256`).update(e.content,`utf8`).digest(`hex`);return{byteLength:Buffer.byteLength(e.content,`utf8`),contentHash:n,filePath:e.filePath}}function setReadFileStamp(e,t,n){let r=e.ensure(ReadFileStateKey,()=>({byTarget:{}}));e.set(ReadFileStateKey,{byTarget:{...r.byTarget,[t]:n}})}function clearReadFileState(){loadContext().set(ReadFileStateKey,{byTarget:{}})}export{ReadFileStateKey,buildReadFileTargetKey,clearReadFileState,createReadFileStamp,normalizeModelPath,setReadFileStamp};
@@ -1,2 +1,2 @@
1
- import{executeGlobOnSandbox}from"#execution/sandbox/glob-tool.js";const GLOB_INPUT_SCHEMA={additionalProperties:!1,properties:{limit:{description:`Maximum number of results to return. Defaults to 100.`,maximum:1e3,minimum:1,type:`integer`},path:{description:`The directory to search in. Defaults to /workspace. Must be an absolute path. Omit to use the default.`,type:`string`},pattern:{description:`The glob pattern to match files against (e.g. "**/*.ts", "src/**/*.js").`,type:`string`}},required:[`pattern`],type:`object`};async function executeGlob(e){return executeGlobOnSandbox(e)}const GLOB_TOOL_DEFINITION={description:[`Fast file pattern matching tool that works with any codebase size.`,``,`Usage:`,`- Supports glob patterns like "**/*.js" or "src/**/*.ts".`,`- Returns matching file paths.`,`- Use this tool when you need to find files by name patterns.`,`- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.`,`- Use the grep tool instead if you need to search file contents.`,`- Call this tool in parallel when you know there are multiple patterns to search for.`].join(`
1
+ import{requireSandboxSession}from"#execution/sandbox/require-sandbox.js";import{executeGlobOnSandbox}from"#execution/sandbox/glob-tool.js";const GLOB_INPUT_SCHEMA={additionalProperties:!1,properties:{limit:{description:`Maximum number of results to return. Defaults to 100.`,maximum:1e3,minimum:1,type:`integer`},path:{description:`The directory to search in. Defaults to /workspace. Must be an absolute path. Omit to use the default.`,type:`string`},pattern:{description:`The glob pattern to match files against (e.g. "**/*.ts", "src/**/*.js").`,type:`string`}},required:[`pattern`],type:`object`};async function executeGlob(e){return executeGlobOnSandbox(await requireSandboxSession(),e)}const GLOB_TOOL_DEFINITION={description:[`Fast file pattern matching tool that works with any codebase size.`,``,`Usage:`,`- Supports glob patterns like "**/*.js" or "src/**/*.ts".`,`- Returns matching file paths.`,`- Use this tool when you need to find files by name patterns.`,`- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.`,`- Use the grep tool instead if you need to search file contents.`,`- Call this tool in parallel when you know there are multiple patterns to search for.`].join(`
2
2
  `),execute:executeGlob,inputSchema:GLOB_INPUT_SCHEMA,logicalPath:`ash:framework/glob`,name:`glob`,sourceId:`ash:glob-tool`,sourceKind:`module`};export{GLOB_INPUT_SCHEMA,GLOB_TOOL_DEFINITION};
@@ -1,2 +1,2 @@
1
- import{executeGrepOnSandbox}from"#execution/sandbox/grep-tool.js";const GREP_INPUT_SCHEMA={additionalProperties:!1,properties:{context:{description:`Number of surrounding context lines to include before and after each match. Defaults to 0.`,minimum:0,type:`integer`},glob:{description:`Filter files by glob pattern (e.g. "*.ts", "*.{ts,tsx}").`,type:`string`},ignoreCase:{description:`Perform case-insensitive search. Defaults to false.`,type:`boolean`},limit:{description:`Maximum number of matches to return per file. Defaults to 100.`,maximum:1e3,minimum:1,type:`integer`},literal:{description:`Treat the pattern as a literal string instead of a regular expression. Defaults to false.`,type:`boolean`},path:{description:`The directory or file to search in. Defaults to /workspace. Must be an absolute path. Omit to use the default.`,type:`string`},pattern:{description:`The regex pattern to search for in file contents (e.g. "log.*Error", "function\\s+\\w+").`,type:`string`}},required:[`pattern`],type:`object`};async function executeGrep(e){return executeGrepOnSandbox(e)}const GREP_TOOL_DEFINITION={description:[`Fast content search tool that works with any codebase size.`,``,`Usage:`,`- Searches file contents using regular expressions.`,`- Supports full regex syntax (e.g. "log.*Error", "function\\s+\\w+").`,`- Filter files by pattern with the glob parameter (e.g. "*.js", "*.{ts,tsx}").`,`- Returns matching lines with file paths and line numbers.`,`- Use this tool when you need to find files containing specific patterns.`,`- Use the glob tool instead if you only need to find files by name.`,`- Call this tool in parallel when you have multiple independent searches.`,`- Any line longer than 2000 characters is truncated.`].join(`
1
+ import{requireSandboxSession}from"#execution/sandbox/require-sandbox.js";import{executeGrepOnSandbox}from"#execution/sandbox/grep-tool.js";const GREP_INPUT_SCHEMA={additionalProperties:!1,properties:{context:{description:`Number of surrounding context lines to include before and after each match. Defaults to 0.`,minimum:0,type:`integer`},glob:{description:`Filter files by glob pattern (e.g. "*.ts", "*.{ts,tsx}").`,type:`string`},ignoreCase:{description:`Perform case-insensitive search. Defaults to false.`,type:`boolean`},limit:{description:`Maximum number of matches to return per file. Defaults to 100.`,maximum:1e3,minimum:1,type:`integer`},literal:{description:`Treat the pattern as a literal string instead of a regular expression. Defaults to false.`,type:`boolean`},path:{description:`The directory or file to search in. Defaults to /workspace. Must be an absolute path. Omit to use the default.`,type:`string`},pattern:{description:`The regex pattern to search for in file contents (e.g. "log.*Error", "function\\s+\\w+").`,type:`string`}},required:[`pattern`],type:`object`};async function executeGrep(e){return executeGrepOnSandbox(await requireSandboxSession(),e)}const GREP_TOOL_DEFINITION={description:[`Fast content search tool that works with any codebase size.`,``,`Usage:`,`- Searches file contents using regular expressions.`,`- Supports full regex syntax (e.g. "log.*Error", "function\\s+\\w+").`,`- Filter files by pattern with the glob parameter (e.g. "*.js", "*.{ts,tsx}").`,`- Returns matching lines with file paths and line numbers.`,`- Use this tool when you need to find files containing specific patterns.`,`- Use the glob tool instead if you only need to find files by name.`,`- Call this tool in parallel when you have multiple independent searches.`,`- Any line longer than 2000 characters is truncated.`].join(`
2
2
  `),execute:executeGrep,inputSchema:GREP_INPUT_SCHEMA,logicalPath:`ash:framework/grep`,name:`grep`,sourceId:`ash:grep-tool`,sourceKind:`module`};export{GREP_INPUT_SCHEMA,GREP_TOOL_DEFINITION};
@@ -1,2 +1,2 @@
1
- import{clearReadFileState}from"#runtime/framework-tools/file-state.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file-tool.js";const READ_FILE_INPUT_SCHEMA={additionalProperties:!1,properties:{filePath:{description:`The absolute path to the file to read.`,type:`string`},limit:{description:`Maximum number of lines to return. Defaults to 2000.`,minimum:1,type:`integer`},offset:{description:`1-based line number to start from. Defaults to 1.`,minimum:1,type:`integer`}},required:[`filePath`],type:`object`};async function executeReadFile(e){return executeReadFileOnSandbox(e)}const READ_FILE_TOOL_DEFINITION={description:[`Read a file from the local filesystem. If the path does not exist, an error is returned.`,``,`Usage:`,`- The filePath parameter should be an absolute path.`,`- By default, this tool returns up to 2000 lines from the start of the file.`,`- The offset parameter is the line number to start from (1-indexed).`,`- To read later sections, call this tool again with a larger offset.`,`- Use the grep tool to find specific content in large files or files with long lines.`,`- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.`,'- Contents are returned with each line prefixed by its line number as `<line>: <content>`. For example, if a file has contents "foo\\n", you will receive "1: foo\\n".',`- Any line longer than 2000 characters is truncated.`,`- Call this tool in parallel when you know there are multiple files you want to read.`,`- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window.`].join(`
2
- `),execute:executeReadFile,inputSchema:READ_FILE_INPUT_SCHEMA,logicalPath:`ash:framework/read-file`,name:`read_file`,onCompact({ctx:t}){return clearReadFileState(t),{}},sourceId:`ash:read-file-tool`,sourceKind:`module`};export{READ_FILE_INPUT_SCHEMA,READ_FILE_TOOL_DEFINITION};
1
+ import{clearReadFileState}from"#runtime/framework-tools/file-state.js";import{requireSandboxSession}from"#execution/sandbox/require-sandbox.js";import{executeReadFileOnSandbox}from"#execution/sandbox/read-file-tool.js";const READ_FILE_INPUT_SCHEMA={additionalProperties:!1,properties:{filePath:{description:`The absolute path to the file to read.`,type:`string`},limit:{description:`Maximum number of lines to return. Defaults to 2000.`,minimum:1,type:`integer`},offset:{description:`1-based line number to start from. Defaults to 1.`,minimum:1,type:`integer`}},required:[`filePath`],type:`object`};async function executeReadFile(e){return executeReadFileOnSandbox(await requireSandboxSession(),e)}const READ_FILE_TOOL_DEFINITION={description:[`Read a file from the local filesystem. If the path does not exist, an error is returned.`,``,`Usage:`,`- The filePath parameter should be an absolute path.`,`- By default, this tool returns up to 2000 lines from the start of the file.`,`- The offset parameter is the line number to start from (1-indexed).`,`- To read later sections, call this tool again with a larger offset.`,`- Use the grep tool to find specific content in large files or files with long lines.`,`- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.`,'- Contents are returned with each line prefixed by its line number as `<line>: <content>`. For example, if a file has contents "foo\\n", you will receive "1: foo\\n".',`- Any line longer than 2000 characters is truncated.`,`- Call this tool in parallel when you know there are multiple files you want to read.`,`- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window.`].join(`
2
+ `),execute:executeReadFile,inputSchema:READ_FILE_INPUT_SCHEMA,logicalPath:`ash:framework/read-file`,name:`read_file`,onCompact(){return clearReadFileState(),{}},sourceId:`ash:read-file-tool`,sourceKind:`module`};export{READ_FILE_INPUT_SCHEMA,READ_FILE_TOOL_DEFINITION};
@@ -1,3 +1,3 @@
1
1
  import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";const TodoStateKey=new ContextKey(`ash.todo`);function formatTodoSummary(e){return e.items.length===0?void 0:`[Your task list was preserved across context compaction]\n${e.items.map(e=>`- [${e.status===`completed`?`x`:e.status===`cancelled`?`-`:` `}] [${e.priority}] ${e.content}`).join(`
2
2
  `)}`}function formatTodoResult(e){let{items:t}=e,n={cancelled:0,completed:0,in_progress:0,pending:0,total:t.length};for(let e of t)n[e.status]++;return{counts:n,todos:t}}function executeTodoTool(t){let r=loadContext(),{todos:i}=t??{};if(i!==void 0){let e={items:[...i]};return r.set(TodoStateKey,e),formatTodoResult(e)}return formatTodoResult(r.ensure(TodoStateKey,()=>({items:[]})))}const TODO_TOOL_DEFINITION={description:[`Use this tool to create and manage a structured task list for the current session.`,`This helps you track progress, organize complex tasks, and demonstrate thoroughness.`,``,`When to use:`,`- Complex multistep tasks requiring 3 or more distinct steps`,`- When the user provides multiple tasks or a numbered list`,`- After receiving new instructions, to capture requirements`,`- After completing a task, to mark it complete and add follow-ups`,``,`When NOT to use:`,`- Single, straightforward tasks that need no tracking`,`- Purely conversational or informational requests`,``,`Usage:`,"- Call with `todos` to replace the entire list (full replacement write)","- Call without `todos` to read the current list",`- Both return the full current list with status counts`,`- Mark tasks in_progress when you start, completed when done`,`- Only have ONE task in_progress at a time`].join(`
3
- `),execute:async e=>executeTodoTool(e??{}),inputSchema:{additionalProperties:!1,properties:{todos:{description:`The updated todo list. Omit to read the current list without modifying it.`,items:{additionalProperties:!1,properties:{content:{description:`Brief description of the task.`,type:`string`},priority:{description:`Priority level of the task.`,enum:[`high`,`medium`,`low`],type:`string`},status:{description:`Current status of the task.`,enum:[`pending`,`in_progress`,`completed`,`cancelled`],type:`string`}},required:[`content`,`status`,`priority`],type:`object`},type:`array`}},type:`object`},logicalPath:`ash:framework/todo`,name:`todo`,onCompact({ctx:e}){let t=e.get(TodoStateKey);if(t===void 0||t.items.length===0)return{};let r=formatTodoSummary(t);return r===void 0?{}:{messages:[{content:r,role:`user`}]}},sourceId:`ash:todo-tool`,sourceKind:`module`};export{TODO_TOOL_DEFINITION,TodoStateKey,executeTodoTool};
3
+ `),execute:async e=>executeTodoTool(e??{}),inputSchema:{additionalProperties:!1,properties:{todos:{description:`The updated todo list. Omit to read the current list without modifying it.`,items:{additionalProperties:!1,properties:{content:{description:`Brief description of the task.`,type:`string`},priority:{description:`Priority level of the task.`,enum:[`high`,`medium`,`low`],type:`string`},status:{description:`Current status of the task.`,enum:[`pending`,`in_progress`,`completed`,`cancelled`],type:`string`}},required:[`content`,`status`,`priority`],type:`object`},type:`array`}},type:`object`},logicalPath:`ash:framework/todo`,name:`todo`,onCompact(){let t=loadContext().get(TodoStateKey);if(t===void 0||t.items.length===0)return{};let r=formatTodoSummary(t);return r===void 0?{}:{messages:[{content:r,role:`user`}]}},sourceId:`ash:todo-tool`,sourceKind:`module`};export{TODO_TOOL_DEFINITION,TodoStateKey,executeTodoTool};
@@ -1,2 +1,2 @@
1
- import{executeWriteFileOnSandbox}from"#execution/sandbox/write-file-tool.js";const WRITE_FILE_INPUT_SCHEMA={additionalProperties:!1,properties:{content:{description:`Complete replacement file contents.`,type:`string`},filePath:{description:`The absolute path to the file to write (must be absolute, not relative).`,type:`string`}},required:[`filePath`,`content`],type:`object`};async function executeWriteFile(e){return executeWriteFileOnSandbox(e)}const WRITE_FILE_TOOL_DEFINITION={description:[`Writes a file to the local filesystem.`,``,`Usage:`,`- This tool will overwrite the existing file if there is one at the provided path.`,`- If this is an existing file, you MUST use the read_file tool first to read the file's contents. This tool will fail if you did not read the file first.`,`- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.`,`- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.`,`- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`].join(`
1
+ import{requireSandboxSession}from"#execution/sandbox/require-sandbox.js";import{executeWriteFileOnSandbox}from"#execution/sandbox/write-file-tool.js";const WRITE_FILE_INPUT_SCHEMA={additionalProperties:!1,properties:{content:{description:`Complete replacement file contents.`,type:`string`},filePath:{description:`The absolute path to the file to write (must be absolute, not relative).`,type:`string`}},required:[`filePath`,`content`],type:`object`};async function executeWriteFile(e){return executeWriteFileOnSandbox(await requireSandboxSession(),e)}const WRITE_FILE_TOOL_DEFINITION={description:[`Writes a file to the local filesystem.`,``,`Usage:`,`- This tool will overwrite the existing file if there is one at the provided path.`,`- If this is an existing file, you MUST use the read_file tool first to read the file's contents. This tool will fail if you did not read the file first.`,`- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.`,`- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.`,`- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`].join(`
2
2
  `),execute:executeWriteFile,inputSchema:WRITE_FILE_INPUT_SCHEMA,logicalPath:`ash:framework/write-file`,name:`write_file`,sourceId:`ash:write-file-tool`,sourceKind:`module`};export{WRITE_FILE_INPUT_SCHEMA,WRITE_FILE_TOOL_DEFINITION};
@@ -7,7 +7,7 @@ import type { ChannelMethod, RouteContext } from "#public/definitions/channel.js
7
7
  import type { RouteHandler } from "#channel/routes.js";
8
8
  import type { OutboundAuthFn } from "#public/agents/auth.js";
9
9
  import type { LifecycleHooks, StreamEventHook } from "#public/definitions/hook.js";
10
- import type { CompactionHookInput, CompactionHookResult, NeedsApprovalContext, ToolModelOutput, ToolRetentionPolicy } from "#public/definitions/tool.js";
10
+ import type { CompactionInput, CompactionHookResult, NeedsApprovalContext, ToolModelOutput, ToolRetentionPolicy } from "#public/definitions/tool.js";
11
11
  import type { AuthorizationDefinition, HeadersDefinition, ToolFilterDefinition } from "#runtime/connections/types.js";
12
12
  import type { CompiledWorkspaceResourceRoot } from "#compiler/manifest.js";
13
13
  import type { WorkspaceRuntimeSpec } from "#runtime/workspace/types.js";
@@ -137,7 +137,7 @@ export type ResolvedToolDefinition = Readonly<Optional<InternalToolDefinitionWit
137
137
  * resolved tool that declares it after the harness compacts message
138
138
  * history. See `packages/ash/src/execution/tool-compaction.ts`.
139
139
  */
140
- readonly onCompact?: (input: CompactionHookInput) => CompactionHookResult | Promise<CompactionHookResult> | void | Promise<void>;
140
+ readonly onCompact?: (input: CompactionInput, ctx: unknown) => CompactionHookResult | Promise<CompactionHookResult> | void | Promise<void>;
141
141
  /**
142
142
  * Optional projection that controls what the model sees as the tool
143
143
  * result. The full `execute` return is still visible to channel event
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "experimental-ash",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "bin": {
5
5
  "ash": "./bin/ash.js",
6
6
  "experimental-ash": "./bin/ash.js"
@@ -172,7 +172,7 @@
172
172
  "access": "public"
173
173
  },
174
174
  "dependencies": {
175
- "experimental-ai-sdk-code-mode": "1.0.9",
175
+ "experimental-ai-sdk-code-mode": "1.0.10",
176
176
  "nitro": "3.0.260522-beta",
177
177
  "quickjs-emscripten": "0.32.0"
178
178
  },