experimental-ash 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/docs/public/README.md +8 -8
- package/dist/docs/public/advanced/{auth-and-route-protection.md → auth-and-route-protection.mdx} +11 -0
- package/dist/docs/public/advanced/context-control.md +4 -4
- package/dist/docs/public/advanced/{evals.md → evals.mdx} +11 -1
- package/dist/docs/public/advanced/{hooks.md → hooks.mdx} +28 -40
- package/dist/docs/public/advanced/instrumentation.md +92 -3
- package/dist/docs/public/advanced/project-layout.md +5 -5
- package/dist/docs/public/advanced/runs-and-streaming.md +8 -2
- package/dist/docs/public/advanced/session-context.md +1 -1
- package/dist/docs/public/advanced/typescript-api.md +49 -6
- package/dist/docs/public/advanced/vercel-deployment.md +1 -1
- package/dist/docs/public/agent-ts.md +5 -5
- package/dist/docs/public/channels/{discord.md → discord.mdx} +11 -0
- package/dist/docs/public/channels/index.md +10 -10
- package/dist/docs/public/channels/{slack.md → slack.mdx} +11 -0
- package/dist/docs/public/channels/{teams.md → teams.mdx} +12 -0
- package/dist/docs/public/channels/{telegram.md → telegram.mdx} +11 -0
- package/dist/docs/public/channels/{twilio.md → twilio.mdx} +11 -0
- package/dist/docs/public/{connections.md → connections.mdx} +18 -6
- package/dist/docs/public/frontend/README.md +16 -0
- package/dist/docs/public/frontend/meta.json +3 -0
- package/dist/docs/public/frontend/nextjs.md +192 -0
- package/dist/docs/public/frontend/use-ash-agent.md +332 -0
- package/dist/docs/public/{getting-started.md → getting-started.mdx} +12 -1
- package/dist/docs/public/{human-in-the-loop.md → human-in-the-loop.mdx} +12 -1
- package/dist/docs/public/meta.json +1 -0
- package/dist/docs/public/sandbox.md +1 -1
- package/dist/docs/public/{schedules.md → schedules.mdx} +9 -0
- package/dist/docs/public/skills.md +2 -2
- package/dist/docs/public/{subagents.md → subagents.mdx} +10 -0
- package/dist/docs/public/{tools.md → tools.mdx} +41 -26
- package/dist/src/channel/adapter.d.ts +13 -0
- package/dist/src/channel/instrumentation.d.ts +10 -0
- package/dist/src/channel/instrumentation.js +1 -0
- package/dist/src/channel/send.js +1 -1
- package/dist/src/channel/types.d.ts +16 -0
- package/dist/src/cli/commands/channels.d.ts +2 -1
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/compiler/manifest.d.ts +13 -1
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/module-map.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-skill.d.ts +15 -2
- package/dist/src/compiler/normalize-skill.js +1 -1
- package/dist/src/compiler/normalize-tool.js +1 -1
- package/dist/src/context/dynamic-skill-lifecycle.d.ts +23 -0
- package/dist/src/context/dynamic-skill-lifecycle.js +1 -0
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +2 -0
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/hook-lifecycle.d.ts +4 -6
- package/dist/src/context/hook-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +6 -4
- package/dist/src/context/keys.js +1 -1
- package/dist/src/context/providers/connection.d.ts +9 -0
- package/dist/src/context/providers/connection.js +1 -1
- package/dist/src/context/providers/sandbox.js +1 -1
- package/dist/src/execution/ash-workflow-attributes.d.ts +118 -0
- package/dist/src/execution/ash-workflow-attributes.js +1 -0
- package/dist/src/execution/channel-context.d.ts +5 -0
- package/dist/src/execution/channel-context.js +1 -0
- package/dist/src/execution/create-session-step.d.ts +28 -1
- package/dist/src/execution/create-session-step.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/durable-session-store.d.ts +7 -0
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/sandbox/prewarm.js +1 -1
- package/dist/src/execution/session.d.ts +6 -0
- package/dist/src/execution/session.js +2 -2
- package/dist/src/execution/skills/instructions.d.ts +3 -2
- package/dist/src/execution/subagent-tool.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/attachment-staging.js +1 -1
- package/dist/src/harness/code-mode.d.ts +0 -5
- package/dist/src/harness/code-mode.js +1 -1
- package/dist/src/harness/emission.d.ts +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/instrumentation-config.d.ts +1 -1
- package/dist/src/harness/instrumentation-metadata.d.ts +23 -0
- package/dist/src/harness/instrumentation-metadata.js +1 -0
- package/dist/src/harness/otel-integration.d.ts +2 -2
- package/dist/src/harness/otel-integration.js +1 -1
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/turn-tag-state.d.ts +50 -0
- package/dist/src/harness/turn-tag-state.js +1 -0
- package/dist/src/harness/types.d.ts +11 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/schema-backed.d.ts +0 -1
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/instrumentation.d.ts +39 -0
- package/dist/src/internal/instrumentation.js +1 -0
- package/dist/src/internal/workflow/builtins.d.ts +32 -0
- package/dist/src/internal/workflow/builtins.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.d.ts +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-core-shim.d.ts +34 -0
- package/dist/src/internal/workflow-bundle/workflow-core-shim.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-transformer.js +1 -1
- package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
- package/dist/src/packages/ash-scaffold/src/steps/run-add-to-agent.js +2 -2
- package/dist/src/public/channels/slack/attachments.js +1 -1
- package/dist/src/public/channels/slack/index.d.ts +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +6 -0
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/index.d.ts +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +6 -0
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/defineChannel.d.ts +12 -2
- package/dist/src/public/definitions/defineChannel.js +1 -1
- package/dist/src/public/definitions/hook.d.ts +3 -11
- package/dist/src/public/definitions/instrumentation.d.ts +88 -2
- package/dist/src/public/definitions/skill.d.ts +5 -0
- package/dist/src/public/definitions/tool.d.ts +25 -66
- package/dist/src/public/definitions/tool.js +1 -1
- package/dist/src/public/instrumentation/index.d.ts +1 -4
- package/dist/src/public/instrumentation/index.js +1 -1
- package/dist/src/public/skills/index.d.ts +2 -0
- package/dist/src/public/skills/index.js +1 -1
- package/dist/src/public/tools/index.d.ts +2 -2
- package/dist/src/public/tools/index.js +1 -1
- package/dist/src/runtime/agent/mock-model-adapter.js +4 -7
- package/dist/src/runtime/agent/mock-model-skill-selection.d.ts +9 -0
- package/dist/src/runtime/agent/mock-model-skill-selection.js +4 -0
- package/dist/src/runtime/attributes/emit.d.ts +73 -0
- package/dist/src/runtime/attributes/emit.js +1 -0
- package/dist/src/runtime/channels/registry.js +1 -1
- package/dist/src/runtime/connections/mcp-client.js +1 -1
- package/dist/src/runtime/framework-tools/code-mode-connection-auth.d.ts +2 -0
- package/dist/src/runtime/framework-tools/connection-search-dynamic.d.ts +34 -0
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -0
- package/dist/src/runtime/framework-tools/index.d.ts +7 -5
- package/dist/src/runtime/framework-tools/index.js +1 -1
- package/dist/src/runtime/prompt/connections.js +1 -1
- package/dist/src/runtime/resolve-agent-graph.js +1 -1
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/resolve-dynamic-skill.d.ts +8 -0
- package/dist/src/runtime/resolve-dynamic-skill.js +1 -0
- package/dist/src/runtime/resolve-dynamic-tool.js +1 -1
- package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
- package/dist/src/runtime/sessions/runtime-context-keys.js +1 -1
- package/dist/src/runtime/types.d.ts +13 -4
- package/dist/src/shared/dynamic-tool-definition.d.ts +51 -76
- package/dist/src/shared/dynamic-tool-definition.js +1 -1
- package/dist/src/shared/guards.d.ts +14 -0
- package/dist/src/shared/guards.js +1 -1
- package/dist/src/shared/skill-definition.d.ts +5 -4
- package/dist/src/shared/tool-definition.d.ts +12 -0
- package/package.json +2 -1
- package/dist/src/runtime/framework-tools/connection-search.d.ts +0 -57
- package/dist/src/runtime/framework-tools/connection-search.js +0 -1
- package/dist/src/runtime/framework-tools/connection-tools.d.ts +0 -55
- package/dist/src/runtime/framework-tools/connection-tools.js +0 -1
|
@@ -53,7 +53,7 @@ export interface ReceiveInput<TReceiveArgs = Record<string, unknown>> {
|
|
|
53
53
|
readonly args: Readonly<TReceiveArgs>;
|
|
54
54
|
readonly auth: SessionAuthContext | null;
|
|
55
55
|
}
|
|
56
|
-
export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveArgs = Record<string, unknown>> {
|
|
56
|
+
export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveArgs = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
|
|
57
57
|
readonly state?: TState;
|
|
58
58
|
/**
|
|
59
59
|
* Builds the per-step channel context handed to `events` and
|
|
@@ -84,6 +84,16 @@ export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveArgs
|
|
|
84
84
|
* stage the file to the sandbox.
|
|
85
85
|
*/
|
|
86
86
|
readonly fetchFile?: (url: string) => Promise<Buffer | FetchFileResult | null>;
|
|
87
|
+
/**
|
|
88
|
+
* Channel-owned metadata exposed to instrumentation callbacks.
|
|
89
|
+
*
|
|
90
|
+
* Keep this projection intentionally small. It is the channel's public
|
|
91
|
+
* observability surface, not a dump of durable adapter state. Return an
|
|
92
|
+
* object composed of JSON primitives, arrays, and plain objects. Ash omits
|
|
93
|
+
* `undefined` object properties and drops projections containing values such
|
|
94
|
+
* as `Date` or `Map`.
|
|
95
|
+
*/
|
|
96
|
+
readonly metadata?: (state: NonNullable<TState>) => TMetadata;
|
|
87
97
|
/**
|
|
88
98
|
* Identifier of the adapter family this channel belongs to. Set by
|
|
89
99
|
* higher-level wrappers (e.g. `slackChannel` passes `"slack"`) so
|
|
@@ -107,4 +117,4 @@ export interface Channel<TState = undefined, TReceiveArgs = Record<string, unkno
|
|
|
107
117
|
send: SendFn<TState>;
|
|
108
118
|
}) => Promise<Session>;
|
|
109
119
|
}
|
|
110
|
-
export declare function defineChannel<TState = undefined, TCtx = void, TReceiveArgs = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveArgs>): Channel<TState, TReceiveArgs>;
|
|
120
|
+
export declare function defineChannel<TState = undefined, TCtx = void, TReceiveArgs = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveArgs, TMetadata>): Channel<TState, TReceiveArgs>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CHANNEL_SENTINEL}from"#channel/compiled-channel.js";import{
|
|
1
|
+
import{CHANNEL_SENTINEL}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{HTTP_ADAPTER_KIND}from"#channel/http.js";import{DELETE,GET,PATCH,POST,PUT}from"#channel/routes.js";function defineChannel(t){let n=buildAdapter(t);return{__kind:CHANNEL_SENTINEL,routes:t.routes,adapter:n,receive:t.receive}}function buildAdapter(e){let i=e.state!=null,a=e.context!=null,o=e.fetchFile!==void 0,s=e.metadata,c=i||a||s!==void 0,l={},u=!1,d=[`turn.started`,`actions.requested`,`action.result`,`message.completed`,`message.appended`,`input.requested`,`turn.failed`,`turn.completed`,`session.failed`,`session.completed`,`session.waiting`,`authorization.required`,`authorization.completed`],f=e.events;for(let e of d){let t=f?.[e];t&&(u=!0,l[e]=(r,i)=>{let a={...i,continuationToken:i.session?.continuationToken??``,setContinuationToken:e=>i.session?.setContinuationToken(e)};return e===`session.failed`?t(r,a):t(r,a,buildCallbackContext())})}return!c&&!u&&!o?{kind:e.kindHint??HTTP_ADAPTER_KIND}:{kind:e.kindHint??`defineChannel`,state:i?{...e.state}:{},fetchFile:e.fetchFile,instrumentation:s===void 0?void 0:{metadata(e){return s(e)}},createAdapterContext(t){let n=t.state,r=t.session;return{...a?e.context(n,r):{},state:n,ctx:t.ctx,session:r}},deliver(e){return defaultDeliverResult(e)},...l}}export{DELETE,GET,PATCH,POST,PUT,defineChannel};
|
|
@@ -2,7 +2,6 @@ import type { ModelMessage } from "ai";
|
|
|
2
2
|
import type { HandleMessageStreamEvent } from "../../protocol/message.js";
|
|
3
3
|
import type { SessionContext } from "./callback-context.js";
|
|
4
4
|
import type { ExactDefinition } from "./exact.js";
|
|
5
|
-
import type { NamedSkillDefinition } from "./skill.js";
|
|
6
5
|
/**
|
|
7
6
|
* Context passed to every hook handler.
|
|
8
7
|
*
|
|
@@ -24,22 +23,15 @@ export interface HookContext extends SessionContext {
|
|
|
24
23
|
* `lifecycle.turn`).
|
|
25
24
|
*
|
|
26
25
|
* `modelContext` messages are appended to the next model call's message
|
|
27
|
-
* list and never written to durable session history.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* contributions are concatenated session-then-turn before the harness's
|
|
31
|
-
* first model call.
|
|
26
|
+
* list and never written to durable session history. Each lifecycle key
|
|
27
|
+
* runs in registry order; contributions are concatenated session-then-turn
|
|
28
|
+
* before the harness's first model call.
|
|
32
29
|
*
|
|
33
30
|
* Returning `void` (or `undefined`) means "no opinion" — the turn
|
|
34
31
|
* proceeds with no additional model context from this hook.
|
|
35
32
|
*/
|
|
36
33
|
export interface LifecycleHookResult {
|
|
37
34
|
readonly modelContext?: readonly ModelMessage[];
|
|
38
|
-
/**
|
|
39
|
-
* Skill packages to materialize into the live durable sandbox before the
|
|
40
|
-
* next model call. Authored skill names cannot be overwritten.
|
|
41
|
-
*/
|
|
42
|
-
readonly skills?: readonly NamedSkillDefinition[];
|
|
43
35
|
}
|
|
44
36
|
/**
|
|
45
37
|
* Lifecycle hook signature shared by `lifecycle.session` and
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { ExactDefinition } from "#public/definitions/exact.js";
|
|
2
|
+
/**
|
|
3
|
+
* Instrumentation authoring helpers for `agent/instrumentation.ts`.
|
|
4
|
+
*/
|
|
5
|
+
import type { ModelMessage, SystemModelMessage } from "ai";
|
|
6
|
+
import type { SessionAuthContext, SessionParent } from "#channel/types.js";
|
|
2
7
|
/**
|
|
3
8
|
* Context passed to the {@link InstrumentationDefinition.setup} callback.
|
|
4
9
|
*/
|
|
@@ -11,6 +16,87 @@ export interface InstrumentationSetupContext {
|
|
|
11
16
|
*/
|
|
12
17
|
readonly agentName: string;
|
|
13
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* User-authored metadata attached to AI SDK telemetry spans.
|
|
21
|
+
*
|
|
22
|
+
* Keys beginning with `ash.` are reserved for framework-owned metadata
|
|
23
|
+
* and are ignored when returned from authored instrumentation.
|
|
24
|
+
*/
|
|
25
|
+
export type InstrumentationMetadata = Readonly<Record<string, string>>;
|
|
26
|
+
/**
|
|
27
|
+
* Base channel metadata shape used by framework channel kinds.
|
|
28
|
+
*/
|
|
29
|
+
export type InstrumentationChannelMetadata = Readonly<Record<string, unknown>>;
|
|
30
|
+
/**
|
|
31
|
+
* Channel metadata projections keyed by instrumentation channel kind.
|
|
32
|
+
*
|
|
33
|
+
* Channel packages and user-authored channels declaration-merge additional
|
|
34
|
+
* `channel:<registered-name>` entries into this map so `input.channel.metadata`
|
|
35
|
+
* narrows after checking `input.channel.kind`.
|
|
36
|
+
*/
|
|
37
|
+
export interface ChannelMetadataMap {
|
|
38
|
+
readonly http: InstrumentationChannelMetadata;
|
|
39
|
+
readonly schedule: InstrumentationChannelMetadata;
|
|
40
|
+
readonly subagent: InstrumentationChannelMetadata;
|
|
41
|
+
readonly unknown: InstrumentationChannelMetadata;
|
|
42
|
+
}
|
|
43
|
+
export type InstrumentationChannelKind = keyof ChannelMetadataMap;
|
|
44
|
+
/**
|
|
45
|
+
* Channel projection exposed to instrumentation callbacks.
|
|
46
|
+
*
|
|
47
|
+
* `kind` is the channel identity Ash has for the current turn (`"http"`,
|
|
48
|
+
* `"schedule"`, `"subagent"`, or `channel:<name>` for authored channels,
|
|
49
|
+
* where `<name>` is the channel's filename under `agent/channels/`).
|
|
50
|
+
*/
|
|
51
|
+
export interface InstrumentationChannelForKind<K extends InstrumentationChannelKind> {
|
|
52
|
+
readonly kind: K;
|
|
53
|
+
readonly metadata: ChannelMetadataMap[K];
|
|
54
|
+
}
|
|
55
|
+
export type InstrumentationChannel = {
|
|
56
|
+
readonly [K in InstrumentationChannelKind]: InstrumentationChannelForKind<K>;
|
|
57
|
+
}[InstrumentationChannelKind];
|
|
58
|
+
export interface InstrumentationSession {
|
|
59
|
+
readonly auth: {
|
|
60
|
+
readonly current: SessionAuthContext | null;
|
|
61
|
+
readonly initiator: SessionAuthContext | null;
|
|
62
|
+
};
|
|
63
|
+
readonly id: string;
|
|
64
|
+
readonly parent?: SessionParent;
|
|
65
|
+
}
|
|
66
|
+
export interface InstrumentationTurn {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly sequence: number;
|
|
69
|
+
}
|
|
70
|
+
export interface InstrumentationStep {
|
|
71
|
+
readonly index: number;
|
|
72
|
+
}
|
|
73
|
+
export interface InstrumentationModelInput {
|
|
74
|
+
readonly instructions: string | readonly SystemModelMessage[] | undefined;
|
|
75
|
+
readonly messages: readonly ModelMessage[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Input passed to `metadata["step.started"]`.
|
|
79
|
+
*
|
|
80
|
+
* The callback runs after Ash has built the final model input for this
|
|
81
|
+
* model-call attempt and before the AI SDK model call is constructed.
|
|
82
|
+
*/
|
|
83
|
+
export interface InstrumentationStepStartedMetadataInput {
|
|
84
|
+
readonly channel: InstrumentationChannel;
|
|
85
|
+
readonly modelInput: InstrumentationModelInput;
|
|
86
|
+
readonly session: InstrumentationSession;
|
|
87
|
+
readonly step: InstrumentationStep;
|
|
88
|
+
readonly turn: InstrumentationTurn;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Metadata hooks accepted by {@link defineInstrumentation}.
|
|
92
|
+
*/
|
|
93
|
+
export interface InstrumentationMetadataConfig {
|
|
94
|
+
/**
|
|
95
|
+
* Per-attempt metadata resolved before the model call so child spans
|
|
96
|
+
* created by the AI SDK inherit the returned values.
|
|
97
|
+
*/
|
|
98
|
+
readonly "step.started"?: (input: InstrumentationStepStartedMetadataInput) => InstrumentationMetadata;
|
|
99
|
+
}
|
|
14
100
|
/**
|
|
15
101
|
* Authored instrumentation settings accepted by `defineInstrumentation`.
|
|
16
102
|
*
|
|
@@ -25,9 +111,9 @@ export interface InstrumentationDefinition {
|
|
|
25
111
|
*/
|
|
26
112
|
readonly functionId?: string;
|
|
27
113
|
/**
|
|
28
|
-
* Additional metadata merged into
|
|
114
|
+
* Additional metadata merged into AI SDK telemetry spans.
|
|
29
115
|
*/
|
|
30
|
-
readonly metadata?:
|
|
116
|
+
readonly metadata?: InstrumentationMetadataConfig;
|
|
31
117
|
/**
|
|
32
118
|
* Whether to record full model inputs in telemetry spans.
|
|
33
119
|
*
|
|
@@ -12,5 +12,10 @@ export type SkillDefinition = SkillPackageDefinition;
|
|
|
12
12
|
/**
|
|
13
13
|
* Defines a skill in TypeScript using the same shape discovery produces from
|
|
14
14
|
* markdown, with optional package-relative sibling files.
|
|
15
|
+
*
|
|
16
|
+
* When used as the default export of a file in `agent/skills/`, this
|
|
17
|
+
* produces a static skill. When used inside a `defineDynamic` handler,
|
|
18
|
+
* the brand stamp lets the lifecycle code detect single-entry vs
|
|
19
|
+
* map-of-entries return shapes.
|
|
15
20
|
*/
|
|
16
21
|
export declare function defineSkill<TSkill extends SkillDefinition>(definition: ExactDefinition<TSkill, SkillDefinition>): TSkill;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { StandardJSONSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
|
|
2
2
|
import type { ModelMessage } from "ai";
|
|
3
|
-
import type { PublicToolDefinition } from "#shared/tool-definition.js";
|
|
3
|
+
import type { PublicToolDefinition, ToolModelOutput } from "#shared/tool-definition.js";
|
|
4
4
|
import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
5
5
|
import type { JsonObject } from "#shared/json.js";
|
|
6
|
-
import { type
|
|
6
|
+
import { type DynamicEvents, type DynamicSentinel } from "#shared/dynamic-tool-definition.js";
|
|
7
7
|
/**
|
|
8
8
|
* Domain input passed to a tool's {@link ToolDefinition.onCompact} hook.
|
|
9
9
|
*/
|
|
@@ -39,19 +39,7 @@ export interface NeedsApprovalContext<TInput = Record<string, unknown>> {
|
|
|
39
39
|
readonly toolInput?: ApprovalToolInput<TInput>;
|
|
40
40
|
readonly toolName: string;
|
|
41
41
|
}
|
|
42
|
-
|
|
43
|
-
* Ash-owned shape for the model-facing tool result produced by
|
|
44
|
-
* {@link ToolDefinition.toModelOutput}. Structurally compatible with the
|
|
45
|
-
* AI SDK's `ToolResultOutput` so the harness can forward it without
|
|
46
|
-
* conversion.
|
|
47
|
-
*/
|
|
48
|
-
export type ToolModelOutput = {
|
|
49
|
-
readonly type: "text";
|
|
50
|
-
readonly value: string;
|
|
51
|
-
} | {
|
|
52
|
-
readonly type: "json";
|
|
53
|
-
readonly value: unknown;
|
|
54
|
-
};
|
|
42
|
+
export type { ToolModelOutput } from "#shared/tool-definition.js";
|
|
55
43
|
/**
|
|
56
44
|
* Result returned from a {@link ToolRetentionPolicy} function.
|
|
57
45
|
*
|
|
@@ -140,6 +128,13 @@ export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefi
|
|
|
140
128
|
};
|
|
141
129
|
/**
|
|
142
130
|
* Defines a tool configuration.
|
|
131
|
+
*
|
|
132
|
+
* Used for both static tools (default export from `agent/tools/*.ts`)
|
|
133
|
+
* and as the entry wrapper inside `defineDynamic` resolvers.
|
|
134
|
+
*
|
|
135
|
+
* For static tools, the runtime tool name is the filename slug.
|
|
136
|
+
* For dynamic entries, `defineTool` stamps a brand that the
|
|
137
|
+
* lifecycle code validates — raw object literals are rejected.
|
|
143
138
|
*/
|
|
144
139
|
export declare function defineTool<TSchema extends StandardJSONSchemaV1<unknown, unknown>, TOutput>(definition: {
|
|
145
140
|
description: ToolDefinition<unknown, unknown>["description"];
|
|
@@ -160,72 +155,37 @@ export declare function defineTool<TOutput>(definition: {
|
|
|
160
155
|
onCompact?: ToolDefinition<unknown, unknown>["onCompact"];
|
|
161
156
|
}): ToolDefinition<Record<string, unknown>, TOutput>;
|
|
162
157
|
export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
|
|
163
|
-
export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
|
|
164
|
-
export declare function defineTool(definition: {
|
|
165
|
-
readonly events: DynamicSingleToolEvents;
|
|
166
|
-
}): DynamicToolSentinel;
|
|
167
158
|
/**
|
|
168
159
|
* Defines a dynamic tool set resolved at runtime. The file's
|
|
169
|
-
* path-derived slug becomes the tool name
|
|
170
|
-
*
|
|
171
|
-
* entry, the tool takes the file's name directly.
|
|
172
|
-
*
|
|
173
|
-
* Uses the same `events` object shape as {@link defineHook}:
|
|
160
|
+
* path-derived slug becomes the tool name; the handler's return
|
|
161
|
+
* shape determines naming:
|
|
174
162
|
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* "session.started": async (event, ctx) => ({
|
|
179
|
-
* export: { description: "...", inputSchema: {...}, execute: ... },
|
|
180
|
-
* query: { description: "...", inputSchema: {...}, execute: ... },
|
|
181
|
-
* }),
|
|
182
|
-
* },
|
|
183
|
-
* });
|
|
184
|
-
* ```
|
|
185
|
-
*/
|
|
186
|
-
export declare function defineTools(definition: {
|
|
187
|
-
readonly events: DynamicToolEvents;
|
|
188
|
-
}): DynamicToolsSentinel;
|
|
189
|
-
/**
|
|
190
|
-
* Typed wrapper for a single entry inside a `defineTools` resolver.
|
|
191
|
-
* Mirrors the AI SDK's `tool()` pattern — an identity function at
|
|
192
|
-
* runtime that captures `TSchema` at the type level so `execute(input)`
|
|
193
|
-
* is inferred from the schema.
|
|
163
|
+
* - Return a single `defineTool(...)` → tool named after the file slug.
|
|
164
|
+
* - Return a `Record<string, defineTool(...)>` → tools named `slug__key`.
|
|
165
|
+
* - Return `null` → no tools for this event.
|
|
194
166
|
*
|
|
195
167
|
* ```ts
|
|
196
|
-
* import {
|
|
168
|
+
* import { defineDynamic, defineTool } from "experimental-ash/tools";
|
|
197
169
|
* import { z } from "zod";
|
|
198
170
|
*
|
|
199
|
-
* export default
|
|
171
|
+
* export default defineDynamic({
|
|
200
172
|
* events: {
|
|
201
|
-
* "session.started": async () => ({
|
|
202
|
-
*
|
|
203
|
-
* description: "
|
|
204
|
-
* inputSchema: z.object({
|
|
173
|
+
* "session.started": async (event, ctx) => ({
|
|
174
|
+
* export: defineTool({
|
|
175
|
+
* description: "Export data",
|
|
176
|
+
* inputSchema: z.object({ format: z.string() }),
|
|
205
177
|
* async execute(input) {
|
|
206
|
-
*
|
|
207
|
-
* return fetchWeather(input.city);
|
|
178
|
+
* return doExport(input.format);
|
|
208
179
|
* },
|
|
209
180
|
* }),
|
|
210
181
|
* }),
|
|
211
182
|
* },
|
|
212
183
|
* });
|
|
213
184
|
* ```
|
|
214
|
-
*
|
|
215
|
-
* Without `tool()`, `execute(input)` defaults to
|
|
216
|
-
* `Record<string, unknown>`. Use `tool()` when you want schema-
|
|
217
|
-
* inferred types.
|
|
218
185
|
*/
|
|
219
|
-
export declare function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
execute(input: StandardJSONSchemaV1.InferOutput<TSchema>, ctx: ToolContext): TOutput | Promise<TOutput>;
|
|
223
|
-
}): DynamicToolEntry<StandardJSONSchemaV1.InferOutput<TSchema>, TOutput>;
|
|
224
|
-
export declare function tool<TOutput>(entry: {
|
|
225
|
-
description: string;
|
|
226
|
-
inputSchema: JsonObject;
|
|
227
|
-
execute(input: Record<string, unknown>, ctx: ToolContext): TOutput | Promise<TOutput>;
|
|
228
|
-
}): DynamicToolEntry<Record<string, unknown>, TOutput>;
|
|
186
|
+
export declare function defineDynamic(definition: {
|
|
187
|
+
readonly events: DynamicEvents;
|
|
188
|
+
}): DynamicSentinel;
|
|
229
189
|
/**
|
|
230
190
|
* Marker discriminator written into every {@link DisabledToolSentinel}.
|
|
231
191
|
*/
|
|
@@ -248,4 +208,3 @@ export declare function disableTool(): DisabledToolSentinel;
|
|
|
248
208
|
* produced by {@link disableTool}.
|
|
249
209
|
*/
|
|
250
210
|
export declare function isDisabledToolSentinel(value: unknown): value is DisabledToolSentinel;
|
|
251
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{DYNAMIC_SENTINEL_KIND,TOOL_BRAND}from"#shared/dynamic-tool-definition.js";import{stampDefinitionKey}from"#public/tool-result-narrowing.js";function defineTool(e){return Object.assign(e,{[TOOL_BRAND]:!0}),stampDefinitionKey(e,`tool:${e.description}`),e}function defineDynamic(t){let n={kind:DYNAMIC_SENTINEL_KIND,events:t.events};return stampDefinitionKey(n,`dynamic:${Object.keys(t.events).join(`,`)}`),n}const DISABLED_TOOL_SENTINEL_KIND=`ash:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}export{defineDynamic,defineTool,disableTool,isDisabledToolSentinel};
|
|
@@ -1,4 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Instrumentation authoring helpers for `agent/instrumentation.ts`.
|
|
3
|
-
*/
|
|
4
|
-
export { defineInstrumentation, type InstrumentationDefinition, type InstrumentationSetupContext, } from "#public/definitions/instrumentation.js";
|
|
1
|
+
export * from "#public/definitions/instrumentation.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export*from"#public/definitions/instrumentation.js";export{};
|
|
@@ -3,3 +3,5 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type { SkillFile, SkillHandle } from "#execution/skills/types.js";
|
|
5
5
|
export { defineSkill, type NamedSkillDefinition, type SkillDefinition, type SkillFileContent, type SkillPackageDefinition, } from "#public/definitions/skill.js";
|
|
6
|
+
export { defineDynamic } from "#public/definitions/tool.js";
|
|
7
|
+
export type { DynamicResolveContext, DynamicSentinel } from "#shared/dynamic-tool-definition.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineSkill}from"#public/definitions/skill.js";export{defineSkill};
|
|
1
|
+
import{defineDynamic}from"#public/definitions/tool.js";import{defineSkill}from"#public/definitions/skill.js";export{defineDynamic,defineSkill};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool authoring helpers for `agent/tools/*.ts` files.
|
|
3
3
|
*/
|
|
4
|
-
export { type CompactionInput, type CompactionHookResult, type DisabledToolSentinel,
|
|
5
|
-
export type { DynamicToolEntry, DynamicToolEvents,
|
|
4
|
+
export { type CompactionInput, type CompactionHookResult, type DisabledToolSentinel, defineDynamic, defineTool, disableTool, isDisabledToolSentinel, type NeedsApprovalContext, type RetentionSummary, type ToolDefinition, type ToolContext, type ToolModelOutput, type ToolRetentionPolicy, } from "#public/definitions/tool.js";
|
|
5
|
+
export type { DynamicToolEntry, DynamicEvents, DynamicToolEvents, DynamicResolveContext, DynamicSentinel, DynamicToolSet, DynamicToolResult, } from "#shared/dynamic-tool-definition.js";
|
|
6
6
|
export { type SessionContext } from "#public/definitions/callback-context.js";
|
|
7
7
|
export { toolResultFrom, type MatchedConnectionResult, type MatchedToolResult, type ToolResultFromFn, } from "#public/tool-result-narrowing.js";
|
|
8
8
|
export { type DefineBashToolInput, defineBashTool } from "#public/tools/define-bash-tool.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineTool,
|
|
1
|
+
import{defineDynamic,defineTool,disableTool,isDisabledToolSentinel}from"#public/definitions/tool.js";import{toolResultFrom}from"#public/tool-result-narrowing.js";import{defineBashTool}from"#public/tools/define-bash-tool.js";import{defineGlobTool}from"#public/tools/define-glob-tool.js";import{defineGrepTool}from"#public/tools/define-grep-tool.js";import{defineReadFileTool}from"#public/tools/define-read-file-tool.js";import{defineWriteFileTool}from"#public/tools/define-write-file-tool.js";export{defineBashTool,defineDynamic,defineGlobTool,defineGrepTool,defineReadFileTool,defineTool,defineWriteFileTool,disableTool,isDisabledToolSentinel,toolResultFrom};
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{CODE_MODE_TOOL_NAME}from"#shared/code-mode.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{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 r=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,r),r}function createMockModelResult(e,t){let n=getLastAuthoredToolResult(e.prompt);if(n!==null){let r=formatToolResultReply(n,e.prompt);return createBootstrapGenerateResult({inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{CODE_MODE_TOOL_NAME}from"#shared/code-mode.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{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 r=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,r),r}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;let i=formatToolResultReply(n,e.prompt);return createBootstrapGenerateResult({inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(i),text:i})}let r=createSkillLoadResult(e.prompt,t);if(r!==null)return r;let i=createAuthoredToolCallResult(e,t);if(i!==null)return i;let o=createAssistantMessage(e.prompt);return createBootstrapGenerateResult({inputTokens:estimateTokenCount(getPromptText(e.prompt)),modelId:t,outputTokens:estimateTokenCount(o),text:o})}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:`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
|
|
2
2
|
`))return[];let n=t.split(`
|
|
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 a=n.find(e=>e!==BOOTSTRAP_RUNTIME_SYSTEM_PROMPT&&e!==`Available skills`);return a===void 0?[]:[a]});return[...new Set(n)]}function
|
|
4
|
-
`)
|
|
5
|
-
`))
|
|
6
|
-
`).slice(1)){let e=parseAvailableSkill(n);e!==null&&t.set(e.name,e)}}return[...t.values()]}function parseAvailableSkill(e){let t=/^- (.+?): (.+?)(?: \(path: (.+)\))?$/.exec(e.trim());return t?.[1]&&t[2]?{description:t[2],name:t[1]}:null}function findRelevantTool(e,t){let n=normalizeText(t);return/\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}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(`
|
|
7
|
-
`)){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 findRelevantSkill(e,t){let n=normalizeText(t);for(let t of e)if(n.includes(normalizeText(t.name)))return t;return/\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}function normalizeText(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,` `).trim()}function resolveSystemProbe(e){let t=e.filter(e=>e.role===`system`).map(e=>getPromptContentText(e.content)).join(`
|
|
8
|
-
`);return/hmr-probe:\s*([^\n]+)/iu.exec(t)?.[1]?.trim()||null}function resolveWeatherCity(e){let t=/"city"\s*:\s*"([^"]+)"/u.exec(e);return t?.[1]?t[1].trim():(/\b(?:in|for)\s+([A-Za-z][A-Za-z\s.-]*?)(?:[?.!,]|$)/u.exec(e)??/\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/u.exec(e))?.[1]?.trim()||`Brooklyn`}function isWeatherPayload(e){return bootstrapWeatherPayloadSchema.safeParse(e).success}function formatToolOutput(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}export{ASH_MOCK_AUTHORED_MODELS_ENV,createMockAuthoredRuntimeModel,resolveMockAuthoredRuntimeModel,shouldMockAuthoredRuntimeModels};
|
|
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 a=n.find(e=>e!==BOOTSTRAP_RUNTIME_SYSTEM_PROMPT&&e!==`Available skills`);return a===void 0?[]:[a]});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
|
+
`)){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(`
|
|
5
|
+
`);return/hmr-probe:\s*([^\n]+)/iu.exec(t)?.[1]?.trim()||null}function resolveWeatherCity(e){let t=/"city"\s*:\s*"([^"]+)"/u.exec(e);return t?.[1]?t[1].trim():(/\b(?:in|for)\s+([A-Za-z][A-Za-z\s.-]*?)(?:[?.!,]|$)/u.exec(e)??/\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/u.exec(e))?.[1]?.trim()||`Brooklyn`}function resolveLookupTopic(e){return/\btopic\s+['"]?([A-Za-z0-9_.-]+)['"]?/u.exec(e)?.[1]??`demo`}function isWeatherPayload(e){return bootstrapWeatherPayloadSchema.safeParse(e).success}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function formatToolOutput(e){if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}export{ASH_MOCK_AUTHORED_MODELS_ENV,createMockAuthoredRuntimeModel,resolveMockAuthoredRuntimeModel,shouldMockAuthoredRuntimeModels};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BootstrapPrompt } from "#runtime/agent/bootstrap-model-utils.js";
|
|
2
|
+
interface AvailableBootstrapSkill {
|
|
3
|
+
readonly description: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getAvailableSkills(prompt: BootstrapPrompt): AvailableBootstrapSkill[];
|
|
7
|
+
export declare function findRelevantSkill(skills: readonly AvailableBootstrapSkill[], message: string): AvailableBootstrapSkill | null;
|
|
8
|
+
export declare function getActivatedSkillIds(prompt: BootstrapPrompt): string[];
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{getPromptContentText}from"#runtime/agent/bootstrap-model-utils.js";function getAvailableSkills(t){let n=new Map;for(let r of t){if(r.role!==`system`)continue;let t=getPromptContentText(r.content);if(t.startsWith(`Available skills
|
|
2
|
+
`))for(let e of t.split(`
|
|
3
|
+
`).slice(1)){let t=parseAvailableSkill(e);t!==null&&n.set(t.name,t)}}return[...n.values()]}function findRelevantSkill(e,t){let n=normalizeText(t);for(let t of e)if(n.includes(normalizeText(t.name)))return t;return/\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}function getActivatedSkillIds(t){return t.filter(e=>e.role===`system`).flatMap(t=>getPromptContentText(t.content).split(`
|
|
4
|
+
`).map(e=>e.trim()).flatMap(e=>{let t=/^Skill \((.+)\)$/.exec(e);return t?.[1]===void 0?[]:[t[1]]}))}function parseAvailableSkill(e){let t=/^- (.+?): (.+?)(?: \(path: (.+)\))?$/.exec(e.trim());return t?.[1]&&t[2]?{description:t[2],name:t[1]}:null}function normalizeText(e){return e.toLowerCase().replace(/[^a-z0-9]+/gu,` `).trim()}export{findRelevantSkill,getActivatedSkillIds,getAvailableSkills};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import "#internal/workflow/builtins.js";
|
|
2
|
+
/**
|
|
3
|
+
* Maximum byte size for an attribute value on a workflow run.
|
|
4
|
+
*
|
|
5
|
+
* Local mirror of `ATTRIBUTE_VALUE_MAX_BYTES` from `@workflow/world`
|
|
6
|
+
* (source of truth: `packages/world/src/attributes.ts` in the workflow
|
|
7
|
+
* repo). The value is duplicated rather than imported because
|
|
8
|
+
* `@workflow/core` — the only workflow surface bundled into the
|
|
9
|
+
* workflow body — does not re-export it, and pulling `@workflow/world`
|
|
10
|
+
* into the body bundle would drag in the full zod attribute validator
|
|
11
|
+
* (the same reason `workflow-core-shim.ts` skips runtime validation in
|
|
12
|
+
* its `experimental_setAttributes`).
|
|
13
|
+
*
|
|
14
|
+
* Strings emitted through {@link setAshAttributes} are truncated to this
|
|
15
|
+
* byte count before they reach the runtime so the validator never
|
|
16
|
+
* rejects a tag for length alone.
|
|
17
|
+
*
|
|
18
|
+
* Drift is conservative-by-construction: if workflow LOWERS the limit,
|
|
19
|
+
* over-long values are rejected and `setAshAttributes` swallows the
|
|
20
|
+
* failure (warn-once-per-process) — dashboards see a missing tag, never
|
|
21
|
+
* a broken agent; if workflow RAISES it, titles are merely shorter than
|
|
22
|
+
* necessary. `emit.drift.test.ts` asserts equality against the real
|
|
23
|
+
* `@workflow/world` export (a devDependency) so CI fails loudly the day
|
|
24
|
+
* the constants diverge.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ASH_ATTRIBUTE_VALUE_MAX_BYTES = 256;
|
|
27
|
+
/**
|
|
28
|
+
* Attribute value the caller wants to write. `undefined` values are
|
|
29
|
+
* stripped before the runtime call; numbers are stringified; strings
|
|
30
|
+
* are truncated to {@link ASH_ATTRIBUTE_VALUE_MAX_BYTES}.
|
|
31
|
+
*/
|
|
32
|
+
export type AshAttributeValue = string | number | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Truncates a string so its UTF-8 byte length is at most `maxBytes`
|
|
35
|
+
* without splitting a multi-byte character.
|
|
36
|
+
*
|
|
37
|
+
* The workflow runtime measures attribute values in UTF-8 bytes, not
|
|
38
|
+
* code units, so `value.slice(0, maxBytes)` is not safe — a JS string
|
|
39
|
+
* with two-byte characters (e.g. emoji surrogate pairs) can serialize
|
|
40
|
+
* to twice as many bytes as code units. We re-encode the truncated
|
|
41
|
+
* candidate after each drop and shrink one code unit at a time when
|
|
42
|
+
* the candidate's last character straddles the byte budget.
|
|
43
|
+
*/
|
|
44
|
+
export declare function truncateForTag(value: string, maxBytes?: number): string;
|
|
45
|
+
/**
|
|
46
|
+
* Writes a batch of Ash-owned attributes to the active workflow run.
|
|
47
|
+
*
|
|
48
|
+
* Reserved-namespace contract:
|
|
49
|
+
* - All keys must use the `$ash.` prefix (the workflow runtime would
|
|
50
|
+
* otherwise reject them as user-space writes into the reserved `$`
|
|
51
|
+
* namespace).
|
|
52
|
+
* - The call always opts in via `{ allowReservedAttributes: true }`
|
|
53
|
+
* on behalf of the framework — authored code never calls this helper
|
|
54
|
+
* directly.
|
|
55
|
+
*
|
|
56
|
+
* Value normalization:
|
|
57
|
+
* - `undefined` entries are dropped so callers can build attribute
|
|
58
|
+
* maps with optional fields (`$ash.subagent` is only present on
|
|
59
|
+
* subagent roots, for example).
|
|
60
|
+
* - Numbers are stringified (the runtime stores all values as strings).
|
|
61
|
+
* - Strings are truncated to {@link ASH_ATTRIBUTE_VALUE_MAX_BYTES} via
|
|
62
|
+
* {@link truncateForTag} so a long free-form value (e.g. `$ash.title`)
|
|
63
|
+
* can never trip the runtime's per-value byte budget.
|
|
64
|
+
*
|
|
65
|
+
* Failure policy: tag writes are observability metadata, not load-bearing
|
|
66
|
+
* state. A failure inside the runtime (transient network, schema bug,
|
|
67
|
+
* missing world adapter) is logged once per process and then swallowed
|
|
68
|
+
* so the Ash session it tagged is unaffected.
|
|
69
|
+
*
|
|
70
|
+
* Must be called from inside a `"use workflow"` or `"use step"` body —
|
|
71
|
+
* the runtime throws a `FatalError` outside those contexts.
|
|
72
|
+
*/
|
|
73
|
+
export declare function setAshAttributes(attrs: Record<string, AshAttributeValue>): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"#internal/workflow/builtins.js";const ASH_ATTRIBUTE_VALUE_MAX_BYTES=256;let WARNED_ABOUT_TAG_FAILURE=!1;function truncateForTag(e,t=256){if(t<=0)return``;let n=new TextEncoder;if(n.encode(e).length<=t)return e;let r=e.length;for(;r>0;){let i=e.charCodeAt(r-1);if(i>=55296&&i<=56319){--r;continue}let a=e.slice(0,r);if(n.encode(a).length<=t)return a;--r}return``}async function setAshAttributes(e){let n={};for(let[t,r]of Object.entries(e))r!==void 0&&(n[t]=truncateForTag(typeof r==`number`?String(r):r));if(Object.keys(n).length!==0)try{let{experimental_setAttributes:e}=await import(`#compiled/@workflow/core/index.js`);await e(n,{allowReservedAttributes:!0})}catch(e){WARNED_ABOUT_TAG_FAILURE||(WARNED_ABOUT_TAG_FAILURE=!0,console.warn(`[ash] setAshAttributes failed; suppressing further warnings this process.`,{keys:Object.keys(n),error:e.message}))}}export{ASH_ATTRIBUTE_VALUE_MAX_BYTES,setAshAttributes,truncateForTag};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAdapterKind}from"#channel/adapter.js";import{SUBAGENT_ADAPTER}from"#execution/subagent-adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(e,t){let n=t,r=e.adaptersByKind.get(n.kind);if(r===void 0)throw Error(`Unknown adapter kind: "${n.kind}". Declare the adapter on the route that starts this session so the runtime can rehydrate it.`);return{...r,state:n.state}}function requireAdapterKind(t,n){let r=getAdapterKind(t);if(typeof r!=`string`||r.length===0)throw new RuntimeRegistryError(`adapter`,"Adapters must declare a non-empty `kind` field.",{entryName:`unknown`,logicalPath:n?.logicalPath,sourceId:n?.sourceId});return r}function carriesAdapterBehavior(e){if(e.deliver!==void 0||e.fetchFile!==void 0||e.createAdapterContext!==void 0)return!0;for(let[t,n]of Object.entries(e))if(!ADAPTER_NON_EVENT_FIELDS.has(t)&&typeof n==`function`)return!0;return!1}export{createRuntimeAdapterRegistry,deserializeRuntimeAdapter};
|
|
1
|
+
import{getAdapterKind}from"#channel/adapter.js";import{SUBAGENT_ADAPTER}from"#execution/subagent-adapter.js";import{SCHEDULE_ADAPTER}from"#channel/schedule.js";import{HTTP_ADAPTER}from"#channel/http.js";import{RuntimeRegistryError}from"#internal/runtime-registry.js";const FRAMEWORK_ADAPTERS=[HTTP_ADAPTER,SUBAGENT_ADAPTER,SCHEDULE_ADAPTER],ADAPTER_NON_EVENT_FIELDS=new Set([`kind`,`state`,`deliver`,`createAdapterContext`,`fetchFile`,`instrumentation`]);function createRuntimeAdapterRegistry(e){let t=new Map,n=new Set;for(let e of FRAMEWORK_ADAPTERS){let r=requireAdapterKind(e);n.add(r),t.set(r,e)}for(let r of e.channels){if(r.adapter===void 0)continue;let e={logicalPath:r.logicalPath,sourceId:r.sourceId},i=r.adapter,a=requireAdapterKind(i,e);if(n.has(a)){if(carriesAdapterBehavior(i))throw new RuntimeRegistryError(`adapter`,`Channel adapter kind "${a}" is reserved by the framework. A route-declared adapter may share a framework kind only as a pass-through with no \`deliver\` hook, event handlers, \`attachments\` resolver, or \`createAdapterContext\` factory. Use a custom \`kind\` to add channel-specific behavior.`,{...e,entryName:a});continue}t.set(a,i)}return{adaptersByKind:t}}function deserializeRuntimeAdapter(e,t){let n=t,r=e.adaptersByKind.get(n.kind);if(r===void 0)throw Error(`Unknown adapter kind: "${n.kind}". Declare the adapter on the route that starts this session so the runtime can rehydrate it.`);return{...r,state:n.state}}function requireAdapterKind(t,n){let r=getAdapterKind(t);if(typeof r!=`string`||r.length===0)throw new RuntimeRegistryError(`adapter`,"Adapters must declare a non-empty `kind` field.",{entryName:`unknown`,logicalPath:n?.logicalPath,sourceId:n?.sourceId});return r}function carriesAdapterBehavior(e){if(e.deliver!==void 0||e.fetchFile!==void 0||e.createAdapterContext!==void 0)return!0;for(let[t,n]of Object.entries(e))if(!ADAPTER_NON_EVENT_FIELDS.has(t)&&typeof n==`function`)return!0;return!1}export{createRuntimeAdapterRegistry,deserializeRuntimeAdapter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{contextStorage}from"#context/container.js";import{
|
|
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,9 +1,11 @@
|
|
|
1
1
|
import type { CodeModeInterrupt, CodeModeInterruptExecutionContext, CodeModeInterruptPayload } from "#shared/code-mode.js";
|
|
2
|
+
import type { AuthorizationChallenge } from "#harness/authorization.js";
|
|
2
3
|
import type { JsonValue } from "#public/types/json.js";
|
|
3
4
|
export declare const CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND = "ash.connection-auth";
|
|
4
5
|
export interface CodeModeConnectionAuthPayload extends CodeModeInterruptPayload {
|
|
5
6
|
readonly kind: typeof CODE_MODE_CONNECTION_AUTH_INTERRUPT_KIND;
|
|
6
7
|
readonly args: JsonValue;
|
|
8
|
+
readonly challenges?: readonly AuthorizationChallenge[];
|
|
7
9
|
readonly connectionName: string;
|
|
8
10
|
readonly toolName: string;
|
|
9
11
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ResolvedDynamicToolResolver } from "#runtime/types.js";
|
|
2
|
+
import type { DynamicToolEvents } from "#shared/dynamic-tool-definition.js";
|
|
3
|
+
import type { ModelMessage } from "ai";
|
|
4
|
+
interface ConnectionSearchResultItem {
|
|
5
|
+
readonly connection: string;
|
|
6
|
+
readonly description: string;
|
|
7
|
+
readonly error?: string;
|
|
8
|
+
readonly inputSchema?: Record<string, unknown>;
|
|
9
|
+
readonly needsAuthorization?: boolean;
|
|
10
|
+
readonly tool?: string;
|
|
11
|
+
readonly qualifiedName?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extracts connection search results from conversation history.
|
|
15
|
+
* Scans tool-result messages for `connection_search` results and
|
|
16
|
+
* returns deduplicated tool metadata (latest result wins per qualifiedName).
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractDiscoveredTools(messages: readonly ModelMessage[]): ConnectionSearchResultItem[];
|
|
19
|
+
/**
|
|
20
|
+
* Creates the connection search dynamic tool resolver events.
|
|
21
|
+
*
|
|
22
|
+
* The resolver subscribes to `step.started` so it re-derives the tool
|
|
23
|
+
* set from conversation history on every step. After compaction, old
|
|
24
|
+
* `connection_search` results disappear from messages and discovered
|
|
25
|
+
* tools naturally drop from the toolset — no `onCompact` hook needed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createConnectionSearchEvents(): DynamicToolEvents;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a `ResolvedDynamicToolResolver` for the framework connection
|
|
30
|
+
* search tool. Used by graph resolution to register alongside authored
|
|
31
|
+
* dynamic tool resolvers.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createConnectionSearchResolver(): ResolvedDynamicToolResolver;
|
|
34
|
+
export {};
|