experimental-ash 0.55.3 → 0.56.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 (96) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +202 -0
  3. package/dist/docs/public/meta.json +1 -0
  4. package/dist/docs/public/onboarding.md +7 -5
  5. package/dist/docs/public/tools.mdx +10 -2
  6. package/dist/skills/agent/SKILL.md +169 -0
  7. package/dist/skills/agent/references/deployment.md +35 -0
  8. package/dist/skills/agent/references/getting-started.md +58 -0
  9. package/dist/skills/agent/references/project-layout.md +35 -0
  10. package/dist/skills/agent/references/runtime-model.md +24 -0
  11. package/dist/skills/agent/references/skills.md +26 -0
  12. package/dist/skills/agent/scripts/add-to-existing-project.sh +12 -0
  13. package/dist/skills/agent/scripts/bootstrap-from-npm.sh +9 -0
  14. package/dist/skills/agent/scripts/verify-local-agent.sh +16 -0
  15. package/dist/skills/ash-add-agent/SKILL.md +166 -0
  16. package/dist/skills/ash-add-next/SKILL.md +137 -0
  17. package/dist/skills/framework/SKILL.md +93 -0
  18. package/dist/skills/framework/references/architecture.md +14 -0
  19. package/dist/skills/framework/references/discovery-and-compilation.md +15 -0
  20. package/dist/skills/framework/references/quality-gates.md +13 -0
  21. package/dist/skills/framework/references/runtime-model.md +12 -0
  22. package/dist/skills/framework/references/workspace-and-sandbox.md +25 -0
  23. package/dist/skills/framework/scripts/framework-review-checklist.sh +13 -0
  24. package/dist/skills/framework/scripts/run-framework-gates.sh +8 -0
  25. package/dist/src/client/output-schema.js +1 -1
  26. package/dist/src/compiler/compile-from-memory.d.ts +2 -0
  27. package/dist/src/compiler/compile-from-memory.js +1 -1
  28. package/dist/src/compiler/manifest.d.ts +4 -2
  29. package/dist/src/compiler/manifest.js +1 -1
  30. package/dist/src/compiler/normalize-agent-config.js +1 -1
  31. package/dist/src/compiler/normalize-subagent.js +1 -1
  32. package/dist/src/compiler/normalize-tool.js +1 -1
  33. package/dist/src/context/build-dynamic-tools.js +1 -1
  34. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  35. package/dist/src/context/keys.d.ts +1 -0
  36. package/dist/src/execution/node-step.js +1 -1
  37. package/dist/src/execution/session.js +1 -1
  38. package/dist/src/execution/workflow-entry.js +1 -1
  39. package/dist/src/harness/code-mode.js +1 -1
  40. package/dist/src/harness/execute-tool.d.ts +1 -0
  41. package/dist/src/harness/provider-tools.d.ts +7 -1
  42. package/dist/src/harness/provider-tools.js +1 -1
  43. package/dist/src/harness/tool-loop.js +1 -1
  44. package/dist/src/harness/tools.d.ts +2 -0
  45. package/dist/src/harness/tools.js +1 -1
  46. package/dist/src/internal/application/package.js +1 -1
  47. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  48. package/dist/src/packages/ash-scaffold/src/channels.js +2 -2
  49. package/dist/src/packages/ash-scaffold/src/steps/run-add-to-agent.js +1 -1
  50. package/dist/src/packages/ash-scaffold/src/web-template.js +2 -2
  51. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  52. package/dist/src/public/definitions/tool.d.ts +21 -1
  53. package/dist/src/public/tools/define-bash-tool.js +1 -1
  54. package/dist/src/public/tools/define-glob-tool.js +1 -1
  55. package/dist/src/public/tools/define-grep-tool.js +1 -1
  56. package/dist/src/public/tools/define-read-file-tool.js +1 -1
  57. package/dist/src/public/tools/define-write-file-tool.js +1 -1
  58. package/dist/src/public/tools/internal.js +1 -1
  59. package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
  60. package/dist/src/runtime/connections/authorization-tokens.d.ts +8 -0
  61. package/dist/src/runtime/connections/authorization-tokens.js +1 -1
  62. package/dist/src/runtime/connections/mcp-client.d.ts +14 -0
  63. package/dist/src/runtime/connections/mcp-client.js +1 -1
  64. package/dist/src/runtime/connections/types.d.ts +1 -0
  65. package/dist/src/runtime/framework-tools/ask-question.d.ts +4 -0
  66. package/dist/src/runtime/framework-tools/ask-question.js +1 -1
  67. package/dist/src/runtime/framework-tools/bash.d.ts +5 -0
  68. package/dist/src/runtime/framework-tools/bash.js +1 -1
  69. package/dist/src/runtime/framework-tools/connection-search-dynamic.d.ts +1 -0
  70. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -1
  71. package/dist/src/runtime/framework-tools/final-output.js +1 -1
  72. package/dist/src/runtime/framework-tools/glob.d.ts +5 -0
  73. package/dist/src/runtime/framework-tools/glob.js +2 -2
  74. package/dist/src/runtime/framework-tools/grep.d.ts +5 -0
  75. package/dist/src/runtime/framework-tools/grep.js +2 -2
  76. package/dist/src/runtime/framework-tools/read-file.d.ts +5 -0
  77. package/dist/src/runtime/framework-tools/read-file.js +2 -2
  78. package/dist/src/runtime/framework-tools/skill.d.ts +2 -0
  79. package/dist/src/runtime/framework-tools/skill.js +1 -1
  80. package/dist/src/runtime/framework-tools/todo.d.ts +2 -0
  81. package/dist/src/runtime/framework-tools/todo.js +2 -2
  82. package/dist/src/runtime/framework-tools/web-fetch.d.ts +3 -0
  83. package/dist/src/runtime/framework-tools/web-fetch.js +2 -2
  84. package/dist/src/runtime/framework-tools/web-search.d.ts +17 -0
  85. package/dist/src/runtime/framework-tools/web-search.js +1 -1
  86. package/dist/src/runtime/framework-tools/write-file.d.ts +5 -0
  87. package/dist/src/runtime/framework-tools/write-file.js +2 -2
  88. package/dist/src/runtime/resolve-tool.js +1 -1
  89. package/dist/src/runtime/subagents/registry.js +1 -1
  90. package/dist/src/runtime/tools/registry.js +1 -1
  91. package/dist/src/runtime/types.d.ts +5 -0
  92. package/dist/src/shared/dynamic-tool-definition.d.ts +2 -1
  93. package/dist/src/shared/json-schema.d.ts +3 -1
  94. package/dist/src/shared/json-schema.js +1 -1
  95. package/dist/src/shared/tool-definition.d.ts +10 -2
  96. package/package.json +20 -1
@@ -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,t){return executeBashOnSandbox(await t.getSandbox(),e)},inputSchema:BASH_INPUT_SCHEMA}}export{defineBashTool};
1
+ import{BASH_INPUT_SCHEMA,BASH_OUTPUT_SCHEMA}from"#runtime/framework-tools/bash.js";import{executeBashOnSandbox}from"#execution/sandbox/bash-tool.js";function defineBashTool(n={}){return{description:n.description??`Execute a shell command in the workspace sandbox.`,async execute(e,t){return executeBashOnSandbox(await t.getSandbox(),e)},inputSchema:BASH_INPUT_SCHEMA,outputSchema:BASH_OUTPUT_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,t){return executeGlobOnSandbox(await t.getSandbox(),e)},inputSchema:GLOB_INPUT_SCHEMA}}export{defineGlobTool};
1
+ import{GLOB_INPUT_SCHEMA,GLOB_OUTPUT_SCHEMA}from"#runtime/framework-tools/glob.js";import{executeGlobOnSandbox}from"#execution/sandbox/glob-tool.js";function defineGlobTool(n={}){return{description:n.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,outputSchema:GLOB_OUTPUT_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,t){return executeGrepOnSandbox(await t.getSandbox(),e)},inputSchema:GREP_INPUT_SCHEMA}}export{defineGrepTool};
1
+ import{GREP_INPUT_SCHEMA,GREP_OUTPUT_SCHEMA}from"#runtime/framework-tools/grep.js";import{executeGrepOnSandbox}from"#execution/sandbox/grep-tool.js";function defineGrepTool(n={}){return{description:n.description??`Search file contents by pattern in the workspace sandbox.`,async execute(e,t){return executeGrepOnSandbox(await t.getSandbox(),e)},inputSchema:GREP_INPUT_SCHEMA,outputSchema:GREP_OUTPUT_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??(()=>(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
+ import{clearReadFileState}from"#runtime/framework-tools/file-state.js";import{READ_FILE_INPUT_SCHEMA,READ_FILE_OUTPUT_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,outputSchema:READ_FILE_OUTPUT_SCHEMA}}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,t){return executeWriteFileOnSandbox(await t.getSandbox(),e)},inputSchema:WRITE_FILE_INPUT_SCHEMA}}export{defineWriteFileTool};
1
+ import{WRITE_FILE_INPUT_SCHEMA,WRITE_FILE_OUTPUT_SCHEMA}from"#runtime/framework-tools/write-file.js";import{executeWriteFileOnSandbox}from"#execution/sandbox/write-file-tool.js";function defineWriteFileTool(n={}){return{description:n.description??`Write a file to the workspace sandbox.`,async execute(e,t){return executeWriteFileOnSandbox(await t.getSandbox(),e)},inputSchema:WRITE_FILE_INPUT_SCHEMA,outputSchema:WRITE_FILE_OUTPUT_SCHEMA}}export{defineWriteFileTool};
@@ -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: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
+ 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??{},outputSchema:e.outputSchema};return e.needsApproval!==void 0&&(r.needsApproval=e.needsApproval),e.onCompact!==void 0&&(r.onCompact=e.onCompact),r}export{toPublicToolDefinition};
@@ -1,4 +1,4 @@
1
- import{z}from"#compiled/zod/index.js";import{CODE_MODE_TOOL_NAME}from"#shared/code-mode.js";import{FINAL_OUTPUT_TOOL_NAME}from"#runtime/framework-tools/final-output.js";import{MockLanguageModelV3}from"ai/test";import{BOOTSTRAP_RUNTIME_MODEL_ID,BOOTSTRAP_RUNTIME_SYSTEM_PROMPT}from"#runtime/agent/bootstrap.js";import{createBootstrapGenerateResult,createBootstrapStreamResult,estimateTokenCount,getLastUserPromptText,getPromptContentText,getPromptText}from"#runtime/agent/bootstrap-model-utils.js";import{findRelevantSkill,getActivatedSkillIds,getAvailableSkills}from"#runtime/agent/mock-model-skill-selection.js";import{createJsonSchemaSample}from"#runtime/agent/mock-structured-output.js";import{LOAD_SKILL_TOOL_NAME}from"#runtime/skills/fragment-context.js";const authoredRuntimeModelMocks=new Map,bootstrapWeatherPayloadSchema=z.object({city:z.string(),condition:z.string(),summary:z.string(),temperatureF:z.number().finite()}).strict(),ASH_MOCK_AUTHORED_MODELS_ENV=`ASH_MOCK_AUTHORED_MODELS`;function shouldMockAuthoredRuntimeModels(){return process.env.ASH_MOCK_AUTHORED_MODELS===`1`||process.env.NODE_ENV===`test`}function createMockAuthoredRuntimeModel(e){let t=authoredRuntimeModelMocks.get(e.id);if(t!==void 0)return t;let n=new MockLanguageModelV3({modelId:e.id,provider:`ash-runtime-mock`,doGenerate:async t=>createMockModelResult(t,e.id),doStream:async t=>createBootstrapStreamResult(createMockModelResult(t,e.id))});return authoredRuntimeModelMocks.set(e.id,n),n}function createMockModelResult(e,t){let n=getLastAuthoredToolResult(e.prompt);if(n!==null){let r=createFollowUpToolCallResult({modelId:t,options:e,result:n});if(r!==null)return r}else{let n=createSkillLoadResult(e.prompt,t)??createAuthoredToolCallResult(e,t);if(n!==null)return n}let r=createFinalOutputResult(e,t);if(r!==null)return r;let i=n===null?createAssistantMessage(e.prompt):formatToolResultReply(n,e.prompt);return createBootstrapGenerateResult({inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(i),text:i})}function createFinalOutputResult(e,t){let r=getAvailableTools(e).find(e=>e.name===FINAL_OUTPUT_TOOL_NAME);if(r===void 0)return null;let i=createJsonSchemaSample(r.inputSchema);return createToolCallGenerateResult({input:i,inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(JSON.stringify(i)),toolCallId:createToolCallId(FINAL_OUTPUT_TOOL_NAME),toolName:FINAL_OUTPUT_TOOL_NAME})}function resolveMockAuthoredRuntimeModel(e){return!shouldMockAuthoredRuntimeModels()||e.id===BOOTSTRAP_RUNTIME_MODEL_ID?null:createMockAuthoredRuntimeModel(e)}function createSkillLoadResult(e,t){let n=getLastUserPromptText(e);if(n===null||getActivatedSkillIds(e).length>0)return null;let r=findRelevantSkill(getAvailableSkills(e),n);return r===null?null:createToolCallGenerateResult({input:{skill:r.name},inputTokens:estimateTokenCount(getPromptText(e)),modelId:t,outputTokens:estimateTokenCount(r.name),toolCallId:`call_load_skill`,toolName:LOAD_SKILL_TOOL_NAME})}function createAuthoredToolCallResult(e,n){let r=getLastUserPromptText(e.prompt);if(r===null)return null;let i=findRelevantTool(getAvailableTools(e),r);if(i===null)return null;let a=resolveWeatherCity(r),o=createAuthoredToolInput(i,r,a);if(i.name===CODE_MODE_TOOL_NAME){let t=findRelevantCodeModeHostTool(i.description,r);if(t===null)return null;let o=`return await tools${formatCodeModeToolAccess(t)}({ city: ${JSON.stringify(a)} });`;return createToolCallGenerateResult({input:{js:o},inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:n,outputTokens:estimateTokenCount(o),toolCallId:createToolCallId(i.name),toolName:i.name})}return createToolCallGenerateResult({input:o,inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:n,outputTokens:estimateTokenCount(Object.values(o).join(` `)),toolCallId:createToolCallId(i.name),toolName:i.name})}function createFollowUpToolCallResult(e){let t=findNextExplicitToolAfterResult({previousToolName:e.result.toolName,prompt:e.options.prompt,tools:getAvailableTools(e.options)});if(t===null)return null;let n=createFollowUpToolInput(e.result.output);return n===null?null:createToolCallGenerateResult({input:n,inputTokens:estimateTokenCount(getPromptText(e.options.prompt)),modelId:e.modelId,outputTokens:estimateTokenCount(Object.values(n).join(` `)),toolCallId:createToolCallId(t.name),toolName:t.name})}function createAuthoredToolInput(e,t,n){let r=getToolInputPropertyNames(e.inputSchema);return r.includes(`topic`)||/\btopic\b/u.test(normalizeText(t))?{topic:resolveLookupTopic(t)}:r.length===1&&r[0]===`message`?{message:t}:{city:n}}function createAssistantMessage(e){let t=getLastUserPromptText(e)??`Hello from Ash`,n=getSystemPromptLabels(e),r=resolveSystemProbe(e);return n.length>0?r===null?`Bootstrap reply [${n.join(`, `)}]: ${t}`:`Bootstrap reply [${n.join(`, `)}; probe=${r}]: ${t}`:r===null?`Bootstrap reply: ${t}`:`Bootstrap reply [probe=${r}]: ${t}`}function formatToolResultReply(e,t){if(e.isError)return`Local weather tool failed: ${formatToolOutput(e.output)}`;if(isWeatherPayload(e.output))return`Used local weather tool for ${e.output.city}: ${e.output.condition}, ${e.output.temperatureF}F. ${e.output.summary}`;let n=getLastUserPromptText(t)??`Hello from Ash`;return`Used ${e.toolName} for "${n}": ${formatToolOutput(e.output)}`}function createToolCallGenerateResult(e){return{content:[{input:JSON.stringify(e.input),toolCallId:e.toolCallId,toolName:e.toolName,type:`tool-call`}],finishReason:{raw:void 0,unified:`tool-calls`},response:{id:`bootstrap-response`,modelId:e.modelId,timestamp:new Date(`2026-03-16T00:00:00.000Z`)},usage:{inputTokens:{cacheRead:0,cacheWrite:0,noCache:e.inputTokens,total:e.inputTokens},outputTokens:{reasoning:0,text:e.outputTokens,total:e.outputTokens}},warnings:[]}}function getAvailableTools(e){return(e.tools??[]).flatMap(e=>e.type===`function`?[{description:e.description,inputSchema:`inputSchema`in e?e.inputSchema:void 0,name:e.name}]:[])}function getLastAuthoredToolResult(e){for(let t of[...e].reverse()){if(t.role===`user`)return null;if(!(t.role!==`tool`&&t.role!==`assistant`)){for(let e of[...t.content].reverse())if(!(typeof e==`string`||e.type!==`tool-result`)&&e.toolName!==LOAD_SKILL_TOOL_NAME)return{isError:e.output.type===`error-json`||e.output.type===`error-text`||e.output.type===`execution-denied`,output:e.output.type===`execution-denied`?{reason:e.output.reason??null,type:e.output.type}:e.output.value,toolCallId:e.toolCallId,toolName:e.toolName}}}return null}function findNextExplicitToolAfterResult(e){let t=getLastUserPromptText(e.prompt);if(t===null)return null;let n=normalizeText(t),r=n.indexOf(normalizeText(e.previousToolName));return r<0?null:e.tools.filter(t=>t.name!==e.previousToolName).flatMap(e=>{let t=n.indexOf(normalizeText(e.name),r+1);return t<0?[]:[{index:t,tool:e}]}).sort((e,t)=>e.index-t.index)[0]?.tool??null}function createFollowUpToolInput(e){return isRecord(e)&&typeof e.stepKey==`string`?{stepKey:e.stepKey}:null}function getSystemPromptLabels(e){let t=e.filter(e=>e.role===`system`);if(t.length===0)return[];let n=t.flatMap(e=>{let t=getPromptContentText(e.content);if(t.startsWith(`Available skills
1
+ import{z}from"#compiled/zod/index.js";import{CODE_MODE_TOOL_NAME}from"#shared/code-mode.js";import{FINAL_OUTPUT_TOOL_NAME}from"#runtime/framework-tools/final-output.js";import{MockLanguageModelV3}from"ai/test";import{BOOTSTRAP_RUNTIME_MODEL_ID,BOOTSTRAP_RUNTIME_SYSTEM_PROMPT}from"#runtime/agent/bootstrap.js";import{createBootstrapGenerateResult,createBootstrapStreamResult,estimateTokenCount,getLastUserPromptText,getPromptContentText,getPromptText}from"#runtime/agent/bootstrap-model-utils.js";import{findRelevantSkill,getActivatedSkillIds,getAvailableSkills}from"#runtime/agent/mock-model-skill-selection.js";import{createJsonSchemaSample}from"#runtime/agent/mock-structured-output.js";import{LOAD_SKILL_TOOL_NAME}from"#runtime/skills/fragment-context.js";const authoredRuntimeModelMocks=new Map,bootstrapWeatherPayloadSchema=z.object({city:z.string(),condition:z.string(),summary:z.string(),temperatureF:z.number().finite()}).strict(),ASH_MOCK_AUTHORED_MODELS_ENV=`ASH_MOCK_AUTHORED_MODELS`;function shouldMockAuthoredRuntimeModels(){return process.env.ASH_MOCK_AUTHORED_MODELS===`1`||process.env.NODE_ENV===`test`}function createMockAuthoredRuntimeModel(e){let t=authoredRuntimeModelMocks.get(e.id);if(t!==void 0)return t;let n=new MockLanguageModelV3({modelId:e.id,provider:`ash-runtime-mock`,doGenerate:async t=>createMockModelResult(t,e.id),doStream:async t=>createBootstrapStreamResult(createMockModelResult(t,e.id))});return authoredRuntimeModelMocks.set(e.id,n),n}function createMockModelResult(e,t){let n=getLastAuthoredToolResult(e.prompt);if(n!==null){let r=createFollowUpToolCallResult({modelId:t,options:e,result:n});if(r!==null)return r}else{let n=createSkillLoadResult(e.prompt,t)??createAuthoredToolCallResult(e,t);if(n!==null)return n}let r=createFinalOutputResult(e,t);if(r!==null)return r;let i=n===null?createAssistantMessage(e.prompt):formatToolResultReply(n,e.prompt);return createBootstrapGenerateResult({inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(i),text:i})}function createFinalOutputResult(e,t){let r=getAvailableTools(e).find(e=>e.name===FINAL_OUTPUT_TOOL_NAME);if(r===void 0)return null;let i=createJsonSchemaSample(r.inputSchema);return createToolCallGenerateResult({input:i,inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(JSON.stringify(i)),toolCallId:createToolCallId(FINAL_OUTPUT_TOOL_NAME),toolName:FINAL_OUTPUT_TOOL_NAME})}function resolveMockAuthoredRuntimeModel(e){return!shouldMockAuthoredRuntimeModels()||e.id===BOOTSTRAP_RUNTIME_MODEL_ID?null:createMockAuthoredRuntimeModel(e)}function createSkillLoadResult(e,t){let n=getLastUserPromptText(e);if(n===null||getActivatedSkillIds(e).length>0)return null;let r=findRelevantSkill(getAvailableSkills(e),n);return r===null?null:createToolCallGenerateResult({input:{skill:r.name},inputTokens:estimateTokenCount(getPromptText(e)),modelId:t,outputTokens:estimateTokenCount(r.name),toolCallId:`call_load_skill`,toolName:LOAD_SKILL_TOOL_NAME})}function createAuthoredToolCallResult(e,n){let r=getLastUserPromptText(e.prompt);if(r===null)return null;let i=findRelevantTool(getAvailableTools(e),r);if(i===null)return null;let a=resolveWeatherCity(r),o=createAuthoredToolInput(i,r,a);if(i.name===CODE_MODE_TOOL_NAME){let t=findRelevantCodeModeHostTool(i.description,r);if(t===null)return null;let o=`return await tools${formatCodeModeToolAccess(t)}({ city: ${JSON.stringify(a)} });`;return createToolCallGenerateResult({input:{js:o},inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:n,outputTokens:estimateTokenCount(o),toolCallId:createToolCallId(i.name),toolName:i.name})}return createToolCallGenerateResult({input:o,inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:n,outputTokens:estimateTokenCount(Object.values(o).join(` `)),toolCallId:createToolCallId(i.name),toolName:i.name})}function createFollowUpToolCallResult(e){let t=findNextExplicitToolAfterResult({previousToolName:e.result.toolName,prompt:e.options.prompt,tools:getAvailableTools(e.options)});if(t===null)return null;let n=createFollowUpToolInput(e.result.output);return n===null?null:createToolCallGenerateResult({input:n,inputTokens:estimateTokenCount(getPromptText(e.options.prompt)),modelId:e.modelId,outputTokens:estimateTokenCount(Object.values(n).join(` `)),toolCallId:createToolCallId(t.name),toolName:t.name})}function createAuthoredToolInput(e,t,n){let r=getToolInputPropertyNames(e.inputSchema);return r.includes(`topic`)||/\btopic\b/u.test(normalizeText(t))?{topic:resolveLookupTopic(t)}:r.length===1&&r[0]===`message`?{message:t}:{city:n}}function createAssistantMessage(e){let t=getLastUserPromptText(e)??`Hello from Ash`,n=getSystemPromptLabels(e),r=resolveSystemProbe(e);return n.length>0?r===null?`Bootstrap reply [${n.join(`, `)}]: ${t}`:`Bootstrap reply [${n.join(`, `)}; probe=${r}]: ${t}`:r===null?`Bootstrap reply: ${t}`:`Bootstrap reply [probe=${r}]: ${t}`}function formatToolResultReply(e,t){if(e.isError)return`Local weather tool failed: ${formatToolOutput(e.output)}`;if(isWeatherPayload(e.output))return`Used local weather tool for ${e.output.city}: ${e.output.condition}, ${e.output.temperatureF}F. ${e.output.summary}`;let n=getLastUserPromptText(t)??`Hello from Ash`;return`Used ${e.toolName} for "${n}": ${formatToolOutput(e.output)}`}function createToolCallGenerateResult(e){return{content:[{input:JSON.stringify(e.input),toolCallId:e.toolCallId,toolName:e.toolName,type:`tool-call`}],finishReason:{raw:void 0,unified:`tool-calls`},response:{id:`bootstrap-response`,modelId:e.modelId,timestamp:new Date(`2026-03-16T00:00:00.000Z`)},usage:{inputTokens:{cacheRead:0,cacheWrite:0,noCache:e.inputTokens,total:e.inputTokens},outputTokens:{reasoning:0,text:e.outputTokens,total:e.outputTokens}},warnings:[]}}function getAvailableTools(e){return(e.tools??[]).flatMap(e=>e.type===`function`?[{description:e.description,inputSchema:`inputSchema`in e?e.inputSchema:void 0,name:e.name,outputSchema:`outputSchema`in e?e.outputSchema:void 0}]:[])}function getLastAuthoredToolResult(e){for(let t of[...e].reverse()){if(t.role===`user`)return null;if(!(t.role!==`tool`&&t.role!==`assistant`)){for(let e of[...t.content].reverse())if(!(typeof e==`string`||e.type!==`tool-result`)&&e.toolName!==LOAD_SKILL_TOOL_NAME)return{isError:e.output.type===`error-json`||e.output.type===`error-text`||e.output.type===`execution-denied`,output:e.output.type===`execution-denied`?{reason:e.output.reason??null,type:e.output.type}:e.output.value,toolCallId:e.toolCallId,toolName:e.toolName}}}return null}function findNextExplicitToolAfterResult(e){let t=getLastUserPromptText(e.prompt);if(t===null)return null;let n=normalizeText(t),r=n.indexOf(normalizeText(e.previousToolName));return r<0?null:e.tools.filter(t=>t.name!==e.previousToolName).flatMap(e=>{let t=n.indexOf(normalizeText(e.name),r+1);return t<0?[]:[{index:t,tool:e}]}).sort((e,t)=>e.index-t.index)[0]?.tool??null}function createFollowUpToolInput(e){return isRecord(e)&&typeof e.stepKey==`string`?{stepKey:e.stepKey}:null}function getSystemPromptLabels(e){let t=e.filter(e=>e.role===`system`);if(t.length===0)return[];let n=t.flatMap(e=>{let t=getPromptContentText(e.content);if(t.startsWith(`Available skills
2
2
  `))return[];let n=t.split(`
3
3
  `).map(e=>e.trim()).filter(e=>e.length>0),r=[];for(let e of n){if(e===BOOTSTRAP_RUNTIME_SYSTEM_PROMPT||e===`Available skills`)continue;let t=/^System \((.+)\)$/.exec(e);if(t?.[1]){r.push(t[1]);continue}let n=/^Skill \((.+)\)$/.exec(e);n?.[1]&&r.push(n[1])}if(r.length>0)return r;let i=n.find(e=>e!==BOOTSTRAP_RUNTIME_SYSTEM_PROMPT&&e!==`Available skills`);return i===void 0?[]:[i]});return[...new Set(n)]}function getToolInputPropertyNames(e){return!isRecord(e)||!isRecord(e.properties)?[]:Object.keys(e.properties)}function findRelevantTool(e,t){let n=normalizeText(t),r=e.find(e=>n.includes(normalizeText(e.name)));return r===void 0?/\b(forecast|temperature|weather|wind|rain|snow)\b/u.test(n)?e.find(e=>/\b(forecast|temperature|weather|wind|rain|snow)\b/u.test(normalizeText(`${e.name} ${e.description??``}`)))??null:null:r}function findRelevantCodeModeHostTool(e,t){return e===void 0?null:findRelevantTool(parseCodeModeHostTools(e),t)?.name??null}function parseCodeModeHostTools(e){let t=[],n;for(let r of e.split(`
4
4
  `)){let e=/^\s*\/\*\*\s*(.*?)\s*\*\/\s*$/u.exec(r);if(e?.[1]!==void 0){n=e[1];continue}let i=/^\s*(?:([$A-Z_a-z][$\w]*)|(["'])(.*?)\2)\s*:\s*\(input:/u.exec(r),a=i?.[1]??i?.[3];a!==void 0&&(t.push({description:n,name:a}),n=void 0)}return t}function formatCodeModeToolAccess(e){return/^[$A-Z_a-z][$\w]*$/u.test(e)?`.${e}`:`[${JSON.stringify(e)}]`}function normalizeText(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,` `).trim()}function createToolCallId(e){return`call_${e.toLowerCase().replace(/[^a-z0-9]+/gu,`_`).replace(/^_+|_+$/gu,``)||`tool`}`}function resolveSystemProbe(e){let t=e.filter(e=>e.role===`system`).map(e=>getPromptContentText(e.content)).join(`
@@ -41,3 +41,11 @@ export declare function readCachedToken(ctx: AlsContext, connectionName: string,
41
41
  * into the durable step payload. See the module docblock.
42
42
  */
43
43
  export declare function writeCachedToken(ctx: AlsContext, connectionName: string, principalKey: string, token: TokenResult): void;
44
+ /**
45
+ * Drops the cached {@link TokenResult} for `(connectionName, principalKey)`,
46
+ * if present. Used when the remote server rejects an already-resolved
47
+ * bearer (HTTP 401) so the subsequent re-authorization attempt does not
48
+ * re-read the stale token from the per-step cache. No-op when nothing is
49
+ * cached for the principal.
50
+ */
51
+ export declare function evictCachedToken(ctx: AlsContext, connectionName: string, principalKey: string): void;
@@ -1 +1 @@
1
- import{ContextKey}from"#context/key.js";const ConnectionAuthorizationTokensKey=new ContextKey(`ash.connectionAuthorizationTokens`);function readCachedToken(e,t,n){let r=e.get(ConnectionAuthorizationTokensKey)?.[t]?.[n];if(r!==void 0&&!(r.expiresAt!==void 0&&r.expiresAt<=Date.now()))return r}function writeCachedToken(e,t,n,r){let i=e.get(ConnectionAuthorizationTokensKey)??{},a=i[t]??{};asContainer(e).setVirtualContext(ConnectionAuthorizationTokensKey,{...i,[t]:{...a,[n]:r}})}function asContainer(e){return e}export{ConnectionAuthorizationTokensKey,readCachedToken,writeCachedToken};
1
+ import{ContextKey}from"#context/key.js";const ConnectionAuthorizationTokensKey=new ContextKey(`ash.connectionAuthorizationTokens`);function readCachedToken(e,t,n){let r=e.get(ConnectionAuthorizationTokensKey)?.[t]?.[n];if(r!==void 0&&!(r.expiresAt!==void 0&&r.expiresAt<=Date.now()))return r}function writeCachedToken(e,t,n,r){let i=e.get(ConnectionAuthorizationTokensKey)??{},a=i[t]??{};asContainer(e).setVirtualContext(ConnectionAuthorizationTokensKey,{...i,[t]:{...a,[n]:r}})}function evictCachedToken(e,t,n){let r=e.get(ConnectionAuthorizationTokensKey),i=r?.[t];if(r===void 0||i===void 0||i[n]===void 0)return;let{[n]:a,...o}=i;asContainer(e).setVirtualContext(ConnectionAuthorizationTokensKey,{...r,[t]:o})}function asContainer(e){return e}export{ConnectionAuthorizationTokensKey,evictCachedToken,readCachedToken,writeCachedToken};
@@ -38,10 +38,24 @@ export declare class McpConnectionClient implements ConnectionClient {
38
38
  /**
39
39
  * Executes a named tool through the AI SDK's tool executor, which
40
40
  * handles the JSON-RPC `tools/call` internally.
41
+ *
42
+ * A `401`/`invalid_token` from the remote server is translated into
43
+ * {@link ConnectionAuthorizationRequiredError} via {@link #rethrowClassified}
44
+ * so callers re-enter the authorization flow instead of surfacing an
45
+ * opaque transport error.
41
46
  */
42
47
  executeTool(toolName: string, args: unknown): Promise<unknown>;
43
48
  close(): Promise<void>;
44
49
  }
50
+ /**
51
+ * Returns `true` when an error from the MCP transport indicates the
52
+ * bearer was rejected by the remote server — an HTTP `401`. Per
53
+ * RFC 6750 a `401` means the access token is missing, expired, or
54
+ * revoked, all of which are recoverable by re-authorizing. (A `403`
55
+ * is an insufficient-scope / permission problem and is intentionally
56
+ * left to propagate, since re-running the same grant would not help.)
57
+ */
58
+ export declare function isMcpAuthRequiredError(error: unknown): boolean;
45
59
  /**
46
60
  * Returns `true` when a tool name passes the configured filter.
47
61
  */
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{contextStorage}from"#context/container.js";import{createMCPClient}from"#compiled/@ai-sdk/mcp/index.js";import{readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";var McpConnectionClient=class{#e;#t;#n;#r;#i;constructor(e){this.#i=e}async connect(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#a();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#a(){let e=await resolveHeaders(this.#i),t=this.#i.url;try{return await createMCPClient({transport:{type:`http`,url:t,headers:e}})}catch(r){if(!isMcpHttpFallbackRetryableError(r))throw r;return await createMCPClient({transport:{type:`sse`,url:t,headers:e}})}}async getToolMetadata(){return(await this.#o()).metadata}async getTools(){return(await this.#o()).tools}async executeTool(e,t){let{tools:n}=await this.#o(),r=n[e];if(r?.execute===void 0)throw Error(`Tool "${e}" not found in connection "${this.#i.connectionName}".`);return r.execute(t,{})}async#o(){if(this.#r!==void 0)return this.#r;if(this.#n!==void 0)return this.#n;this.#n=this.#s();try{return this.#r=await this.#n,this.#r}catch(e){throw this.#n=void 0,e}}async#s(){let e=await this.connect(),t=await e.listTools(),n=this.#i.tools,r=n===void 0?t.tools:t.tools.filter(e=>passesToolFilter(e.name,n)),i=e.toolsFromDefinitions({tools:r});return{metadata:r.map(e=>({annotations:e.annotations,description:e.description??``,inputSchema:e.inputSchema??{},name:e.name})),tools:i}}async close(){this.#t!==void 0&&(await this.#t.close(),this.#t=void 0),this.#e=void 0,this.#n=void 0,this.#r=void 0}};function isMcpHttpFallbackRetryableError(e){let t=readHttpStatus(e);return t===400||t===404||t===405}function readHttpStatus(t){for(let n of walkErrorChain(t)){if(!isObject(n))continue;let t=readStatusField(n);if(t!==void 0)return t;let r=n.response;if(isObject(r)){let e=readStatusField(r);if(e!==void 0)return e}if(typeof n.message==`string`){let e=/\bHTTP\s+(\d{3})\b/u.exec(n.message);if(e?.[1]!==void 0)return Number(e[1])}}}function readStatusField(e){if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode}function*walkErrorChain(t){let n=t,r=new Set;for(;n!=null&&!r.has(n);){if(r.add(n),yield n,!isObject(n)||!(`cause`in n))return;n=n.cause}}function passesToolFilter(e,t){return t===void 0?!0:`allow`in t?t.allow.includes(e):!t.block.includes(e)}async function resolveHeaders(e){let t={};if(e.authorization!==void 0&&(t.Authorization=`Bearer ${(await resolveToken(e)).token}`),e.headers!==void 0){let n=await resolveHeadersDefinition(e.headers);for(let[r,i]of Object.entries(n)){if(e.authorization!==void 0&&r.toLowerCase()===`authorization`)throw Error(`Connection "${e.connectionName}" headers must not include an "Authorization" key when "authorization" is also provided.`);t[r]=i}}return t}async function resolveToken(e){if(e.authorization===void 0)throw Error(`Connection "${e.connectionName}" does not define authorization.`);let n=contextStorage.getStore(),a=resolveConnectionPrincipal(e.connectionName,e.authorization,n),o={url:e.url};if(n===void 0)return await e.authorization.getToken({principal:a,connection:o});let s=principalKey(a),c=readCachedToken(n,e.connectionName,s);if(c!==void 0)return c;let l=await e.authorization.getToken({principal:a,connection:o});return writeCachedToken(n,e.connectionName,s,l),l}async function resolveHeadersDefinition(e){if(typeof e==`function`)return await e();let t={},n=Object.entries(e);for(let[e,r]of n)t[e]=await resolveHeaderValue(r);return t}async function resolveHeaderValue(e){return typeof e==`function`?await e():await e}export{McpConnectionClient,passesToolFilter,resolveHeaders};
1
+ import{isObject}from"#shared/guards.js";import{contextStorage}from"#context/container.js";import{ConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{createMCPClient}from"#compiled/@ai-sdk/mcp/index.js";import{evictCachedToken,readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";var McpConnectionClient=class{#e;#t;#n;#r;#i;constructor(e){this.#i=e}async connect(){if(this.#t!==void 0)return this.#t;if(this.#e!==void 0)return this.#e;this.#e=this.#a();try{return this.#t=await this.#e,this.#t}catch(e){throw this.#e=void 0,e}}async#a(){let e=await resolveHeaders(this.#i),t=this.#i.url;try{return await createMCPClient({transport:{type:`http`,url:t,headers:e}})}catch(n){if(!isMcpHttpFallbackRetryableError(n))throw n;return await createMCPClient({transport:{type:`sse`,url:t,headers:e}})}}async getToolMetadata(){return(await this.#o()).metadata}async getTools(){return(await this.#o()).tools}async executeTool(e,t){try{let{tools:n}=await this.#o(),r=n[e];if(r?.execute===void 0)throw Error(`Tool "${e}" not found in connection "${this.#i.connectionName}".`);return await r.execute(t,{})}catch(e){return await this.#l(e)}}async#o(){if(this.#r!==void 0)return this.#r;if(this.#n!==void 0)return this.#n;this.#n=this.#s();try{return this.#r=await this.#n,this.#r}catch(e){throw this.#n=void 0,e}}async#s(){try{return await this.#c()}catch(e){return await this.#l(e)}}async#c(){let e=await this.connect(),t=await e.listTools(),n=this.#i.tools,r=n===void 0?t.tools:t.tools.filter(e=>passesToolFilter(e.name,n)),i=e.toolsFromDefinitions({tools:r});return{metadata:r.map(e=>({annotations:e.annotations,description:e.description??``,inputSchema:e.inputSchema??{},name:e.name,outputSchema:`outputSchema`in e&&e.outputSchema!==void 0?e.outputSchema:void 0})),tools:i}}async close(){this.#t!==void 0&&(await this.#t.close(),this.#t=void 0),this.#e=void 0,this.#n=void 0,this.#r=void 0}async#l(e){throw isMcpAuthRequiredError(e)?(this.#u(),await this.close(),new ConnectionAuthorizationRequiredError(this.#i.connectionName,{message:`Connection "${this.#i.connectionName}" requires authorization (the server rejected the token).`})):e}#u(){let e=this.#i.authorization;if(e===void 0)return;let n=contextStorage.getStore();if(n!==void 0)try{let t=resolveConnectionPrincipal(this.#i.connectionName,e,n);evictCachedToken(n,this.#i.connectionName,principalKey(t))}catch{}}};function isMcpAuthRequiredError(e){return readHttpStatus(e)===401}function isMcpHttpFallbackRetryableError(e){let t=readHttpStatus(e);return t===400||t===404||t===405}function readHttpStatus(t){for(let n of walkErrorChain(t)){if(!isObject(n))continue;let t=readStatusField(n);if(t!==void 0)return t;let r=n.response;if(isObject(r)){let e=readStatusField(r);if(e!==void 0)return e}if(typeof n.message==`string`){let e=/\bHTTP\s+(\d{3})\b/u.exec(n.message);if(e?.[1]!==void 0)return Number(e[1])}}}function readStatusField(e){if(typeof e.status==`number`)return e.status;if(typeof e.statusCode==`number`)return e.statusCode}function*walkErrorChain(t){let n=t,r=new Set;for(;n!=null&&!r.has(n);){if(r.add(n),yield n,!isObject(n)||!(`cause`in n))return;n=n.cause}}function passesToolFilter(e,t){return t===void 0?!0:`allow`in t?t.allow.includes(e):!t.block.includes(e)}async function resolveHeaders(e){let t={};if(e.authorization!==void 0&&(t.Authorization=`Bearer ${(await resolveToken(e)).token}`),e.headers!==void 0){let n=await resolveHeadersDefinition(e.headers);for(let[r,i]of Object.entries(n)){if(e.authorization!==void 0&&r.toLowerCase()===`authorization`)throw Error(`Connection "${e.connectionName}" headers must not include an "Authorization" key when "authorization" is also provided.`);t[r]=i}}return t}async function resolveToken(e){if(e.authorization===void 0)throw Error(`Connection "${e.connectionName}" does not define authorization.`);let n=contextStorage.getStore(),r=resolveConnectionPrincipal(e.connectionName,e.authorization,n),i={url:e.url};if(n===void 0)return await e.authorization.getToken({principal:r,connection:i});let a=principalKey(r),o=readCachedToken(n,e.connectionName,a);if(o!==void 0)return o;let s=await e.authorization.getToken({principal:r,connection:i});return writeCachedToken(n,e.connectionName,a,s),s}async function resolveHeadersDefinition(e){if(typeof e==`function`)return await e();let t={},n=Object.entries(e);for(let[e,r]of n)t[e]=await resolveHeaderValue(r);return t}async function resolveHeaderValue(e){return typeof e==`function`?await e():await e}export{McpConnectionClient,isMcpAuthRequiredError,passesToolFilter,resolveHeaders};
@@ -290,6 +290,7 @@ export interface ConnectionToolMetadata {
290
290
  readonly description: string;
291
291
  readonly inputSchema: Record<string, unknown>;
292
292
  readonly name: string;
293
+ readonly outputSchema?: Record<string, unknown>;
293
294
  }
294
295
  /** A live client for a single connection. */
295
296
  export interface ConnectionClient {
@@ -8,6 +8,10 @@ export declare const ASK_QUESTION_TOOL_NAME = "ask_question";
8
8
  * Shared input schema used by the framework `ask_question` tool.
9
9
  */
10
10
  export declare const ASK_QUESTION_INPUT_SCHEMA: JsonObject;
11
+ /**
12
+ * Shared output schema used by the framework `ask_question` tool.
13
+ */
14
+ export declare const ASK_QUESTION_OUTPUT_SCHEMA: JsonObject;
11
15
  /**
12
16
  * Root-only framework tool that lets the agent request structured user input.
13
17
  *
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{inputRequestSchema}from"#runtime/input/types.js";const ASK_QUESTION_TOOL_NAME=`ask_question`,askQuestionToolInputSchema=inputRequestSchema.omit({action:!0,display:!0,requestId:!0}),{$schema:_jsonSchemaVersion,...askQuestionInputSchema}=z.toJSONSchema(askQuestionToolInputSchema),ASK_QUESTION_INPUT_SCHEMA=askQuestionInputSchema,ASK_QUESTION_TOOL_DEFINITION={description:`Ask the user a question and wait for their response before continuing. Use this when you need clarification or a choice from the user.`,inputSchema:ASK_QUESTION_INPUT_SCHEMA,logicalPath:`ash:framework/ask-question`,name:ASK_QUESTION_TOOL_NAME,sourceId:`ash:ask-question-tool`,sourceKind:`module`};export{ASK_QUESTION_INPUT_SCHEMA,ASK_QUESTION_TOOL_DEFINITION,ASK_QUESTION_TOOL_NAME};
1
+ import{z}from"#compiled/zod/index.js";import{inputRequestSchema}from"#runtime/input/types.js";const ASK_QUESTION_TOOL_NAME=`ask_question`,askQuestionToolInputSchema=inputRequestSchema.omit({action:!0,display:!0,requestId:!0}),{$schema:_jsonSchemaVersion,...askQuestionInputSchema}=z.toJSONSchema(askQuestionToolInputSchema),askQuestionToolOutputSchema=z.object({optionId:z.string().optional(),status:z.enum([`answered`,`ignored`]),text:z.string().optional()}).strict(),{$schema:_outputJsonSchemaVersion,...askQuestionOutputSchema}=z.toJSONSchema(askQuestionToolOutputSchema),ASK_QUESTION_INPUT_SCHEMA=askQuestionInputSchema,ASK_QUESTION_OUTPUT_SCHEMA=askQuestionOutputSchema,ASK_QUESTION_TOOL_DEFINITION={description:`Ask the user a question and wait for their response before continuing. Use this when you need clarification or a choice from the user.`,inputSchema:ASK_QUESTION_INPUT_SCHEMA,logicalPath:`ash:framework/ask-question`,name:ASK_QUESTION_TOOL_NAME,outputSchema:ASK_QUESTION_OUTPUT_SCHEMA,sourceId:`ash:ask-question-tool`,sourceKind:`module`};export{ASK_QUESTION_INPUT_SCHEMA,ASK_QUESTION_OUTPUT_SCHEMA,ASK_QUESTION_TOOL_DEFINITION,ASK_QUESTION_TOOL_NAME};
@@ -9,4 +9,9 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
9
9
  * input contracts in sync without duplication.
10
10
  */
11
11
  export declare const BASH_INPUT_SCHEMA: JsonObject;
12
+ /**
13
+ * Shared output schema used by the framework `bash` tool and any author tool
14
+ * constructed via {@link defineBashTool}.
15
+ */
16
+ export declare const BASH_OUTPUT_SCHEMA: JsonObject;
12
17
  export declare const BASH_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1 +1 @@
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
+ 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`},BASH_OUTPUT_SCHEMA={additionalProperties:!1,properties:{exitCode:{type:`number`},stderr:{type:`string`},stdout:{type:`string`},truncated:{type:`boolean`}},required:[`exitCode`,`stderr`,`stdout`,`truncated`],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`,outputSchema:BASH_OUTPUT_SCHEMA,sourceId:`ash:bash-tool`,sourceKind:`module`};export{BASH_INPUT_SCHEMA,BASH_OUTPUT_SCHEMA,BASH_TOOL_DEFINITION};
@@ -7,6 +7,7 @@ interface ConnectionSearchResultItem {
7
7
  readonly error?: string;
8
8
  readonly inputSchema?: Record<string, unknown>;
9
9
  readonly needsAuthorization?: boolean;
10
+ readonly outputSchema?: Record<string, unknown>;
10
11
  readonly tool?: string;
11
12
  readonly qualifiedName?: string;
12
13
  }
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{ConnectionRegistryKey}from"#context/providers/connection.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";const logger=createLogger(`framework.connection-search-dynamic`),ConnectionSearchResultsKey=new ContextKey(`ash.connectionSearchResults`);function qualifiedConnectionToolName(e,t){return`${e}__${t}`}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}async function completePendingAuthorizations(e){let n=loadContext();for(let t of e.getConnections()){let r=getAuthorizationResult(t.connectionName);if(!r)continue;let a=resolveInteractiveAuth(e,t.connectionName);if(!a)continue;let o=resolveConnectionPrincipal(t.connectionName,a),s=await a.completeAuthorization({callbackUrl:r.hookUrl,connection:{url:t.url??``},principal:o,request:r.callback,state:r.state});writeCachedToken(n,t.connectionName,principalKey(o),s)}}async function executeConnectionSearch(e){let n=loadContext(),i=n.get(ConnectionRegistryKey);if(i===void 0)return[];await completePendingAuthorizations(i);let s=e.limit??10,l=tokenize(e.keywords),u=[],p=[],m=e.connection!==void 0&&e.connection!==``?i.getConnections().filter(t=>t.connectionName===e.connection):i.getConnections(),h=[];for(let e of m){let t;try{t=await i.getClient(e.connectionName).getToolMetadata()}catch(t){if(isConnectionAuthorizationRequiredError(t)){let t=resolveInteractiveAuth(i,e.connectionName);if(t){let n=getHookUrl(e.connectionName);if(n){let r=resolveConnectionPrincipal(e.connectionName,t);try{let{challenge:i,state:a}=await t.startAuthorization({callbackUrl:n,connection:{url:e.url??``},principal:r});h.push({name:e.connectionName,challenge:i,hookUrl:n,state:a})}catch(t){logger.warn(`startAuthorization failed`,{connection:e.connectionName,error:t instanceof Error?t:Error(String(t))})}}}p.push({connection:e.connectionName,description:e.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(t)){logger.warn(`connection authorization failed`,{connection:e.connectionName,reason:t.reason,retryable:t.retryable,error:t}),p.push({connection:e.connectionName,description:e.description,error:`Authorization failed for ${e.connectionName}: ${t.message}`});continue}let n=t instanceof Error?t.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:e.connectionName,error:t instanceof Error?t:Error(n)}),p.push({connection:e.connectionName,description:e.description,error:`Failed to load tools for "${e.connectionName}": ${n}`});continue}for(let n of t){let t=scoreMatch(l,n);t>0&&u.push({item:{connection:e.connectionName,description:n.description,inputSchema:n.inputSchema,qualifiedName:`connection__${qualifiedConnectionToolName(e.connectionName,n.name)}`,tool:n.name},score:t})}}if(h.length>0)return requestAuthorization(h);u.sort((e,t)=>t.score-e.score);let g=u.slice(0,s).map(e=>e.item);if(g.length>0){let e=[...g,...p],t=n.get(ConnectionSearchResultsKey)??[],r=new Map(t.map(e=>[e.qualifiedName,e]));for(let e of g)e.qualifiedName&&r.set(e.qualifiedName,e);return n.set(ConnectionSearchResultsKey,[...r.values()]),e}return m.map(e=>p.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}function extractDiscoveredTools(e){let t=new Map;for(let n of e){if(n.role!==`tool`)continue;let e=n.content;for(let n of e){if(n.type!==`tool-result`||n.toolName!==`connection__search`)continue;let e=n.output;if(e==null)continue;let r=typeof e==`object`&&`type`in e&&`value`in e?e.value:e;if(Array.isArray(r))for(let e of r)e.tool&&e.qualifiedName&&t.set(e.qualifiedName,e)}}return[...t.values()]}function createConnectionSearchEvents(){return{"step.started":async(e,n)=>{let c=loadContext().get(ConnectionRegistryKey);if(!c||c.getConnections().length===0)return null;let d=c.getConnections().map(e=>e.connectionName),p=extractDiscoveredTools(n.messages),m=loadContext().get(ConnectionSearchResultsKey)??[],h=new Map;for(let e of m)e.qualifiedName&&h.set(e.qualifiedName,e);for(let e of p)e.qualifiedName&&h.set(e.qualifiedName,e);let g=[...h.values()],_={};_.search={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. \`connection__linear__list_issues\`) in your next response. Available connections: ${d.join(`, `)}.`,inputSchema:{type:`object`,additionalProperties:!1,properties:{keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`},connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`}},required:[`keywords`]},async execute(e){return executeConnectionSearch(e)}};for(let e of g){let n=e.connection,d=e.tool,f=c.getConnectionApproval(n);_[qualifiedConnectionToolName(n,d)]={description:e.description,inputSchema:e.inputSchema??{type:`object`},needsApproval:f,async execute(e){let c=loadContext().get(ConnectionRegistryKey),f=c.getConnections().find(e=>e.connectionName===n),p=f?.authorization&&supportsInteractiveAuthorization(f.authorization)?f.authorization:void 0;if(p){let e=getAuthorizationResult(n);if(e){let r=loadContext(),i=resolveConnectionPrincipal(n,p),a=await p.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:f?.url??``},principal:i,request:e.callback,state:e.state});writeCachedToken(r,n,principalKey(i),a)}}try{let t=(await c.getClient(n).getTools())[d];if(!t?.execute)throw Error(`Connection tool "${qualifiedConnectionToolName(n,d)}" has no execute function.`);return t.execute(e,{})}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!p)throw e;let t=getHookUrl(n);if(!t)throw e;let r=resolveConnectionPrincipal(n,p),{challenge:i,state:s}=await p.startAuthorization({callbackUrl:t,connection:{url:f?.url??``},principal:r});return requestAuthorization([{name:n,challenge:i,hookUrl:t,state:s}])}}}}return _}}}function createConnectionSearchResolver(){let e=createConnectionSearchEvents();return{slug:`connection`,eventNames:Object.keys(e),events:e,sourceId:`ash:connection-search-dynamic`,sourceKind:`module`,logicalPath:`ash:framework/connection-search-dynamic`}}export{createConnectionSearchEvents,createConnectionSearchResolver,extractDiscoveredTools};
1
+ import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{ConnectionRegistryKey}from"#context/providers/connection.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{ConnectionAuthorizationFailedError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";const logger=createLogger(`framework.connection-search-dynamic`),CONNECTION_SEARCH_OUTPUT_SCHEMA={items:{additionalProperties:!1,properties:{connection:{type:`string`},description:{type:`string`},error:{type:`string`},inputSchema:{type:`object`},needsAuthorization:{type:`boolean`},outputSchema:{type:`object`},qualifiedName:{type:`string`},tool:{type:`string`}},required:[`connection`,`description`],type:`object`},type:`array`},ConnectionSearchResultsKey=new ContextKey(`ash.connectionSearchResults`);function qualifiedConnectionToolName(e,t){return`${e}__${t}`}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}async function completePendingAuthorizations(e){let n=loadContext(),r=new Set;for(let t of e.getConnections()){let a=getAuthorizationResult(t.connectionName);if(!a)continue;let o=resolveInteractiveAuth(e,t.connectionName);if(!o)continue;let s=resolveConnectionPrincipal(t.connectionName,o),c=await o.completeAuthorization({callbackUrl:a.hookUrl,connection:{url:t.url??``},principal:s,request:a.callback,state:a.state});writeCachedToken(n,t.connectionName,principalKey(s),c),r.add(t.connectionName)}return r}async function executeConnectionSearch(e){let n=loadContext(),i=n.get(ConnectionRegistryKey);if(i===void 0)return[];let s=await completePendingAuthorizations(i),c=e.limit??10,u=tokenize(e.keywords),d=[],p=[],h=e.connection!==void 0&&e.connection!==``?i.getConnections().filter(t=>t.connectionName===e.connection):i.getConnections(),g=[];for(let e of h){let t;try{t=await i.getClient(e.connectionName).getToolMetadata()}catch(t){if(isConnectionAuthorizationRequiredError(t)){if(s.has(e.connectionName)){logger.warn(`connection still unauthorized after authorization`,{connection:e.connectionName}),p.push({connection:e.connectionName,description:e.description,error:`Authorization for "${e.connectionName}" did not take effect; the token was rejected after sign-in.`});continue}let t=resolveInteractiveAuth(i,e.connectionName);if(t){let n=getHookUrl(e.connectionName);if(n){let r=resolveConnectionPrincipal(e.connectionName,t);try{let{challenge:i,state:a}=await t.startAuthorization({callbackUrl:n,connection:{url:e.url??``},principal:r});g.push({name:e.connectionName,challenge:i,hookUrl:n,state:a})}catch(t){logger.warn(`startAuthorization failed`,{connection:e.connectionName,error:t instanceof Error?t:Error(String(t))})}}}p.push({connection:e.connectionName,description:e.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(t)){logger.warn(`connection authorization failed`,{connection:e.connectionName,reason:t.reason,retryable:t.retryable,error:t}),p.push({connection:e.connectionName,description:e.description,error:`Authorization failed for ${e.connectionName}: ${t.message}`});continue}let n=t instanceof Error?t.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:e.connectionName,error:t instanceof Error?t:Error(n)}),p.push({connection:e.connectionName,description:e.description,error:`Failed to load tools for "${e.connectionName}": ${n}`});continue}for(let n of t){let t=scoreMatch(u,n);t>0&&d.push({item:{connection:e.connectionName,description:n.description,inputSchema:n.inputSchema,outputSchema:n.outputSchema,qualifiedName:`connection__${qualifiedConnectionToolName(e.connectionName,n.name)}`,tool:n.name},score:t})}}if(g.length>0)return requestAuthorization(g);d.sort((e,t)=>t.score-e.score);let _=d.slice(0,c).map(e=>e.item);if(_.length>0){let e=[..._,...p],t=n.get(ConnectionSearchResultsKey)??[],r=new Map(t.map(e=>[e.qualifiedName,e]));for(let e of _)e.qualifiedName&&r.set(e.qualifiedName,e);return n.set(ConnectionSearchResultsKey,[...r.values()]),e}return h.map(e=>p.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}function extractDiscoveredTools(e){let t=new Map;for(let n of e){if(n.role!==`tool`)continue;let e=n.content;for(let n of e){if(n.type!==`tool-result`||n.toolName!==`connection__search`)continue;let e=n.output;if(e==null)continue;let r=typeof e==`object`&&`type`in e&&`value`in e?e.value:e;if(Array.isArray(r))for(let e of r)e.tool&&e.qualifiedName&&t.set(e.qualifiedName,e)}}return[...t.values()]}function createConnectionSearchEvents(){return{"step.started":async(e,n)=>{let l=loadContext().get(ConnectionRegistryKey);if(!l||l.getConnections().length===0)return null;let f=l.getConnections().map(e=>e.connectionName),h=extractDiscoveredTools(n.messages),g=loadContext().get(ConnectionSearchResultsKey)??[],_=new Map;for(let e of g)e.qualifiedName&&_.set(e.qualifiedName,e);for(let e of h)e.qualifiedName&&_.set(e.qualifiedName,e);let v=[..._.values()],y={};y.search={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. \`connection__linear__list_issues\`) in your next response. Available connections: ${f.join(`, `)}.`,inputSchema:{type:`object`,additionalProperties:!1,properties:{keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`},connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`}},required:[`keywords`]},async execute(e){return executeConnectionSearch(e)},outputSchema:CONNECTION_SEARCH_OUTPUT_SCHEMA};for(let e of v){let n=e.connection,f=e.tool,p=l.getConnectionApproval(n);y[qualifiedConnectionToolName(n,f)]={description:e.description,inputSchema:e.inputSchema??{type:`object`},needsApproval:p,outputSchema:e.outputSchema,async execute(e){let l=loadContext().get(ConnectionRegistryKey),p=l.getConnections().find(e=>e.connectionName===n),m=p?.authorization&&supportsInteractiveAuthorization(p.authorization)?p.authorization:void 0,h=!1;if(m){let e=getAuthorizationResult(n);if(e){h=!0;let r=loadContext(),i=resolveConnectionPrincipal(n,m),a=await m.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:p?.url??``},principal:i,request:e.callback,state:e.state});writeCachedToken(r,n,principalKey(i),a)}}try{return await l.getClient(n).executeTool(f,e)}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!m)throw e;if(h)throw new ConnectionAuthorizationFailedError(n,{retryable:!1,reason:`token_rejected_after_authorization`,message:`Connection "${n}" rejected the token immediately after authorization.`});let t=getHookUrl(n);if(!t)throw e;let r=resolveConnectionPrincipal(n,m),{challenge:i,state:s}=await m.startAuthorization({callbackUrl:t,connection:{url:p?.url??``},principal:r});return requestAuthorization([{name:n,challenge:i,hookUrl:t,state:s}])}}}}return y}}}function createConnectionSearchResolver(){let e=createConnectionSearchEvents();return{slug:`connection`,eventNames:Object.keys(e),events:e,sourceId:`ash:connection-search-dynamic`,sourceKind:`module`,logicalPath:`ash:framework/connection-search-dynamic`}}export{createConnectionSearchEvents,createConnectionSearchResolver,extractDiscoveredTools};
@@ -1 +1 @@
1
- import{jsonSchema}from"ai";const FINAL_OUTPUT_TOOL_NAME=`final_output`;function buildFinalOutputTool(e){return{description:`Deliver your final answer in the required structure by calling this tool. Call it exactly once, when you are done; do not answer in prose.`,inputSchema:jsonSchema(e)}}export{FINAL_OUTPUT_TOOL_NAME,buildFinalOutputTool};
1
+ import{jsonSchema}from"ai";const FINAL_OUTPUT_TOOL_NAME=`final_output`;function buildFinalOutputTool(e){return{description:`Deliver your final answer in the required structure by calling this tool. Call it exactly once, when you are done; do not answer in prose.`,inputSchema:jsonSchema(e),outputSchema:jsonSchema(e)}}export{FINAL_OUTPUT_TOOL_NAME,buildFinalOutputTool};
@@ -9,4 +9,9 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
9
9
  * input contracts in sync without duplication.
10
10
  */
11
11
  export declare const GLOB_INPUT_SCHEMA: JsonObject;
12
+ /**
13
+ * Shared output schema used by the framework `glob` tool and any author tool
14
+ * constructed via {@link defineGlobTool}.
15
+ */
16
+ export declare const GLOB_OUTPUT_SCHEMA: JsonObject;
12
17
  export declare const GLOB_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1,2 +1,2 @@
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
- `),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
+ 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`},GLOB_OUTPUT_SCHEMA={additionalProperties:!1,properties:{content:{type:`string`},count:{type:`integer`},path:{type:`string`},truncated:{type:`boolean`}},required:[`content`,`count`,`path`,`truncated`],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
+ `),execute:executeGlob,inputSchema:GLOB_INPUT_SCHEMA,logicalPath:`ash:framework/glob`,name:`glob`,outputSchema:GLOB_OUTPUT_SCHEMA,sourceId:`ash:glob-tool`,sourceKind:`module`};export{GLOB_INPUT_SCHEMA,GLOB_OUTPUT_SCHEMA,GLOB_TOOL_DEFINITION};
@@ -9,4 +9,9 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
9
9
  * input contracts in sync without duplication.
10
10
  */
11
11
  export declare const GREP_INPUT_SCHEMA: JsonObject;
12
+ /**
13
+ * Shared output schema used by the framework `grep` tool and any author tool
14
+ * constructed via {@link defineGrepTool}.
15
+ */
16
+ export declare const GREP_OUTPUT_SCHEMA: JsonObject;
12
17
  export declare const GREP_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1,2 +1,2 @@
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
- `),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
+ 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`},GREP_OUTPUT_SCHEMA={additionalProperties:!1,properties:{content:{type:`string`},matchCount:{type:`integer`},path:{type:`string`},truncated:{type:`boolean`}},required:[`content`,`matchCount`,`path`,`truncated`],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
+ `),execute:executeGrep,inputSchema:GREP_INPUT_SCHEMA,logicalPath:`ash:framework/grep`,name:`grep`,outputSchema:GREP_OUTPUT_SCHEMA,sourceId:`ash:grep-tool`,sourceKind:`module`};export{GREP_INPUT_SCHEMA,GREP_OUTPUT_SCHEMA,GREP_TOOL_DEFINITION};
@@ -9,4 +9,9 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
9
9
  * model input contracts in sync without duplication.
10
10
  */
11
11
  export declare const READ_FILE_INPUT_SCHEMA: JsonObject;
12
+ /**
13
+ * Shared output schema used by the framework `read_file` tool and any author
14
+ * tool constructed via {@link defineReadFileTool}.
15
+ */
16
+ export declare const READ_FILE_OUTPUT_SCHEMA: JsonObject;
12
17
  export declare const READ_FILE_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1,2 +1,2 @@
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
+ 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`},READ_FILE_OUTPUT_SCHEMA={additionalProperties:!1,properties:{content:{type:`string`},nextOffset:{minimum:1,type:`integer`},path:{type:`string`},totalLines:{minimum:0,type:`integer`},truncated:{type:`boolean`}},required:[`content`,`path`,`totalLines`,`truncated`],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(),{}},outputSchema:READ_FILE_OUTPUT_SCHEMA,sourceId:`ash:read-file-tool`,sourceKind:`module`};export{READ_FILE_INPUT_SCHEMA,READ_FILE_OUTPUT_SCHEMA,READ_FILE_TOOL_DEFINITION};
@@ -1,2 +1,4 @@
1
1
  import type { ResolvedToolDefinition } from "#runtime/types.js";
2
+ import type { JsonObject } from "#shared/json.js";
3
+ export declare const SKILL_OUTPUT_SCHEMA: JsonObject;
2
4
  export declare const SKILL_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1 +1 @@
1
- import{SandboxKey}from"#context/keys.js";import{loadContext}from"#context/container.js";import{loadSkillFromSandbox}from"#runtime/skills/sandbox-access.js";async function executeLoadSkillTool(t){let n=loadContext().get(SandboxKey);if(n===void 0)throw Error(`The load_skill tool requires sandbox access on the runtime context. Ensure the step is running inside a managed runtime context with sandbox support.`);let{skill:r}=t;return await loadSkillFromSandbox(n,r)}const SKILL_TOOL_DEFINITION={description:[`Load the full instructions for one available skill by name or id.`,`Use this tool when the request clearly matches a listed skill description or when the user explicitly asks for that skill.`,`Loading adds the skill instructions to the current turn.`,`Choose the "skill" value from the Available skills block.`].join(` `),execute:e=>executeLoadSkillTool(e),inputSchema:{additionalProperties:!1,properties:{skill:{description:`Available skill name or id.`,type:`string`}},required:[`skill`],type:`object`},logicalPath:`ash:framework/load-skill`,name:`load_skill`,sourceId:`ash:load-skill-tool`,sourceKind:`module`};export{SKILL_TOOL_DEFINITION};
1
+ import{SandboxKey}from"#context/keys.js";import{loadContext}from"#context/container.js";import{loadSkillFromSandbox}from"#runtime/skills/sandbox-access.js";async function executeLoadSkillTool(t){let n=loadContext().get(SandboxKey);if(n===void 0)throw Error(`The load_skill tool requires sandbox access on the runtime context. Ensure the step is running inside a managed runtime context with sandbox support.`);let{skill:r}=t;return await loadSkillFromSandbox(n,r)}const SKILL_OUTPUT_SCHEMA={type:`string`},SKILL_TOOL_DEFINITION={description:[`Load the full instructions for one available skill by name or id.`,`Use this tool when the request clearly matches a listed skill description or when the user explicitly asks for that skill.`,`Loading adds the skill instructions to the current turn.`,`Choose the "skill" value from the Available skills block.`].join(` `),execute:e=>executeLoadSkillTool(e),inputSchema:{additionalProperties:!1,properties:{skill:{description:`Available skill name or id.`,type:`string`}},required:[`skill`],type:`object`},logicalPath:`ash:framework/load-skill`,name:`load_skill`,outputSchema:SKILL_OUTPUT_SCHEMA,sourceId:`ash:load-skill-tool`,sourceKind:`module`};export{SKILL_OUTPUT_SCHEMA,SKILL_TOOL_DEFINITION};
@@ -1,5 +1,6 @@
1
1
  import { ContextKey } from "#context/key.js";
2
2
  import type { ResolvedToolDefinition } from "#runtime/types.js";
3
+ import type { JsonObject } from "#shared/json.js";
3
4
  /**
4
5
  * Single item in the todo list.
5
6
  */
@@ -34,4 +35,5 @@ export interface TodoToolInput {
34
35
  * the full current state.
35
36
  */
36
37
  export declare function executeTodoTool(input: TodoToolInput): unknown;
38
+ export declare const TODO_OUTPUT_SCHEMA: JsonObject;
37
39
  export declare const TODO_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -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
- `)}`}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(){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};
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_ITEM_SCHEMA={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`},TODO_OUTPUT_SCHEMA={additionalProperties:!1,properties:{counts:{additionalProperties:!1,properties:{cancelled:{minimum:0,type:`integer`},completed:{minimum:0,type:`integer`},in_progress:{minimum:0,type:`integer`},pending:{minimum:0,type:`integer`},total:{minimum:0,type:`integer`}},required:[`cancelled`,`completed`,`in_progress`,`pending`,`total`],type:`object`},todos:{items:TODO_ITEM_SCHEMA,type:`array`}},required:[`counts`,`todos`],type:`object`},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:TODO_ITEM_SCHEMA,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`}]}},outputSchema:TODO_OUTPUT_SCHEMA,sourceId:`ash:todo-tool`,sourceKind:`module`};export{TODO_OUTPUT_SCHEMA,TODO_TOOL_DEFINITION,TodoStateKey,executeTodoTool};
@@ -1,2 +1,5 @@
1
1
  import type { ResolvedToolDefinition } from "#runtime/types.js";
2
+ import type { JsonObject } from "#shared/json.js";
3
+ export declare const WEB_FETCH_INPUT_SCHEMA: JsonObject;
4
+ export declare const WEB_FETCH_OUTPUT_SCHEMA: JsonObject;
2
5
  export declare const WEB_FETCH_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1,2 +1,2 @@
1
- import{executeWebFetchTool}from"#execution/web-fetch/tool.js";async function executeWebFetch(e){return executeWebFetchTool(e)}const WEB_FETCH_TOOL_DEFINITION={description:[`Fetch a webpage and return its content in the requested format. Use this to retrieve and analyze content from URLs.`,``,`Usage notes:`,`- The URL must be a fully-formed valid URL starting with http:// or https://`,`- HTML responses are automatically converted to markdown or plain text based on the requested format`,`- Format options: "markdown" (default), "text", or "html"`,`- Default timeout is 30 seconds (max 120 seconds)`,`- Maximum response size is 5 MB; content is further capped at the shared tool-output budget (50 KB / 2000 lines)`,`- This tool is read-only and does not modify any files`].join(`
2
- `),execute:executeWebFetch,inputSchema:{additionalProperties:!1,properties:{format:{description:`The format to return the content in (text, markdown, or html). HTML responses are automatically converted to the requested format. Defaults to "markdown".`,enum:[`markdown`,`text`,`html`],type:`string`},timeout:{description:`Optional timeout in seconds. Defaults to 30, max 120.`,type:`number`},url:{description:`The fully-formed URL to fetch content from. Must start with http:// or https://.`,type:`string`}},required:[`url`],type:`object`},logicalPath:`ash:framework/web-fetch`,name:`web_fetch`,sourceId:`ash:web-fetch-tool`,sourceKind:`module`};export{WEB_FETCH_TOOL_DEFINITION};
1
+ import{executeWebFetchTool}from"#execution/web-fetch/tool.js";async function executeWebFetch(e){return executeWebFetchTool(e)}const WEB_FETCH_INPUT_SCHEMA={additionalProperties:!1,properties:{format:{description:`The format to return the content in (text, markdown, or html). HTML responses are automatically converted to the requested format. Defaults to "markdown".`,enum:[`markdown`,`text`,`html`],type:`string`},timeout:{description:`Optional timeout in seconds. Defaults to 30, max 120.`,type:`number`},url:{description:`The fully-formed URL to fetch content from. Must start with http:// or https://.`,type:`string`}},required:[`url`],type:`object`},WEB_FETCH_OUTPUT_SCHEMA={additionalProperties:!1,properties:{content:{type:`string`},contentType:{type:`string`},truncated:{type:`boolean`},url:{type:`string`}},required:[`content`,`contentType`,`url`,`truncated`],type:`object`},WEB_FETCH_TOOL_DEFINITION={description:[`Fetch a webpage and return its content in the requested format. Use this to retrieve and analyze content from URLs.`,``,`Usage notes:`,`- The URL must be a fully-formed valid URL starting with http:// or https://`,`- HTML responses are automatically converted to markdown or plain text based on the requested format`,`- Format options: "markdown" (default), "text", or "html"`,`- Default timeout is 30 seconds (max 120 seconds)`,`- Maximum response size is 5 MB; content is further capped at the shared tool-output budget (50 KB / 2000 lines)`,`- This tool is read-only and does not modify any files`].join(`
2
+ `),execute:executeWebFetch,inputSchema:WEB_FETCH_INPUT_SCHEMA,logicalPath:`ash:framework/web-fetch`,name:`web_fetch`,outputSchema:WEB_FETCH_OUTPUT_SCHEMA,sourceId:`ash:web-fetch-tool`,sourceKind:`module`};export{WEB_FETCH_INPUT_SCHEMA,WEB_FETCH_OUTPUT_SCHEMA,WEB_FETCH_TOOL_DEFINITION};
@@ -1,4 +1,21 @@
1
1
  import type { ResolvedToolDefinition } from "#runtime/types.js";
2
+ import type { JsonObject } from "#shared/json.js";
3
+ /**
4
+ * Output schema for OpenAI's provider-managed `webSearch` tool.
5
+ */
6
+ export declare const WEB_SEARCH_OPENAI_OUTPUT_SCHEMA: JsonObject;
7
+ /**
8
+ * Output schema for Anthropic's stable provider-managed `webSearch_20250305` tool.
9
+ */
10
+ export declare const WEB_SEARCH_ANTHROPIC_OUTPUT_SCHEMA: JsonObject;
11
+ /**
12
+ * Output schema for Google's provider-managed `googleSearch` grounding tool.
13
+ */
14
+ export declare const WEB_SEARCH_GOOGLE_OUTPUT_SCHEMA: JsonObject;
15
+ /**
16
+ * Output schema for AI Gateway's provider-managed `perplexitySearch` tool.
17
+ */
18
+ export declare const WEB_SEARCH_GATEWAY_OUTPUT_SCHEMA: JsonObject;
2
19
  /**
3
20
  * Framework-provided web search tool definition.
4
21
  *
@@ -1 +1 @@
1
- const WEB_SEARCH_TOOL_DEFINITION={description:`Search the web for real-time information. Use this to find up-to-date information about current events, recent developments, or topics that may have changed since the knowledge cutoff.`,inputSchema:null,logicalPath:`ash:framework/web-search`,name:`web_search`,sourceId:`ash:web-search-tool`,sourceKind:`module`};export{WEB_SEARCH_TOOL_DEFINITION};
1
+ const WEB_SEARCH_OPENAI_OUTPUT_SCHEMA={$schema:`http://json-schema.org/draft-07/schema#`,additionalProperties:!1,properties:{action:{oneOf:[{additionalProperties:!1,properties:{queries:{items:{type:`string`},type:`array`},query:{type:`string`},type:{const:`search`,type:`string`}},required:[`type`],type:`object`},{additionalProperties:!1,properties:{type:{const:`openPage`,type:`string`},url:{anyOf:[{type:`string`},{type:`null`}]}},required:[`type`],type:`object`},{additionalProperties:!1,properties:{pattern:{anyOf:[{type:`string`},{type:`null`}]},type:{const:`findInPage`,type:`string`},url:{anyOf:[{type:`string`},{type:`null`}]}},required:[`type`],type:`object`}]},sources:{items:{oneOf:[{additionalProperties:!1,properties:{type:{const:`url`,type:`string`},url:{type:`string`}},required:[`type`,`url`],type:`object`},{additionalProperties:!1,properties:{name:{type:`string`},type:{const:`api`,type:`string`}},required:[`type`,`name`],type:`object`}]},type:`array`}},type:`object`},WEB_SEARCH_ANTHROPIC_OUTPUT_SCHEMA={$schema:`http://json-schema.org/draft-07/schema#`,items:{additionalProperties:!1,properties:{encryptedContent:{type:`string`},pageAge:{anyOf:[{type:`string`},{type:`null`}]},title:{anyOf:[{type:`string`},{type:`null`}]},type:{const:`web_search_result`,type:`string`},url:{type:`string`}},required:[`url`,`title`,`pageAge`,`encryptedContent`,`type`],type:`object`},type:`array`},WEB_SEARCH_GOOGLE_OUTPUT_SCHEMA={$schema:`http://json-schema.org/draft-07/schema#`,additionalProperties:!1,properties:{},type:`object`},WEB_SEARCH_GATEWAY_OUTPUT_SCHEMA={$schema:`http://json-schema.org/draft-07/schema#`,anyOf:[{additionalProperties:!1,properties:{id:{type:`string`},results:{items:{additionalProperties:!1,properties:{date:{type:`string`},lastUpdated:{type:`string`},snippet:{type:`string`},title:{type:`string`},url:{type:`string`}},required:[`title`,`url`,`snippet`],type:`object`},type:`array`}},required:[`results`,`id`],type:`object`},{additionalProperties:!1,properties:{error:{enum:[`api_error`,`rate_limit`,`timeout`,`invalid_input`,`unknown`],type:`string`},message:{type:`string`},statusCode:{type:`number`}},required:[`error`,`message`],type:`object`}]},WEB_SEARCH_TOOL_DEFINITION={description:`Search the web for real-time information. Use this to find up-to-date information about current events, recent developments, or topics that may have changed since the knowledge cutoff.`,inputSchema:null,logicalPath:`ash:framework/web-search`,name:`web_search`,sourceId:`ash:web-search-tool`,sourceKind:`module`};export{WEB_SEARCH_ANTHROPIC_OUTPUT_SCHEMA,WEB_SEARCH_GATEWAY_OUTPUT_SCHEMA,WEB_SEARCH_GOOGLE_OUTPUT_SCHEMA,WEB_SEARCH_OPENAI_OUTPUT_SCHEMA,WEB_SEARCH_TOOL_DEFINITION};
@@ -9,4 +9,9 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
9
9
  * model input contracts in sync without duplication.
10
10
  */
11
11
  export declare const WRITE_FILE_INPUT_SCHEMA: JsonObject;
12
+ /**
13
+ * Shared output schema used by the framework `write_file` tool and any author
14
+ * tool constructed via {@link defineWriteFileTool}.
15
+ */
16
+ export declare const WRITE_FILE_OUTPUT_SCHEMA: JsonObject;
12
17
  export declare const WRITE_FILE_TOOL_DEFINITION: ResolvedToolDefinition;
@@ -1,2 +1,2 @@
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
- `),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};
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`},WRITE_FILE_OUTPUT_SCHEMA={additionalProperties:!1,properties:{existed:{type:`boolean`},path:{type:`string`}},required:[`existed`,`path`],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
+ `),execute:executeWriteFile,inputSchema:WRITE_FILE_INPUT_SCHEMA,logicalPath:`ash:framework/write-file`,name:`write_file`,outputSchema:WRITE_FILE_OUTPUT_SCHEMA,sourceId:`ash:write-file-tool`,sourceKind:`module`};export{WRITE_FILE_INPUT_SCHEMA,WRITE_FILE_OUTPUT_SCHEMA,WRITE_FILE_TOOL_DEFINITION};
@@ -1 +1 @@
1
- import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{registerDefinitionSource,stampDefinitionKey}from"#public/tool-result-narrowing.js";async function resolveToolDefinition(i,a,o){try{let n=expectObjectRecord(await loadResolvedModuleExport({definition:i,kindLabel:`tool`,moduleMap:a,nodeId:o}),describe(i,`to return an object`)),r={kind:`tool`,logicalPath:i.logicalPath,name:i.name},s=`tool-source:${i.sourceId}`;stampDefinitionKey(n,s),registerDefinitionSource(s,r),registerDefinitionSource(`tool:${n.description}`,r);let c=expectFunction(n.execute,describe(i,`to provide an execute function`));return{description:i.description,execute:c,exportName:i.exportName,inputSchema:i.inputSchema,logicalPath:i.logicalPath,name:i.name,sourceId:i.sourceId,sourceKind:`module`,...extractOptionalHooks(n,i)}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the tool execute function from "${i.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:i.logicalPath,sourceId:i.sourceId})}}function extractOptionalHooks(t,n){let r={};return t.onCompact!==void 0&&(r.onCompact=expectFunction(t.onCompact,describe(n,`to provide an onCompact function`))),t.needsApproval!==void 0&&(r.needsApproval=expectFunction(t.needsApproval,describe(n,`to provide a needsApproval function`))),t.toModelOutput!==void 0&&(r.toModelOutput=expectFunction(t.toModelOutput,describe(n,`to provide a toModelOutput function`))),t.inputSchema!==void 0&&isFlexibleSchema(t.inputSchema)&&(r.inputStandardSchema=t.inputSchema),r}function describe(e,t){return`Expected the tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}function isFlexibleSchema(e){return typeof e==`object`&&!!e&&`~standard`in e&&typeof e[`~standard`]==`object`}export{resolveToolDefinition};
1
+ import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{registerDefinitionSource,stampDefinitionKey}from"#public/tool-result-narrowing.js";async function resolveToolDefinition(i,a,o){try{let n=expectObjectRecord(await loadResolvedModuleExport({definition:i,kindLabel:`tool`,moduleMap:a,nodeId:o}),describe(i,`to return an object`)),r={kind:`tool`,logicalPath:i.logicalPath,name:i.name},s=`tool-source:${i.sourceId}`;stampDefinitionKey(n,s),registerDefinitionSource(s,r),registerDefinitionSource(`tool:${n.description}`,r);let c=expectFunction(n.execute,describe(i,`to provide an execute function`));return{description:i.description,execute:c,exportName:i.exportName,inputSchema:i.inputSchema,logicalPath:i.logicalPath,name:i.name,outputSchema:i.outputSchema,sourceId:i.sourceId,sourceKind:`module`,...extractOptionalHooks(n,i)}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the tool execute function from "${i.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:i.logicalPath,sourceId:i.sourceId})}}function extractOptionalHooks(t,n){let r={};return t.onCompact!==void 0&&(r.onCompact=expectFunction(t.onCompact,describe(n,`to provide an onCompact function`))),t.needsApproval!==void 0&&(r.needsApproval=expectFunction(t.needsApproval,describe(n,`to provide a needsApproval function`))),t.toModelOutput!==void 0&&(r.toModelOutput=expectFunction(t.toModelOutput,describe(n,`to provide a toModelOutput function`))),t.inputSchema!==void 0&&isFlexibleSchema(t.inputSchema)&&(r.inputStandardSchema=t.inputSchema),t.outputSchema!==void 0&&isFlexibleSchema(t.outputSchema)&&(r.outputStandardSchema=t.outputSchema),r}function describe(e,t){return`Expected the tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}function isFlexibleSchema(e){return typeof e==`object`&&!!e&&`~standard`in e&&typeof e[`~standard`]==`object`}export{resolveToolDefinition};
@@ -1 +1 @@
1
- import{RuntimeRegistry,RuntimeRegistryError}from"#internal/runtime-registry.js";const SUBAGENT_TOOL_INPUT_SCHEMA=Object.freeze({type:`object`,properties:Object.freeze({message:Object.freeze({type:`string`,description:`The message to send to the subagent. Provide all context the subagent needs to complete the task; the subagent does not see the parent's history.`})}),required:Object.freeze([`message`]),additionalProperties:!1});function createRuntimeSubagentRegistry(t){let n=[],r=new RuntimeRegistry(`subagent`,t.reservedToolNames??[]),i=new Map;for(let e of t.subagents){let t={logicalPath:e.logicalPath,sourceId:e.sourceId};if(i.has(e.nodeId))throw new RuntimeRegistryError(`subagent`,`Found multiple runtime subagents mapped to node id "${e.nodeId}".`,{...t,entryName:e.name});let a=createPreparedRuntimeSubagentTool(e),o={definition:e,prepared:a};r.register(e.name,o,{location:t,duplicateMessage:`Found multiple subagents named "${e.name}". Subagent names must be unique at runtime.`,reservedMessage:`Subagent "${e.name}" collides with another runtime-visible tool name.`}),n.push(a),i.set(e.nodeId,o)}return{preparedTools:n,subagentsByName:r.asMap(),subagentsByNodeId:i}}function createPreparedRuntimeSubagentTool(e){return{description:e.description,inputSchema:SUBAGENT_TOOL_INPUT_SCHEMA,kind:e.kind,logicalPath:e.logicalPath,name:e.name,nodeId:e.nodeId,sourceId:e.sourceId}}export{createRuntimeSubagentRegistry};
1
+ import{RuntimeRegistry,RuntimeRegistryError}from"#internal/runtime-registry.js";const SUBAGENT_TOOL_INPUT_SCHEMA=Object.freeze({type:`object`,properties:Object.freeze({message:Object.freeze({type:`string`,description:`The message to send to the subagent. Provide all context the subagent needs to complete the task; the subagent does not see the parent's history.`})}),required:Object.freeze([`message`]),additionalProperties:!1});function createRuntimeSubagentRegistry(t){let n=[],r=new RuntimeRegistry(`subagent`,t.reservedToolNames??[]),i=new Map;for(let e of t.subagents){let t={logicalPath:e.logicalPath,sourceId:e.sourceId};if(i.has(e.nodeId))throw new RuntimeRegistryError(`subagent`,`Found multiple runtime subagents mapped to node id "${e.nodeId}".`,{...t,entryName:e.name});let a=createPreparedRuntimeSubagentTool(e),o={definition:e,prepared:a};r.register(e.name,o,{location:t,duplicateMessage:`Found multiple subagents named "${e.name}". Subagent names must be unique at runtime.`,reservedMessage:`Subagent "${e.name}" collides with another runtime-visible tool name.`}),n.push(a),i.set(e.nodeId,o)}return{preparedTools:n,subagentsByName:r.asMap(),subagentsByNodeId:i}}function createPreparedRuntimeSubagentTool(e){return{description:e.description,inputSchema:SUBAGENT_TOOL_INPUT_SCHEMA,kind:e.kind,logicalPath:e.logicalPath,name:e.name,nodeId:e.nodeId,outputSchema:e.kind===`remote`?e.outputSchema:void 0,sourceId:e.sourceId}}export{createRuntimeSubagentRegistry};
@@ -1 +1 @@
1
- import{RuntimeRegistry}from"#internal/runtime-registry.js";async function createRuntimeToolRegistry(t,n={}){let r=[],i=new RuntimeRegistry(`tool`,n.reservedToolNames??[]);for(let e of t.tools){let t=await createPreparedRuntimeTool(e);i.register(e.name,{definition:e,prepared:t},{location:{logicalPath:e.logicalPath,sourceId:e.sourceId},duplicateMessage:`Found multiple authored tools named "${e.name}". Tool names must be unique at runtime.`,reservedMessage:`Tool "${e.name}" collides with another runtime-visible tool name.`}),r.push(t)}return{preparedTools:r,toolsByName:i.asMap()}}function findRegisteredRuntimeTool(e,t){return e.toolsByName.get(t)??null}async function createPreparedRuntimeTool(e){return{description:e.description,inputSchema:e.inputSchema,kind:`authored-tool`,logicalPath:e.logicalPath,name:e.name,sourceId:e.sourceId}}export{createRuntimeToolRegistry,findRegisteredRuntimeTool};
1
+ import{RuntimeRegistry}from"#internal/runtime-registry.js";async function createRuntimeToolRegistry(t,n={}){let r=[],i=new RuntimeRegistry(`tool`,n.reservedToolNames??[]);for(let e of t.tools){let t=await createPreparedRuntimeTool(e);i.register(e.name,{definition:e,prepared:t},{location:{logicalPath:e.logicalPath,sourceId:e.sourceId},duplicateMessage:`Found multiple authored tools named "${e.name}". Tool names must be unique at runtime.`,reservedMessage:`Tool "${e.name}" collides with another runtime-visible tool name.`}),r.push(t)}return{preparedTools:r,toolsByName:i.asMap()}}function findRegisteredRuntimeTool(e,t){return e.toolsByName.get(t)??null}async function createPreparedRuntimeTool(e){return{description:e.description,inputSchema:e.inputSchema,kind:`authored-tool`,logicalPath:e.logicalPath,name:e.name,outputSchema:e.outputSchema,sourceId:e.sourceId}}export{createRuntimeToolRegistry,findRegisteredRuntimeTool};
@@ -108,6 +108,11 @@ export type ResolvedToolDefinition = Readonly<Optional<InternalToolDefinitionWit
108
108
  * extraction and runtime validation with transforms/defaults.
109
109
  */
110
110
  readonly inputStandardSchema?: FlexibleSchema;
111
+ /**
112
+ * Optional live Standard Schema reattached from the authored module at
113
+ * resolve time for tool output typing/validation.
114
+ */
115
+ readonly outputStandardSchema?: FlexibleSchema;
111
116
  /**
112
117
  * Optional per-tool approval gate. When set, determines whether user
113
118
  * approval is required before executing this tool. See
@@ -1,5 +1,5 @@
1
1
  import type { ModelMessage } from "ai";
2
- import type { PublicToolInputSchema, ToolModelOutput } from "#shared/tool-definition.js";
2
+ import type { PublicToolInputSchema, PublicToolOutputSchema, ToolModelOutput } from "#shared/tool-definition.js";
3
3
  import type { SessionContext } from "#public/definitions/callback-context.js";
4
4
  import type { NeedsApprovalContext } from "#public/definitions/tool.js";
5
5
  import type { SessionAuth } from "#context/keys.js";
@@ -55,6 +55,7 @@ export interface DynamicResolveContext {
55
55
  export interface DynamicToolEntry<TInput = Record<string, unknown>, TOutput = any> {
56
56
  readonly description: string;
57
57
  readonly inputSchema: PublicToolInputSchema<TInput>;
58
+ readonly outputSchema?: PublicToolOutputSchema<TOutput>;
58
59
  execute(input: TInput, ctx: ToolContext): TOutput | Promise<TOutput>;
59
60
  readonly toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
60
61
  /**
@@ -1,7 +1,9 @@
1
1
  import type { StandardJSONSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
2
2
  import { type JsonObject } from "#shared/json.js";
3
+ type JsonSchemaDirection = "input" | "output";
3
4
  /**
4
5
  * Normalizes one Standard Schema or JSON Schema definition into plain JSON
5
6
  * Schema data that can cross Ash runtime and client boundaries.
6
7
  */
7
- export declare function normalizeJsonSchemaDefinition(value: StandardJSONSchemaV1 | Record<string, unknown> | unknown): JsonObject;
8
+ export declare function normalizeJsonSchemaDefinition(value: StandardJSONSchemaV1 | Record<string, unknown> | unknown, direction?: JsonSchemaDirection): JsonObject;
9
+ export {};
@@ -1 +1 @@
1
- import{parseJsonObject}from"#shared/json.js";function normalizeJsonSchemaDefinition(t){return isStandardSchema(t)?parseJsonObject(t[`~standard`].jsonSchema.input({target:`draft-07`})):parseJsonObject(t)}function isStandardSchema(e){return typeof e==`object`&&!!e&&`~standard`in e}export{normalizeJsonSchemaDefinition};
1
+ import{parseJsonObject}from"#shared/json.js";function normalizeJsonSchemaDefinition(t,n=`input`){return isStandardSchema(t)?parseJsonObject(t[`~standard`].jsonSchema[n]({target:`draft-07`})):parseJsonObject(t)}function isStandardSchema(e){return typeof e==`object`&&!!e&&`~standard`in e}export{normalizeJsonSchemaDefinition};
@@ -20,19 +20,27 @@ interface ToolDefinitionBase {
20
20
  export interface InternalToolDefinition extends ToolDefinitionBase {
21
21
  name: string;
22
22
  inputSchema: JsonObject | null;
23
+ outputSchema?: JsonObject;
23
24
  }
24
25
  export type PublicToolInputSchema<TInput = unknown> = StandardJSONSchemaV1<unknown, TInput> | JsonObject;
26
+ export type PublicToolOutputSchema<TOutput = unknown> = StandardJSONSchemaV1<unknown, TOutput> | JsonObject;
25
27
  /**
26
28
  * Authored public tool definition shape. Identity is derived from the
27
29
  * file path at compile time, so `name` is intentionally absent here.
28
30
  */
29
- export interface PublicToolDefinition<TInput = unknown> extends ToolDefinitionBase {
31
+ export interface PublicToolDefinition<TInput = unknown, TOutput = unknown> extends ToolDefinitionBase {
30
32
  inputSchema: PublicToolInputSchema<TInput>;
33
+ /**
34
+ * Optional schema describing the value returned by the tool executor.
35
+ * Code mode uses this to expose typed host-tool return values to the
36
+ * generated program, and the AI SDK can use it for tool result typing.
37
+ */
38
+ outputSchema?: PublicToolOutputSchema<TOutput>;
31
39
  }
32
40
  export interface InternalToolDefinitionWithExecuteFn<TInput = unknown, TOutput = unknown> extends InternalToolDefinition {
33
41
  execute: ToolExecuteFn<TInput, TOutput>;
34
42
  }
35
- export interface PublicToolDefinitionWithExecuteFn<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput> {
43
+ export interface PublicToolDefinitionWithExecuteFn<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> {
36
44
  execute: ToolExecuteFn<TInput, TOutput>;
37
45
  }
38
46
  /**
package/package.json CHANGED
@@ -1,6 +1,25 @@
1
1
  {
2
2
  "name": "experimental-ash",
3
- "version": "0.55.3",
3
+ "version": "0.56.0",
4
+ "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
5
+ "keywords": [
6
+ "agent-framework",
7
+ "agents",
8
+ "ai-agents",
9
+ "ai-sdk",
10
+ "ash",
11
+ "evals",
12
+ "mcp",
13
+ "model-context-protocol",
14
+ "nextjs",
15
+ "observability",
16
+ "react",
17
+ "serverless",
18
+ "tools",
19
+ "vercel",
20
+ "workflow"
21
+ ],
22
+ "license": "Apache-2.0",
4
23
  "bin": {
5
24
  "ash": "./bin/ash.js",
6
25
  "experimental-ash": "./bin/ash.js"