experimental-ash 0.42.0 → 0.44.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 +37 -0
- package/bin/ash.js +1 -0
- package/dist/docs/internals/mechanical-invariants.md +16 -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 +142 -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 +50 -7
- 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 +39 -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/compiled-channel.d.ts +4 -1
- package/dist/src/channel/compiled-channel.js +1 -1
- package/dist/src/channel/instrumentation.d.ts +10 -0
- package/dist/src/channel/instrumentation.js +1 -0
- package/dist/src/channel/routes.d.ts +8 -10
- 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/compiled/.vendor-stamp.json +1 -1
- package/dist/src/compiled/@vercel/sandbox/index.d.ts +12 -19
- package/dist/src/compiled/@vercel/sandbox/network-policy.d.ts +161 -0
- package/dist/src/compiled/just-bash/index.d.ts +15 -2
- package/dist/src/compiled/just-bash/network/types.d.ts +155 -0
- package/dist/src/compiler/artifacts.d.ts +1 -0
- package/dist/src/compiler/artifacts.js +1 -1
- package/dist/src/compiler/channel-instrumentation-types.d.ts +8 -0
- package/dist/src/compiler/channel-instrumentation-types.js +2 -0
- 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/bindings/local.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/prewarm.js +1 -1
- package/dist/src/execution/sandbox/session.d.ts +6 -1
- package/dist/src/execution/sandbox/session.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/packages/ash-scaffold/src/web-template.js +1 -0
- package/dist/src/public/channels/discord/discordChannel.d.ts +5 -2
- package/dist/src/public/channels/index.d.ts +1 -1
- 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 +12 -8
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +5 -2
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +5 -2
- 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 +12 -3
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/defineChannel.d.ts +17 -4
- 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 +1 -66
- package/dist/src/public/definitions/instrumentation.js +1 -1
- 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 +175 -1
- package/dist/src/public/instrumentation/index.js +1 -1
- package/dist/src/public/sandbox/index.d.ts +1 -0
- 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-channel.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/sandbox-network-policy.d.ts +23 -0
- package/dist/src/shared/sandbox-network-policy.js +1 -0
- package/dist/src/shared/sandbox-session.d.ts +15 -0
- 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
|
@@ -75,6 +75,8 @@ export interface FetchFileResult {
|
|
|
75
75
|
readonly mediaType?: string;
|
|
76
76
|
readonly filename?: string;
|
|
77
77
|
}
|
|
78
|
+
export type ChannelInstrumentationMetadata = Readonly<Record<string, unknown>>;
|
|
79
|
+
export type ChannelInstrumentationMetadataProjector = (state: Record<string, unknown> | undefined) => ChannelInstrumentationMetadata;
|
|
78
80
|
/**
|
|
79
81
|
* Plain-object channel adapter with durable state, an optional inbound
|
|
80
82
|
* delivery hook, event handlers, and optional attachment resolution.
|
|
@@ -122,6 +124,17 @@ export type ChannelAdapter<TCtx extends ChannelAdapterContext<any> = ChannelAdap
|
|
|
122
124
|
* construction time.
|
|
123
125
|
*/
|
|
124
126
|
readonly fetchFile?: (url: string) => Promise<Buffer | FetchFileResult | null>;
|
|
127
|
+
/**
|
|
128
|
+
* Framework-owned observability projection for the active channel.
|
|
129
|
+
*
|
|
130
|
+
* Channel implementations decide which state fields are safe and
|
|
131
|
+
* meaningful to expose to instrumentation callbacks. The harness reads
|
|
132
|
+
* the resulting projection through a seed context key rather than
|
|
133
|
+
* inspecting adapter state directly.
|
|
134
|
+
*/
|
|
135
|
+
readonly instrumentation?: {
|
|
136
|
+
readonly metadata?: ChannelInstrumentationMetadataProjector;
|
|
137
|
+
};
|
|
125
138
|
} & ChannelEventHandlers<TCtx>;
|
|
126
139
|
/**
|
|
127
140
|
* Produces the default {@link StepInput} when no custom adapter `deliver`
|
|
@@ -3,7 +3,7 @@ import type { RouteHandler, SendFn } from "#channel/routes.js";
|
|
|
3
3
|
import type { Session } from "#channel/session.js";
|
|
4
4
|
import type { SessionAuthContext } from "#channel/types.js";
|
|
5
5
|
export declare const CHANNEL_SENTINEL: "ash:channel";
|
|
6
|
-
export interface CompiledChannel<TState = undefined, TReceiveArgs = Record<string, unknown>> {
|
|
6
|
+
export interface CompiledChannel<TState = undefined, TReceiveArgs = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
|
|
7
7
|
readonly __kind: typeof CHANNEL_SENTINEL;
|
|
8
8
|
readonly routes: readonly {
|
|
9
9
|
method: string;
|
|
@@ -11,6 +11,7 @@ export interface CompiledChannel<TState = undefined, TReceiveArgs = Record<strin
|
|
|
11
11
|
handler: RouteHandler<TState>;
|
|
12
12
|
}[];
|
|
13
13
|
readonly adapter: ChannelAdapter<any>;
|
|
14
|
+
readonly __metadata?: TMetadata;
|
|
14
15
|
readonly receive?: (input: {
|
|
15
16
|
readonly message: string;
|
|
16
17
|
readonly args: Readonly<TReceiveArgs>;
|
|
@@ -20,3 +21,5 @@ export interface CompiledChannel<TState = undefined, TReceiveArgs = Record<strin
|
|
|
20
21
|
}) => Promise<Session>;
|
|
21
22
|
}
|
|
22
23
|
export declare function isCompiledChannel(value: unknown): value is CompiledChannel;
|
|
24
|
+
export declare function getChannelInstrumentationKind(value: unknown): string | undefined;
|
|
25
|
+
export declare function setChannelInstrumentationKind(channel: CompiledChannel, kind: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const CHANNEL_SENTINEL=`ash:channel
|
|
1
|
+
const CHANNEL_SENTINEL=`ash:channel`,CHANNEL_INSTRUMENTATION_KIND=Symbol.for(`ash.channel.instrumentationKind`);function isCompiledChannel(e){return typeof e==`object`&&!!e&&e.__kind===`ash:channel`}function getChannelInstrumentationKind(e){if(!isCompiledChannel(e))return;let t=Reflect.get(e,CHANNEL_INSTRUMENTATION_KIND);if(typeof t==`string`&&t.length>0)return t;let n=e.adapter.kind;return typeof n==`string`&&n.startsWith(`channel:`)?n:void 0}function setChannelInstrumentationKind(e,t){Object.defineProperty(e,CHANNEL_INSTRUMENTATION_KIND,{configurable:!0,enumerable:!1,value:t})}export{CHANNEL_SENTINEL,getChannelInstrumentationKind,isCompiledChannel,setChannelInstrumentationKind};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChannelAdapter, ChannelInstrumentationMetadata } from "#channel/adapter.js";
|
|
2
|
+
export interface ChannelInstrumentationProjection {
|
|
3
|
+
readonly kind: string;
|
|
4
|
+
readonly metadata: ChannelInstrumentationMetadata;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildChannelInstrumentationProjection(input: {
|
|
7
|
+
readonly adapter: ChannelAdapter;
|
|
8
|
+
readonly channelName?: string;
|
|
9
|
+
readonly existingKind?: string;
|
|
10
|
+
}): ChannelInstrumentationProjection;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{getAdapterKind}from"#channel/adapter.js";import{isInstrumentationChannelKind,resolveInstrumentationProjection}from"#internal/instrumentation.js";const log=createLogger(`channel.instrumentation`);function buildChannelInstrumentationProjection(e){let{adapter:t,channelName:n,existingKind:r}=e;return{kind:resolveKind({adapter:t,channelName:n,existingKind:r}),metadata:resolveMetadata(t)}}function resolveKind(e){let{adapter:r,channelName:i,existingKind:a}=e;if(a!==void 0)return a;if(i!==void 0&&i.length>0)return`channel:${i}`;let o=getAdapterKind(r);return isInstrumentationChannelKind(o)?o:`channel:${o}`}function resolveMetadata(e){let n=e.instrumentation?.metadata;return n===void 0?{}:resolveInstrumentationProjection({invoke:()=>n(e.state),log,source:getAdapterKind(e)})??{}}export{buildChannelInstrumentationProjection};
|
|
@@ -32,6 +32,12 @@ export interface SendPayload {
|
|
|
32
32
|
readonly modelContext?: readonly ModelMessage[];
|
|
33
33
|
}
|
|
34
34
|
export type SendFn<TState = undefined> = (input: string | UserContent | SendPayload, options: SendOptions<TState>) => Promise<Session>;
|
|
35
|
+
type BaseSendOptions = {
|
|
36
|
+
auth: SessionAuthContext | null;
|
|
37
|
+
callback?: SessionCallback;
|
|
38
|
+
continuationToken: string;
|
|
39
|
+
mode?: RunMode;
|
|
40
|
+
};
|
|
35
41
|
/**
|
|
36
42
|
* Options for {@link SendFn}. The channel owns its continuation-token
|
|
37
43
|
* format — pass the channel-local raw token (the framework prepends
|
|
@@ -39,16 +45,7 @@ export type SendFn<TState = undefined> = (input: string | UserContent | SendPayl
|
|
|
39
45
|
* state via {@link state}, which becomes the new session's `state`
|
|
40
46
|
* on first `runtime.run()` and is ignored on subsequent `deliver`s.
|
|
41
47
|
*/
|
|
42
|
-
export type SendOptions<TState = undefined> = TState extends undefined ? {
|
|
43
|
-
auth: SessionAuthContext | null;
|
|
44
|
-
callback?: SessionCallback;
|
|
45
|
-
continuationToken: string;
|
|
46
|
-
mode?: RunMode;
|
|
47
|
-
} : {
|
|
48
|
-
auth: SessionAuthContext | null;
|
|
49
|
-
callback?: SessionCallback;
|
|
50
|
-
continuationToken: string;
|
|
51
|
-
mode?: RunMode;
|
|
48
|
+
export type SendOptions<TState = undefined> = [TState] extends [undefined] ? BaseSendOptions : BaseSendOptions & {
|
|
52
49
|
state: TState;
|
|
53
50
|
};
|
|
54
51
|
export type GetSessionFn = (sessionId: string) => Session;
|
|
@@ -63,3 +60,4 @@ export declare function POST<TState = undefined>(path: string, handler: RouteHan
|
|
|
63
60
|
export declare function PUT<TState = undefined>(path: string, handler: RouteHandler<TState>): RouteDefinition<TState>;
|
|
64
61
|
export declare function PATCH<TState = undefined>(path: string, handler: RouteHandler<TState>): RouteDefinition<TState>;
|
|
65
62
|
export declare function DELETE<TState = undefined>(path: string, handler: RouteHandler<TState>): RouteDefinition<TState>;
|
|
63
|
+
export {};
|
package/dist/src/channel/send.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createSession}from"#channel/session.js";import{createLogger}from"#internal/logging.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";const log=createLogger(`channel.send`);function createSendFn(t,r,i){return async(a,o)=>{let s=o.auth,c=o.callback,l=o.mode??`conversation`,u=o.state,d=o.continuationToken,f=`${i}:${d}`,{message:p,inputResponses:m,modelContext:h}=normalizeSendInput(a),g=serializeUrlFilePartsInMessage(p);try{let{sessionId:n}=await t.deliver({auth:s,continuationToken:f,payload:{inputResponses:m,message:g,modelContext:h}});return createSession(n,d,t)}catch(e){isRuntimeNoActiveSessionError(e)||log.warn(`deliver failed, falling back to starting a new session`,{continuationToken:f})}if(m&&m.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let _=u?{...r,state:{...r.state,...u}}:r;return createSession((await t.run({adapter:_,auth:s,capabilities:l===`conversation`?{requestInput:!0}:void 0,callback:c,continuationToken:f,input:{message:g??``,modelContext:h},mode:l})).sessionId,d,t)}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,n=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?n:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};
|
|
1
|
+
import{createSession}from"#channel/session.js";import{createLogger}from"#internal/logging.js";import{isRuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{serializeUrlFilePart}from"#internal/attachments/url-refs.js";const log=createLogger(`channel.send`);function createSendFn(t,r,i){return async(a,o)=>{let s=o.auth,c=o.callback,l=o.mode??`conversation`,u=o.state,d=o.continuationToken,f=`${i}:${d}`,{message:p,inputResponses:m,modelContext:h}=normalizeSendInput(a),g=serializeUrlFilePartsInMessage(p);try{let{sessionId:n}=await t.deliver({auth:s,continuationToken:f,payload:{inputResponses:m,message:g,modelContext:h}});return createSession(n,d,t)}catch(e){isRuntimeNoActiveSessionError(e)||log.warn(`deliver failed, falling back to starting a new session`,{continuationToken:f})}if(m&&m.length>0)throw Error(`Cannot deliver inputResponses — the target session was not found via continuation token.`);let _=u?{...r,state:{...r.state,...u}}:r;return createSession((await t.run({adapter:_,auth:s,capabilities:l===`conversation`?{requestInput:!0}:void 0,channelName:i,callback:c,continuationToken:f,input:{message:g??``,modelContext:h},mode:l})).sessionId,d,t)}}function serializeUrlFilePartsInMessage(e){if(e===void 0||typeof e==`string`)return e;let t=!1,n=e.map(e=>e.type===`file`&&e.data instanceof URL&&e.data.protocol!==`data:`?(t=!0,{...e,data:serializeUrlFilePart(e.data)}):e);return t?n:e}function normalizeSendInput(e){return typeof e==`string`||Array.isArray(e)?{message:e}:e}export{createSendFn};
|
|
@@ -5,6 +5,7 @@ import type { RuntimeActionResult } from "#runtime/actions/types.js";
|
|
|
5
5
|
import type { InputRequest, InputResponse } from "#runtime/input/types.js";
|
|
6
6
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
7
7
|
export type { ContextAccessor } from "#context/key.js";
|
|
8
|
+
export type { ChannelInstrumentationProjection } from "#channel/instrumentation.js";
|
|
8
9
|
/**
|
|
9
10
|
* Identifies one turn within a session.
|
|
10
11
|
*/
|
|
@@ -15,8 +16,17 @@ export interface SessionTurn {
|
|
|
15
16
|
/**
|
|
16
17
|
* Stable lineage metadata describing the immediate Ash parent execution that
|
|
17
18
|
* delegated the current session.
|
|
19
|
+
*
|
|
20
|
+
* `sessionId` and `turn` always describe the **immediate** parent — the
|
|
21
|
+
* agent that dispatched this child. `rootSessionId` denormalizes the top
|
|
22
|
+
* of the dispatch chain so descendants can identify the user-facing
|
|
23
|
+
* session without walking back up parent-by-parent. It is always
|
|
24
|
+
* populated at dispatch: a first-level child sets it to the top
|
|
25
|
+
* session's id (its immediate parent), and deeper descendants inherit
|
|
26
|
+
* the same root.
|
|
18
27
|
*/
|
|
19
28
|
export interface SessionParent {
|
|
29
|
+
readonly rootSessionId: string;
|
|
20
30
|
readonly sessionId: string;
|
|
21
31
|
readonly turn: SessionTurn;
|
|
22
32
|
}
|
|
@@ -162,6 +172,12 @@ export interface SessionCapabilities {
|
|
|
162
172
|
*/
|
|
163
173
|
export interface RunInput {
|
|
164
174
|
readonly adapter: ChannelAdapter<any>;
|
|
175
|
+
/**
|
|
176
|
+
* Registered channel name for root sessions started from an authored
|
|
177
|
+
* channel route. Framework runs omit this and use their framework
|
|
178
|
+
* adapter kind (`http`, `schedule`, `subagent`) directly.
|
|
179
|
+
*/
|
|
180
|
+
readonly channelName?: string;
|
|
165
181
|
/**
|
|
166
182
|
* Authenticated caller principal for this session. `null` means the
|
|
167
183
|
* request was accepted with no credentials.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RunAddToAgentOptions } from "@vercel/ash-scaffold/steps";
|
|
1
|
+
import { type DeployProjectOptions, type RunAddToAgentOptions } from "@vercel/ash-scaffold/steps";
|
|
2
2
|
import { type ChannelAddPrompter } from "@vercel/ash-scaffold/cli";
|
|
3
3
|
import { type DeploymentInfo } from "@vercel/ash-scaffold/primitives";
|
|
4
4
|
export interface CliLogger {
|
|
@@ -11,6 +11,7 @@ export interface AddChannelCommandOptions {
|
|
|
11
11
|
export interface ChannelsAddDependencies {
|
|
12
12
|
createPrompter?: () => ChannelAddPrompter;
|
|
13
13
|
detectDeployment(projectPath: string): Promise<DeploymentInfo>;
|
|
14
|
+
deployProject(options: DeployProjectOptions): Promise<void>;
|
|
14
15
|
runAddToAgent(options: RunAddToAgentOptions): Promise<void>;
|
|
15
16
|
}
|
|
16
17
|
export declare function runChannelsAddCommand(logger: CliLogger, appRoot: string, args: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"./channel-add-conflicts.js";import{isAshProject}from"../../packages/ash-scaffold/src/project.js";import{listAuthoredChannels}from"../../packages/ash-scaffold/src/channels.js";import"../../packages/ash-scaffold/src/index.js";import{detectDeployment}from"../../packages/ash-scaffold/src/primitives/detect-deployment.js";import{createAddToAgentState,runAddToAgent}from"../../packages/ash-scaffold/src/steps/run-add-to-agent.js";import"../../packages/ash-scaffold/src/steps/index.js";import{ChannelAddCancelledError,createChannelAddPrompter}from"../../packages/ash-scaffold/src/cli/channel-add-prompter.js";import"../../packages/ash-scaffold/src/cli/index.js";import"../../packages/ash-scaffold/src/primitives/index.js";const NOT_AN_AGENT_MESSAGE="No Ash agent in this directory. Run `pnpm create experimental-ash-agent`, then run this command from inside the new project.",KNOWN_CHANNEL_KINDS=[`slack`,`web`];function isChannelKind(e){return KNOWN_CHANNEL_KINDS.includes(e)}function parseChannelKind(e){if(!isChannelKind(e))throw Error(`Unknown channel kind "${e}". Known: ${KNOWN_CHANNEL_KINDS.join(`, `)}.`);return e}const defaultChannelsAddDependencies={detectDeployment,runAddToAgent};async function runAddChannelsFlow(n,r,i,o){if(r===void 0&&(!process.stdin.isTTY||!process.stdout.isTTY))throw Error(`Pass a channel kind: \`ash channels add <${KNOWN_CHANNEL_KINDS.join(`|`)}>\`.`);let s=o.createPrompter?.()??createChannelAddPrompter();s.intro(`Add channels to your Ash agent`),s.log.message(`Checking the current Vercel project...`);let c=createAddToAgentState(await o.detectDeployment(n)),l;function inspectRegistrations(){return l===void 0&&(s.log.message(`Inspecting existing channel registrations...`),l=inspectExistingChannelRegistrations(n)),l}let u=r===void 0?(await inspectRegistrations()).disabledChannelReasons:void 0;await o.runAddToAgent({prompter:s,projectPath:n,state:c,presetChannels:r===void 0?void 0:[r],disabledChannelReasons:u,force:i.force,validateSelectedChannels:async t=>{!t.includes(`web`)&&!t.includes(`slack`)||assertCanAddSelectedChannels(t,await inspectRegistrations())}}),s.outro(c.channels.length===0?`No channels added.`:`Channels added.`)}async function runChannelsAddCommand(e,t,r,i=defaultChannelsAddDependencies){if(!await isAshProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{await runAddChannelsFlow(t,r.kind===void 0?void 0:parseChannelKind(r.kind),r.options,i)}catch(t){if(t instanceof ChannelAddCancelledError)return;e.error(t instanceof Error?t.message:String(t)),process.exitCode=1}}async function runChannelsListCommand(e,t,i){if(!await isAshProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let a=await listAuthoredChannels(t);if(i.json){e.log(JSON.stringify({channels:a},null,2));return}if(a.length===0){e.log("No channels defined. Run `ash channels add` to add one.");return}for(let t of a)e.log(t)}export{runChannelsAddCommand,runChannelsListCommand};
|
|
1
|
+
import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"./channel-add-conflicts.js";import{isAshProject}from"../../packages/ash-scaffold/src/project.js";import{listAuthoredChannels}from"../../packages/ash-scaffold/src/channels.js";import"../../packages/ash-scaffold/src/index.js";import{detectDeployment}from"../../packages/ash-scaffold/src/primitives/detect-deployment.js";import{createAddToAgentState,deployProject,runAddToAgent}from"../../packages/ash-scaffold/src/steps/run-add-to-agent.js";import"../../packages/ash-scaffold/src/steps/index.js";import{ChannelAddCancelledError,createChannelAddPrompter}from"../../packages/ash-scaffold/src/cli/channel-add-prompter.js";import"../../packages/ash-scaffold/src/cli/index.js";import"../../packages/ash-scaffold/src/primitives/index.js";const NOT_AN_AGENT_MESSAGE="No Ash agent in this directory. Run `pnpm create experimental-ash-agent`, then run this command from inside the new project.",KNOWN_CHANNEL_KINDS=[`slack`,`web`];function isChannelKind(e){return KNOWN_CHANNEL_KINDS.includes(e)}function parseChannelKind(e){if(!isChannelKind(e))throw Error(`Unknown channel kind "${e}". Known: ${KNOWN_CHANNEL_KINDS.join(`, `)}.`);return e}const defaultChannelsAddDependencies={detectDeployment,deployProject,runAddToAgent};async function runAddChannelsFlow(n,r,i,o){if(r===void 0&&(!process.stdin.isTTY||!process.stdout.isTTY))throw Error(`Pass a channel kind: \`ash channels add <${KNOWN_CHANNEL_KINDS.join(`|`)}>\`.`);let s=o.createPrompter?.()??createChannelAddPrompter();s.intro(`Add channels to your Ash agent`),s.log.message(`Checking the current Vercel project...`);let c=createAddToAgentState(await o.detectDeployment(n)),l;function inspectRegistrations(){return l===void 0&&(s.log.message(`Inspecting existing channel registrations...`),l=inspectExistingChannelRegistrations(n)),l}let u=r===void 0?(await inspectRegistrations()).disabledChannelReasons:void 0;await o.runAddToAgent({prompter:s,projectPath:n,state:c,presetChannels:r===void 0?void 0:[r],disabledChannelReasons:u,force:i.force,validateSelectedChannels:async t=>{!t.includes(`web`)&&!t.includes(`slack`)||assertCanAddSelectedChannels(t,await inspectRegistrations())}}),await o.deployProject({prompter:s,projectPath:n,vercelProjectId:c.vercelProjectId,state:c}),s.outro(c.channels.length===0?`No channels added.`:`Channels added.`)}async function runChannelsAddCommand(e,t,r,i=defaultChannelsAddDependencies){if(!await isAshProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}try{await runAddChannelsFlow(t,r.kind===void 0?void 0:parseChannelKind(r.kind),r.options,i)}catch(t){if(t instanceof ChannelAddCancelledError)return;e.error(t instanceof Error?t.message:String(t)),process.exitCode=1}}async function runChannelsListCommand(e,t,i){if(!await isAshProject(t)){e.error(NOT_AN_AGENT_MESSAGE),process.exitCode=1;return}let a=await listAuthoredChannels(t);if(i.json){e.log(JSON.stringify({channels:a},null,2));return}if(a.length===0){e.log("No channels defined. Run `ash channels add` to add one.");return}for(let t of a)e.log(t)}export{runChannelsAddCommand,runChannelsListCommand};
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface NetworkPolicyRule {
|
|
6
|
-
transform?: NetworkTransformer[] | undefined;
|
|
7
|
-
}
|
|
1
|
+
// The firewall network-policy types are copied verbatim from the installed
|
|
2
|
+
// `@vercel/sandbox` at vendor time (see scripts/vendor-compiled/@vercel/sandbox.mjs)
|
|
3
|
+
// so the credential-brokering surface never drifts from the SDK.
|
|
4
|
+
import type { NetworkPolicy } from "./network-policy.js";
|
|
8
5
|
|
|
9
|
-
export type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
deny?: string[] | undefined;
|
|
18
|
-
}
|
|
19
|
-
| undefined;
|
|
20
|
-
};
|
|
6
|
+
export type {
|
|
7
|
+
NetworkPolicy,
|
|
8
|
+
NetworkPolicyKeyValueMatcher,
|
|
9
|
+
NetworkPolicyMatch,
|
|
10
|
+
NetworkPolicyMatcher,
|
|
11
|
+
NetworkPolicyRule,
|
|
12
|
+
NetworkTransformer,
|
|
13
|
+
} from "./network-policy.js";
|
|
21
14
|
|
|
22
15
|
export interface SandboxKeepLastSnapshotsConfig {
|
|
23
16
|
count: number;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
//#region src/network-policy.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A transform applied to network requests matching a domain rule.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* {
|
|
7
|
+
* headers: { authorization: "Bearer sk-..." }
|
|
8
|
+
* }
|
|
9
|
+
*/
|
|
10
|
+
type NetworkTransformer = {
|
|
11
|
+
/** Headers to set on the outgoing request. */
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Defines how a request value is matched.
|
|
16
|
+
*/
|
|
17
|
+
type NetworkPolicyMatcher = {
|
|
18
|
+
/** Match the value exactly. */
|
|
19
|
+
exact?: string;
|
|
20
|
+
} | {
|
|
21
|
+
/** Match values that start with the provided prefix. */
|
|
22
|
+
startsWith?: string;
|
|
23
|
+
} | {
|
|
24
|
+
/** Match values against an RE2 regular expression. */
|
|
25
|
+
regex?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Matcher for key/value request entries such as headers and query parameters.
|
|
29
|
+
*/
|
|
30
|
+
type NetworkPolicyKeyValueMatcher = {
|
|
31
|
+
/** Matcher for the entry key. */
|
|
32
|
+
key?: NetworkPolicyMatcher;
|
|
33
|
+
/** Matcher for the entry value. */
|
|
34
|
+
value?: NetworkPolicyMatcher;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Request matcher for a network policy rule.
|
|
38
|
+
*
|
|
39
|
+
* All specified dimensions must match. Multiple methods are ORed; multiple
|
|
40
|
+
* header and query-string matchers are ANDed.
|
|
41
|
+
*/
|
|
42
|
+
type NetworkPolicyMatch = {
|
|
43
|
+
/** Match on the request path. */
|
|
44
|
+
path?: NetworkPolicyMatcher;
|
|
45
|
+
/** Match on the HTTP method. */
|
|
46
|
+
method?: string[];
|
|
47
|
+
/** Match on query-string entries. */
|
|
48
|
+
queryString?: NetworkPolicyKeyValueMatcher[];
|
|
49
|
+
/** Match on request headers. */
|
|
50
|
+
headers?: NetworkPolicyKeyValueMatcher[];
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A rule applied to requests matching a domain in the network policy.
|
|
54
|
+
*/
|
|
55
|
+
type NetworkPolicyRule = {
|
|
56
|
+
/**
|
|
57
|
+
* Optional request matcher. When provided, transforms only apply to requests
|
|
58
|
+
* that match every specified dimension.
|
|
59
|
+
*/
|
|
60
|
+
match?: NetworkPolicyMatch;
|
|
61
|
+
/**
|
|
62
|
+
* Transforms to apply to matching requests.
|
|
63
|
+
*/
|
|
64
|
+
transform?: NetworkTransformer[];
|
|
65
|
+
/**
|
|
66
|
+
* HTTPS proxy URL to forward matching requests to. Must not include query string or fragment.
|
|
67
|
+
*
|
|
68
|
+
* You can use the `defineSandboxProxy` helper from `@vercel/sandbox/proxy` to implement the proxy handler
|
|
69
|
+
* automatically, which handles authorization and extracts metadata about the request and sandbox.
|
|
70
|
+
*
|
|
71
|
+
* @see https://vercel.com/docs/vercel-sandbox/concepts/firewall#requests-proxying
|
|
72
|
+
*/
|
|
73
|
+
forwardURL?: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Network policy to define network restrictions for the sandbox.
|
|
77
|
+
*
|
|
78
|
+
* - `"allow-all"`: Full internet access (default). All traffic is allowed.
|
|
79
|
+
* - `"deny-all"`: No internet access. All traffic is denied.
|
|
80
|
+
* - Object: Custom access with explicit allow/deny lists.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // Full internet access (default)
|
|
84
|
+
* "allow-all"
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // No external access
|
|
88
|
+
* "deny-all"
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* // Custom access with specific domains (simple list)
|
|
92
|
+
* // All traffic not explicitly allowed is denied.
|
|
93
|
+
* {
|
|
94
|
+
* allow: ["*.npmjs.org", "github.com"],
|
|
95
|
+
* subnets: {
|
|
96
|
+
* allow: ["10.0.0.0/8"],
|
|
97
|
+
* deny: ["10.1.0.0/16"]
|
|
98
|
+
* }
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* // Custom access with specific domains (record form)
|
|
103
|
+
* {
|
|
104
|
+
* allow: {
|
|
105
|
+
* "*.npmjs.org": [],
|
|
106
|
+
* "github.com": [],
|
|
107
|
+
* }
|
|
108
|
+
* }
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // Custom access with request transformers
|
|
112
|
+
* {
|
|
113
|
+
* allow: {
|
|
114
|
+
* "ai-gateway.vercel.sh": [
|
|
115
|
+
* {
|
|
116
|
+
* match: {
|
|
117
|
+
* method: ["POST"],
|
|
118
|
+
* path: { startsWith: "/v1/" },
|
|
119
|
+
* headers: [
|
|
120
|
+
* { key: { exact: "x-api-key" }, value: { exact: "placeholder" } }
|
|
121
|
+
* ]
|
|
122
|
+
* },
|
|
123
|
+
* transform: [{
|
|
124
|
+
* headers: { authorization: "Bearer ..." }
|
|
125
|
+
* }]
|
|
126
|
+
* }
|
|
127
|
+
* ],
|
|
128
|
+
* "*": []
|
|
129
|
+
* }
|
|
130
|
+
* }
|
|
131
|
+
*/
|
|
132
|
+
type NetworkPolicy = "allow-all" | "deny-all" | {
|
|
133
|
+
/**
|
|
134
|
+
* Domains to allow traffic to.
|
|
135
|
+
* Use "*" prefix for wildcard matching (e.g., "*.npmjs.org").
|
|
136
|
+
*
|
|
137
|
+
* Accepts either:
|
|
138
|
+
* - `string[]`: A simple list of domains to allow.
|
|
139
|
+
* - `Record<string, NetworkPolicyRule[]>`: A map of domains to rules.
|
|
140
|
+
* An empty array allows traffic with no additional rules.
|
|
141
|
+
*/
|
|
142
|
+
allow?: string[] | Record<string, NetworkPolicyRule[]>;
|
|
143
|
+
/**
|
|
144
|
+
* Subnet-level access control using CIDR notation.
|
|
145
|
+
*/
|
|
146
|
+
subnets?: {
|
|
147
|
+
/**
|
|
148
|
+
* List of CIDRs to allow traffic to.
|
|
149
|
+
* Traffic to these addresses will bypass the domain allowlist.
|
|
150
|
+
*/
|
|
151
|
+
allow?: string[];
|
|
152
|
+
/**
|
|
153
|
+
* List of CIDRs to deny traffic to.
|
|
154
|
+
* These take precedence over allowed domains and CIDRs.
|
|
155
|
+
*/
|
|
156
|
+
deny?: string[];
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
160
|
+
export { NetworkPolicy, NetworkPolicyKeyValueMatcher, NetworkPolicyMatch, NetworkPolicyMatcher, NetworkPolicyRule, NetworkTransformer };
|
|
161
|
+
//# sourceMappingURL=network-policy.d.ts.map
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
// The network-policy types are copied verbatim from the installed just-bash at
|
|
2
|
+
// vendor time (see scripts/vendor-compiled/just-bash.mjs) so the credential-
|
|
3
|
+
// brokering surface (allowedUrlPrefixes + header transforms) never drifts.
|
|
4
|
+
import type { NetworkConfig } from "./network/types.js";
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
AllowedUrl,
|
|
8
|
+
AllowedUrlEntry,
|
|
9
|
+
HttpMethod,
|
|
10
|
+
NetworkConfig,
|
|
11
|
+
RequestTransform,
|
|
12
|
+
} from "./network/types.js";
|
|
13
|
+
|
|
1
14
|
export type InitialFileContent = string | Uint8Array;
|
|
2
15
|
export type InitialFiles = Record<string, InitialFileContent>;
|
|
3
16
|
|
|
@@ -17,7 +30,7 @@ export interface BashOptions {
|
|
|
17
30
|
cwd: string;
|
|
18
31
|
env?: Readonly<Record<string, string>> | undefined;
|
|
19
32
|
fs: IFileSystem;
|
|
20
|
-
network?:
|
|
33
|
+
network?: NetworkConfig | undefined;
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
export interface BashExecResult {
|
|
@@ -50,7 +63,7 @@ export interface SandboxOptions {
|
|
|
50
63
|
cwd?: string | undefined;
|
|
51
64
|
env?: Record<string, string> | undefined;
|
|
52
65
|
fs?: IFileSystem | undefined;
|
|
53
|
-
network?:
|
|
66
|
+
network?: NetworkConfig | undefined;
|
|
54
67
|
timeoutMs?: number | undefined;
|
|
55
68
|
}
|
|
56
69
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network configuration types
|
|
3
|
+
*
|
|
4
|
+
* Network access is disabled by default. To enable network access (e.g., for curl),
|
|
5
|
+
* you must explicitly configure allowed URLs.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* DNS lookup result used for private IP resolution checks
|
|
9
|
+
*/
|
|
10
|
+
export interface DnsLookupResult {
|
|
11
|
+
address: string;
|
|
12
|
+
family: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* HTTP methods that can be allowed
|
|
16
|
+
*/
|
|
17
|
+
export type HttpMethod = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
|
18
|
+
/**
|
|
19
|
+
* Header transform applied at the fetch boundary.
|
|
20
|
+
* Headers specified here override any user-supplied headers with the same name.
|
|
21
|
+
*/
|
|
22
|
+
export interface RequestTransform {
|
|
23
|
+
headers: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* An allowed URL entry with optional header transforms.
|
|
27
|
+
* Transforms are applied at the fetch boundary so secrets never enter the sandbox.
|
|
28
|
+
*/
|
|
29
|
+
export interface AllowedUrl {
|
|
30
|
+
url: string;
|
|
31
|
+
transform?: RequestTransform[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* An entry in the allowedUrlPrefixes list: either a plain URL string or
|
|
35
|
+
* an object with a URL and optional transforms.
|
|
36
|
+
*/
|
|
37
|
+
export type AllowedUrlEntry = string | AllowedUrl;
|
|
38
|
+
/**
|
|
39
|
+
* Configuration for network access
|
|
40
|
+
*/
|
|
41
|
+
export interface NetworkConfig {
|
|
42
|
+
/**
|
|
43
|
+
* List of allowed URL prefixes. Each entry must be a full origin (scheme + host),
|
|
44
|
+
* optionally followed by a path prefix:
|
|
45
|
+
* - An origin: "https://api.example.com" - allows all paths on this origin
|
|
46
|
+
* - An origin + path prefix: "https://api.example.com/v1/" - allows only paths starting with /v1/
|
|
47
|
+
*
|
|
48
|
+
* Entries can be plain strings or objects with transforms for credentials brokering:
|
|
49
|
+
* ```
|
|
50
|
+
* allowedUrlPrefixes: [
|
|
51
|
+
* "https://other-api.com",
|
|
52
|
+
* {
|
|
53
|
+
* url: "https://ai-gateway.vercel.sh",
|
|
54
|
+
* transform: [{ headers: { "Authorization": "Bearer secret" } }],
|
|
55
|
+
* },
|
|
56
|
+
* ]
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* The check is performed on the full URL, so "https://api.example.com/v1" will allow:
|
|
60
|
+
* - https://api.example.com/v1
|
|
61
|
+
* - https://api.example.com/v1/users
|
|
62
|
+
* - https://api.example.com/v1/users/123
|
|
63
|
+
*
|
|
64
|
+
* But NOT:
|
|
65
|
+
* - https://api.example.com/v10
|
|
66
|
+
* - https://api.example.com/v1-admin
|
|
67
|
+
* - https://api.example.com/v2/users
|
|
68
|
+
* - https://api.example.org/v1/users (different origin)
|
|
69
|
+
* - URLs that rely on ambiguous encoded separators like %2f or %5c
|
|
70
|
+
*
|
|
71
|
+
* Invalid entries (missing scheme, missing host, relative paths) will throw an error.
|
|
72
|
+
*/
|
|
73
|
+
allowedUrlPrefixes?: AllowedUrlEntry[];
|
|
74
|
+
/**
|
|
75
|
+
* List of allowed HTTP methods. Defaults to ["GET", "HEAD"] for safety.
|
|
76
|
+
* dangerouslyAllowFullInternetAccess to enables all methods.
|
|
77
|
+
*/
|
|
78
|
+
allowedMethods?: HttpMethod[];
|
|
79
|
+
/**
|
|
80
|
+
* Bypass the allow-list and allow all URLs and methods.
|
|
81
|
+
* DANGEROUS: Only use this in trusted environments.
|
|
82
|
+
*/
|
|
83
|
+
dangerouslyAllowFullInternetAccess?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Maximum number of redirects to follow (default: 20)
|
|
86
|
+
*/
|
|
87
|
+
maxRedirects?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Request timeout in milliseconds (default: 30000)
|
|
90
|
+
*/
|
|
91
|
+
timeoutMs?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Maximum response body size in bytes (default: 10MB).
|
|
94
|
+
* Responses larger than this will be rejected with ResponseTooLargeError.
|
|
95
|
+
*/
|
|
96
|
+
maxResponseSize?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Reject URLs with private/loopback IP addresses as hostnames.
|
|
99
|
+
* Performs both lexical hostname checks and DNS resolution to catch
|
|
100
|
+
* domains that resolve to private IPs (e.g., DNS rebinding attacks).
|
|
101
|
+
* Useful for mitigating SSRF attacks. Default: false (opt-in).
|
|
102
|
+
*
|
|
103
|
+
* When enabled, the private IP check is enforced even when
|
|
104
|
+
* `dangerouslyAllowFullInternetAccess` is true, ensuring that
|
|
105
|
+
* internal/loopback addresses are never reachable.
|
|
106
|
+
*/
|
|
107
|
+
denyPrivateRanges?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* @internal Override DNS resolution for testing.
|
|
110
|
+
* When set, used instead of the default `dns.lookup` for the
|
|
111
|
+
* denyPrivateRanges DNS rebinding check.
|
|
112
|
+
*/
|
|
113
|
+
_dnsResolve?: (hostname: string) => Promise<DnsLookupResult[]>;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Result of a network fetch operation
|
|
117
|
+
*/
|
|
118
|
+
export interface FetchResult {
|
|
119
|
+
status: number;
|
|
120
|
+
statusText: string;
|
|
121
|
+
headers: Record<string, string>;
|
|
122
|
+
/** Raw response bytes (never decoded as UTF-8 text). */
|
|
123
|
+
body: Uint8Array;
|
|
124
|
+
url: string;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Error thrown when a URL is not allowed
|
|
128
|
+
*/
|
|
129
|
+
export declare class NetworkAccessDeniedError extends Error {
|
|
130
|
+
constructor(url: string, reason?: string);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Error thrown when too many redirects occur
|
|
134
|
+
*/
|
|
135
|
+
export declare class TooManyRedirectsError extends Error {
|
|
136
|
+
constructor(maxRedirects: number);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Error thrown when a redirect target is not allowed
|
|
140
|
+
*/
|
|
141
|
+
export declare class RedirectNotAllowedError extends Error {
|
|
142
|
+
constructor(url: string);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Error thrown when an HTTP method is not allowed
|
|
146
|
+
*/
|
|
147
|
+
export declare class MethodNotAllowedError extends Error {
|
|
148
|
+
constructor(method: string, allowedMethods: string[]);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Error thrown when a response body exceeds the maximum allowed size
|
|
152
|
+
*/
|
|
153
|
+
export declare class ResponseTooLargeError extends Error {
|
|
154
|
+
constructor(maxSize: number);
|
|
155
|
+
}
|
|
@@ -22,6 +22,7 @@ export declare const COMPILE_METADATA_VERSION = 5;
|
|
|
22
22
|
*/
|
|
23
23
|
export interface CompilerArtifactPaths {
|
|
24
24
|
appRoot: string;
|
|
25
|
+
channelInstrumentationTypesPath: string;
|
|
25
26
|
compiledManifestPath: string;
|
|
26
27
|
compileDirectoryPath: string;
|
|
27
28
|
compileMetadataPath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join,relative,resolve}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createHash}from"node:crypto";import{summarizeDiscoverDiagnostics}from"#discover/diagnostics.js";import{normalizeLogicalPath}from"#discover/filesystem.js";import{createCompiledModuleMapSource}from"#compiler/module-map.js";import{compileAgentManifest}from"#compiler/normalize-manifest.js";import{materializeWorkspaceResources}from"#compiler/workspace-resources.js";const COMPILE_METADATA_KIND=`ash-compile-metadata`,COMPILE_METADATA_VERSION=5;function resolveCompilerArtifactPaths(t){let r=resolve(t),i=join(r,`.ash`,`discovery`),a=join(r,`.ash`,`compile`);return{appRoot:r,compiledManifestPath:join(a,`compiled-agent-manifest.json`),compileDirectoryPath:a,compileMetadataPath:join(a,`compile-metadata.json`),diagnosticsPath:join(i,`diagnostics.json`),discoveryManifestPath:join(i,`agent-discovery-manifest.json`),discoveryDirectoryPath:i,moduleMapPath:join(a,`module-map.mjs`)}}function createDiscoveryDiagnosticsArtifact(e){return{diagnostics:[...e],kind:`ash-discovery-diagnostics`,summary:summarizeDiscoverDiagnostics(e),version:1}}function createCompileMetadata(e){let t=resolveInstalledPackageInfo(),n=createContentHash(e.discoveryManifestJson),r=createContentHash(e.diagnosticsArtifactJson),i=createContentHash(e.moduleMapSource);return{compile:{moduleMap:{path:toArtifactRelativePath(e.appRoot,e.paths.moduleMapPath),sha256:i}},discovery:{diagnostics:{path:toArtifactRelativePath(e.appRoot,e.paths.diagnosticsPath),sha256:r},manifest:{path:toArtifactRelativePath(e.appRoot,e.paths.discoveryManifestPath),sha256:n},sourceGraphHash:createContentHash(`${n}:${r}:${i}`),summary:e.diagnosticsSummary},generator:{name:t.name,version:t.version},kind:COMPILE_METADATA_KIND,status:e.diagnosticsSummary.errors>0?`failed`:`ready`,version:5}}async function writeCompilerArtifacts(e){let t=resolveCompilerArtifactPaths(e.appRoot),n=createDiscoveryDiagnosticsArtifact(e.diagnostics),a=await materializeWorkspaceResources({compileDirectoryPath:t.compileDirectoryPath,manifest:await compileAgentManifest(e.manifest)}),o=serializeArtifactJson(a),s=serializeArtifactJson(e.manifest),c=serializeArtifactJson(n),l=createCompiledModuleMapSource({manifest:a,moduleMapPath:t.moduleMapPath}),u=createCompileMetadata({appRoot:e.appRoot,diagnosticsArtifactJson:c,diagnosticsSummary:n.summary,discoveryManifestJson:s,moduleMapSource:l,paths:t}),
|
|
1
|
+
import{join,relative,resolve}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createHash}from"node:crypto";import{summarizeDiscoverDiagnostics}from"#discover/diagnostics.js";import{normalizeLogicalPath}from"#discover/filesystem.js";import{CHANNEL_INSTRUMENTATION_TYPES_FILE_NAME,createChannelInstrumentationTypesSource}from"#compiler/channel-instrumentation-types.js";import{createCompiledModuleMapSource}from"#compiler/module-map.js";import{compileAgentManifest}from"#compiler/normalize-manifest.js";import{materializeWorkspaceResources}from"#compiler/workspace-resources.js";const COMPILE_METADATA_KIND=`ash-compile-metadata`,COMPILE_METADATA_VERSION=5;function resolveCompilerArtifactPaths(t){let r=resolve(t),i=join(r,`.ash`,`discovery`),a=join(r,`.ash`,`compile`);return{appRoot:r,channelInstrumentationTypesPath:join(a,CHANNEL_INSTRUMENTATION_TYPES_FILE_NAME),compiledManifestPath:join(a,`compiled-agent-manifest.json`),compileDirectoryPath:a,compileMetadataPath:join(a,`compile-metadata.json`),diagnosticsPath:join(i,`diagnostics.json`),discoveryManifestPath:join(i,`agent-discovery-manifest.json`),discoveryDirectoryPath:i,moduleMapPath:join(a,`module-map.mjs`)}}function createDiscoveryDiagnosticsArtifact(e){return{diagnostics:[...e],kind:`ash-discovery-diagnostics`,summary:summarizeDiscoverDiagnostics(e),version:1}}function createCompileMetadata(e){let t=resolveInstalledPackageInfo(),n=createContentHash(e.discoveryManifestJson),r=createContentHash(e.diagnosticsArtifactJson),i=createContentHash(e.moduleMapSource);return{compile:{moduleMap:{path:toArtifactRelativePath(e.appRoot,e.paths.moduleMapPath),sha256:i}},discovery:{diagnostics:{path:toArtifactRelativePath(e.appRoot,e.paths.diagnosticsPath),sha256:r},manifest:{path:toArtifactRelativePath(e.appRoot,e.paths.discoveryManifestPath),sha256:n},sourceGraphHash:createContentHash(`${n}:${r}:${i}`),summary:e.diagnosticsSummary},generator:{name:t.name,version:t.version},kind:COMPILE_METADATA_KIND,status:e.diagnosticsSummary.errors>0?`failed`:`ready`,version:5}}async function writeCompilerArtifacts(e){let t=resolveCompilerArtifactPaths(e.appRoot),n=createDiscoveryDiagnosticsArtifact(e.diagnostics),a=await materializeWorkspaceResources({compileDirectoryPath:t.compileDirectoryPath,manifest:await compileAgentManifest(e.manifest)}),o=serializeArtifactJson(a),s=serializeArtifactJson(e.manifest),c=serializeArtifactJson(n),l=createCompiledModuleMapSource({manifest:a,moduleMapPath:t.moduleMapPath}),u=createChannelInstrumentationTypesSource({manifest:a,typesPath:t.channelInstrumentationTypesPath}),d=createCompileMetadata({appRoot:e.appRoot,diagnosticsArtifactJson:c,diagnosticsSummary:n.summary,discoveryManifestJson:s,moduleMapSource:l,paths:t}),f=serializeArtifactJson(d);return await mkdir(t.discoveryDirectoryPath,{recursive:!0}),await mkdir(t.compileDirectoryPath,{recursive:!0}),await Promise.all([writeFile(t.compiledManifestPath,o),writeFile(t.diagnosticsPath,c),writeFile(t.discoveryManifestPath,s),writeFile(t.channelInstrumentationTypesPath,u),writeFile(t.moduleMapPath,l),writeFile(t.compileMetadataPath,f)]),{compiledManifest:a,diagnosticsArtifact:n,metadata:d,moduleMapSource:l,paths:t}}function createContentHash(e){return createHash(`sha256`).update(e).digest(`hex`)}function serializeArtifactJson(e){return`${JSON.stringify(e,null,2)}\n`}function toArtifactRelativePath(e,r){return normalizeLogicalPath(relative(resolve(e),r))}export{COMPILE_METADATA_KIND,COMPILE_METADATA_VERSION,createCompileMetadata,resolveCompilerArtifactPaths,writeCompilerArtifacts};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CompiledAgentManifest } from "#compiler/manifest.js";
|
|
2
|
+
interface ChannelInstrumentationTypesSourceInput {
|
|
3
|
+
readonly manifest: CompiledAgentManifest;
|
|
4
|
+
readonly typesPath: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const CHANNEL_INSTRUMENTATION_TYPES_FILE_NAME = "channel-instrumentation-types.d.ts";
|
|
7
|
+
export declare function createChannelInstrumentationTypesSource(input: ChannelInstrumentationTypesSourceInput): string;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{dirname,join,relative}from"node:path";const CHANNEL_INSTRUMENTATION_TYPES_FILE_NAME=`channel-instrumentation-types.d.ts`;function createChannelInstrumentationTypesSource(e){let t=collectChannelInstrumentationDeclarations(e);return[`// Generated by Ash. Do not edit by hand.`,`import type { InferChannelMetadata } from "experimental-ash/channels";`,``,`declare module "experimental-ash/instrumentation" {`,...t.length===0?[` interface ChannelMetadataMap {}`,` interface ChannelReferenceMap {}`]:[` interface ChannelMetadataMap {`,...t.map(e=>` readonly ${JSON.stringify(e.kind)}: InferChannelMetadata<${renderImportedChannelType(e)}>;`),` }`,` interface ChannelReferenceMap {`,...t.map(e=>` readonly ${JSON.stringify(e.kind)}: ${renderImportedChannelType(e)};`),` }`],`}`,``].join(`
|
|
2
|
+
`)}function collectChannelInstrumentationDeclarations(t){let n=dirname(t.typesPath),r=new Map;for(let e of[...t.manifest.channels].filter(e=>e.kind===`channel`).sort(compareCompiledChannels)){let i=`channel:${e.name}`;r.has(i)||r.set(i,{exportName:e.exportName,importSpecifier:createChannelImportSpecifier({agentRoot:t.manifest.agentRoot,channel:e,fromDirectory:n}),kind:i})}return[...r.values()]}function compareCompiledChannels(e,t){return e.name.localeCompare(t.name)||e.logicalPath.localeCompare(t.logicalPath)||(e.exportName??``).localeCompare(t.exportName??``)||e.sourceId.localeCompare(t.sourceId)||e.method.localeCompare(t.method)||e.urlPath.localeCompare(t.urlPath)}function createChannelImportSpecifier(e){let r=join(e.agentRoot,toRuntimeImportLogicalPath(e.channel.logicalPath)),i=relative(e.fromDirectory,r).replaceAll(`\\`,`/`);return i.startsWith(`.`)?i:`./${i}`}function toRuntimeImportLogicalPath(e){return e.endsWith(`.mts`)?`${e.slice(0,-4)}.mjs`:e.endsWith(`.cts`)?`${e.slice(0,-4)}.cjs`:e.endsWith(`.ts`)?`${e.slice(0,-3)}.js`:e}function renderImportedChannelType(e){let t=e.exportName??`default`,n=`import(${JSON.stringify(e.importSpecifier)})`;return isIdentifierName(t)?`typeof ${n}.${t}`:`typeof ${n}[${JSON.stringify(t)}]`}function isIdentifierName(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}export{CHANNEL_INSTRUMENTATION_TYPES_FILE_NAME,createChannelInstrumentationTypesSource};
|