experimental-ash 0.7.2 → 0.7.3
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/dist/docs/internals/README.md +8 -8
- package/dist/docs/internals/context.md +1 -1
- package/dist/docs/internals/hooks.md +5 -5
- package/dist/docs/internals/message-runtime.md +2 -2
- package/dist/docs/public/README.md +22 -22
- package/dist/docs/public/agent-ts.md +21 -17
- package/dist/docs/public/auth-and-route-protection.md +3 -3
- package/dist/docs/public/channels/README.md +8 -8
- package/dist/docs/public/cli-build-and-debugging.md +3 -3
- package/dist/docs/public/connections.md +5 -5
- package/dist/docs/public/context-control.md +8 -8
- package/dist/docs/public/evals.md +3 -3
- package/dist/docs/public/getting-started.md +5 -5
- package/dist/docs/public/hooks.md +4 -4
- package/dist/docs/public/human-in-the-loop.md +3 -3
- package/dist/docs/public/instrumentation.md +4 -3
- package/dist/docs/public/project-layout.md +11 -11
- package/dist/docs/public/runs-and-streaming.md +3 -3
- package/dist/docs/public/sandbox.md +3 -3
- package/dist/docs/public/session-context.md +10 -6
- package/dist/docs/public/skills.md +5 -3
- package/dist/docs/public/subagents.md +2 -2
- package/dist/docs/public/tools.md +4 -5
- package/dist/docs/public/typescript-api.md +11 -11
- package/dist/docs/public/vercel-deployment.md +4 -4
- package/dist/docs/public/workspace.md +3 -3
- package/dist/src/channel/compiled-channel.d.ts +4 -2
- package/dist/src/channel/schedule.d.ts +11 -23
- package/dist/src/channel/schedule.js +18 -19
- package/dist/src/chunks/{dev-authored-source-watcher-D3ybKVO9.js → dev-authored-source-watcher-Druw92QN.js} +1 -1
- package/dist/src/chunks/{host-Ck0qkepf.js → host-CQ7AZID3.js} +2 -2
- package/dist/src/chunks/paths-DQbfjCIS.js +88 -0
- package/dist/src/chunks/{prewarm-DJtOdukm.js → prewarm-CcphIXc0.js} +1 -1
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/compiler/normalize-channel.d.ts +4 -4
- package/dist/src/compiler/normalize-channel.js +9 -22
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/channel.d.ts +7 -9
- package/dist/src/internal/authored-definition/channel.js +9 -33
- package/dist/src/internal/nitro/routes/channel-dispatch.d.ts +5 -3
- package/dist/src/internal/nitro/routes/channel-dispatch.js +8 -5
- package/dist/src/internal/nitro/routes/runtime-stack.js +1 -1
- package/dist/src/internal/nitro/routes/schedule-task.d.ts +3 -4
- package/dist/src/internal/nitro/routes/schedule-task.js +5 -7
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/definitions/channel.d.ts +1 -63
- package/dist/src/public/definitions/channel.js +0 -16
- package/dist/src/public/definitions/defineChannel.d.ts +7 -4
- package/dist/src/runtime/resolve-channel.d.ts +9 -4
- package/dist/src/runtime/resolve-channel.js +21 -28
- package/dist/src/runtime/types.d.ts +13 -8
- package/package.json +1 -1
- package/dist/src/chunks/paths-BFX2EgQO.js +0 -88
- package/dist/src/compiler/channel-url.d.ts +0 -5
- package/dist/src/compiler/channel-url.js +0 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"../../chunks/paths-
|
|
1
|
+
import{n as e}from"../../chunks/paths-DQbfjCIS.js";import{loadDevelopmentEnvironmentFiles as t}from"../../cli/dev/environment.js";import{a as n,n as r,t as i}from"../../chunks/client-DBMG7iuf.js";import{n as a}from"../../chunks/host-CQ7AZID3.js";import{discoverAndImportSuites as o,discoverSuiteFiles as s,importSuiteFile as c}from"../runner/discover.js";import{executeSuite as l}from"../runner/execute-suite.js";import{ConsoleReporter as u}from"../runner/reporters/console.js";var d=n();function f(e,t){e.command(`eval`).description(`Run eval suites against an Ash agent.`).option(`--suite <id...>`,`Suite IDs to run (repeatable)`).option(`--all`,`Run all discovered suites`).option(`--url <url>`,`Remote agent URL (skip local host startup)`).option(`--timeout <ms>`,`Per-case timeout in milliseconds`).option(`--max-concurrency <n>`,`Max concurrent case executions per suite`).option(`--json`,`Output results as JSON`).option(`--list-suites`,`List discovered suites and exit`).option(`--skip-report`,`Skip suite-defined reporters (e.g. Braintrust)`).action(async e=>{await p(e,t)})}async function p(n,r){let i=e();if(t(i),n.listSuites){await y(i,r);return}let s=n.suite,c=await o(i,s);if(c.length===0){s&&s.length>0?r.error(`No suites found matching: ${s.join(`, `)}`):r.error(`No eval suites found. Create suite files under evals/ with the *.eval.ts extension.`),process.exitCode=1;return}let u,d;n.url?d={kind:`remote`,url:n.url}:(u=await a(i,{host:`127.0.0.1`,port:0}),d={kind:`local`,url:u.url});let f=m(d);try{let e=[];for(let t of c){let r=_(t,n),a=v(r,{json:n.json===!0,skipReport:n.skipReport===!0}),o=await l({suite:r,target:d,reporters:a,appRoot:i,client:f});e.push(o)}n.json&&r.log(JSON.stringify(e,null,2)),e.some(e=>e.errored>0)&&(process.exitCode=1)}finally{u&&await u.close()}process.exit(process.exitCode??0)}function m(e){if(e.kind===`local`)return new i({host:e.url});let t={},n=process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();return n&&(t[r]=n),new i({auth:h(),headers:Object.keys(t).length>0?t:void 0,host:e.url})}function h(){let e=process.env.ASH_EVAL_AUTH_TOKEN?.trim();return e?{bearer:e}:{bearer:g}}async function g(){try{let e=(await(0,d.getVercelOidcToken)()).trim();if(e.length>0)return e}catch{}return process.env.VERCEL_OIDC_TOKEN?.trim()??``}function _(e,t){let n=t.maxConcurrency?Number.parseInt(t.maxConcurrency,10):void 0,r=t.timeout?Number.parseInt(t.timeout,10):void 0;if(n===void 0&&r===void 0)return e;let i={...e};return n!==void 0&&(i.maxConcurrency=n),r!==void 0&&(i.timeoutMs=r),i}function v(e,t){let n=t.json?[]:[new u];return!t.skipReport&&e.reporters&&n.push(...e.reporters),n}async function y(e,t){let n=await s(e);if(n.length===0){t.log(`No eval suites found.`);return}t.log(`Found ${n.length} eval suite file(s):\n`);for(let r of n){let n=await c(e,r);t.log(` ${n.id}${n.description?` - ${n.description}`:``}`)}}export{f as registerEvalCommand,p as runEvalCommand};
|
|
@@ -6,7 +6,7 @@ import { ASH_PACKAGE_NAME } from "#package-name.js";
|
|
|
6
6
|
let cachedPackageInfo;
|
|
7
7
|
// The package build stamps the published version into `dist` so bundled
|
|
8
8
|
// deployments can still report package metadata without resolving package.json.
|
|
9
|
-
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.7.
|
|
9
|
+
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.7.3";
|
|
10
10
|
const BUNDLED_FALLBACK_PACKAGE_VERSION_PLACEHOLDER = "__ASH_PACKAGE_VERSION_PLACEHOLDER__";
|
|
11
11
|
const WORKFLOW_MODULE_ALIASES = {
|
|
12
12
|
"workflow/api": "src/compiled/@workflow/core/runtime.js",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Route } from "#public/definitions/channel.js";
|
|
2
1
|
import { type CompiledChannel } from "#channel/compiled-channel.js";
|
|
3
2
|
/**
|
|
4
3
|
* Type guard: returns whether `value` is a {@link CompiledChannel} produced
|
|
@@ -9,15 +8,14 @@ export declare function isCompiledChannel(value: unknown): value is CompiledChan
|
|
|
9
8
|
* Normalizes one authored channel definition into the canonical internal
|
|
10
9
|
* shape consumed by the compiler.
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* are validated and returned as Route.
|
|
11
|
+
* Authored channels must go through {@link defineChannel} (or a wrapper
|
|
12
|
+
* like `slackChannel` / `ashChannel`) and therefore must be
|
|
13
|
+
* {@link CompiledChannel} values. The legacy plain-`{ fetch, receive? }`
|
|
14
|
+
* Route shape is no longer supported — drop a clear error for it so
|
|
15
|
+
* users on old patterns get a useful migration hint instead of a silent
|
|
16
|
+
* runtime crash deeper in dispatch.
|
|
19
17
|
*
|
|
20
18
|
* Disable sentinels are handled by the compiler before this function is
|
|
21
19
|
* called.
|
|
22
20
|
*/
|
|
23
|
-
export declare function normalizeChannelDefinition(value: unknown, message: string):
|
|
21
|
+
export declare function normalizeChannelDefinition(value: unknown, message: string): CompiledChannel;
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
|
|
2
|
-
import { expectFunction, expectObjectRecord, expectOnlyKnownKeys, } from "#internal/authored-module.js";
|
|
3
|
-
const CHANNEL_METHODS = new Set([
|
|
4
|
-
"GET",
|
|
5
|
-
"POST",
|
|
6
|
-
"PUT",
|
|
7
|
-
"DELETE",
|
|
8
|
-
"PATCH",
|
|
9
|
-
]);
|
|
10
2
|
/**
|
|
11
3
|
* Type guard: returns whether `value` is a {@link CompiledChannel} produced
|
|
12
4
|
* by {@link defineChannel}.
|
|
@@ -20,35 +12,19 @@ export function isCompiledChannel(value) {
|
|
|
20
12
|
* Normalizes one authored channel definition into the canonical internal
|
|
21
13
|
* shape consumed by the compiler.
|
|
22
14
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* are validated and returned as Route.
|
|
15
|
+
* Authored channels must go through {@link defineChannel} (or a wrapper
|
|
16
|
+
* like `slackChannel` / `ashChannel`) and therefore must be
|
|
17
|
+
* {@link CompiledChannel} values. The legacy plain-`{ fetch, receive? }`
|
|
18
|
+
* Route shape is no longer supported — drop a clear error for it so
|
|
19
|
+
* users on old patterns get a useful migration hint instead of a silent
|
|
20
|
+
* runtime crash deeper in dispatch.
|
|
30
21
|
*
|
|
31
22
|
* Disable sentinels are handled by the compiler before this function is
|
|
32
23
|
* called.
|
|
33
24
|
*/
|
|
34
25
|
export function normalizeChannelDefinition(value, message) {
|
|
35
|
-
if (isCompiledChannel(value)) {
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
const record = expectObjectRecord(value, message);
|
|
39
|
-
expectOnlyKnownKeys(record, ["adapter", "fetch", "method", "receive"], message);
|
|
40
|
-
const fetchHandler = expectFunction(record.fetch, message);
|
|
41
|
-
let method;
|
|
42
|
-
if (record.method !== undefined) {
|
|
43
|
-
if (typeof record.method !== "string" || !CHANNEL_METHODS.has(record.method)) {
|
|
44
|
-
throw new Error(message);
|
|
45
|
-
}
|
|
46
|
-
method = record.method;
|
|
47
|
-
}
|
|
48
|
-
const adapter = record.adapter;
|
|
49
|
-
const receive = typeof record.receive === "function" ? record.receive : undefined;
|
|
50
|
-
if (method === undefined) {
|
|
51
|
-
return { adapter, fetch: fetchHandler, receive };
|
|
26
|
+
if (!isCompiledChannel(value)) {
|
|
27
|
+
throw new Error(`${message} Use \`defineChannel({ routes, ... })\` (or a wrapper like \`slackChannel\` / \`ashChannel\`) — bare \`{ fetch, receive? }\` channel objects are no longer supported.`);
|
|
52
28
|
}
|
|
53
|
-
return
|
|
29
|
+
return value;
|
|
54
30
|
}
|
|
@@ -11,8 +11,10 @@ import type { NitroArtifactsConfig } from "#internal/nitro/routes/runtime-artifa
|
|
|
11
11
|
* Nitro forwards that work to `event.waitUntil()` so webhook
|
|
12
12
|
* acknowledgements can return immediately.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* Two dispatch shapes: authored channels (`defineChannel` and its
|
|
15
|
+
* wrappers) carry a `handler` field and receive `RouteHandlerArgs` with
|
|
16
|
+
* `send`, `getSession`, etc. Framework-internal channels (the
|
|
17
|
+
* connection callback route) build `ResolvedChannelDefinition` directly
|
|
18
|
+
* with just `fetch` and receive a `RouteContext` carrying `agent`.
|
|
17
19
|
*/
|
|
18
20
|
export declare function dispatchChannelRequest(event: H3Event, routeKey: string, config: NitroArtifactsConfig): Promise<Response>;
|
|
@@ -12,9 +12,11 @@ import { resolveNitroChannelRuntimeBundle } from "#internal/nitro/routes/runtime
|
|
|
12
12
|
* Nitro forwards that work to `event.waitUntil()` so webhook
|
|
13
13
|
* acknowledgements can return immediately.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Two dispatch shapes: authored channels (`defineChannel` and its
|
|
16
|
+
* wrappers) carry a `handler` field and receive `RouteHandlerArgs` with
|
|
17
|
+
* `send`, `getSession`, etc. Framework-internal channels (the
|
|
18
|
+
* connection callback route) build `ResolvedChannelDefinition` directly
|
|
19
|
+
* with just `fetch` and receive a `RouteContext` carrying `agent`.
|
|
18
20
|
*/
|
|
19
21
|
export async function dispatchChannelRequest(event, routeKey, config) {
|
|
20
22
|
const bundle = await resolveNitroChannelRuntimeBundle(config);
|
|
@@ -34,7 +36,7 @@ export async function dispatchChannelRequest(event, routeKey, config) {
|
|
|
34
36
|
};
|
|
35
37
|
let response;
|
|
36
38
|
if (matchedChannel.handler) {
|
|
37
|
-
//
|
|
39
|
+
// Authored CompiledChannel route — build RouteHandlerArgs.
|
|
38
40
|
const adapter = matchedChannel.adapter ?? { kind: "channel" };
|
|
39
41
|
const send = createSendFn(bundle.runtime, adapter, matchedChannel.name);
|
|
40
42
|
const getSession = createGetSessionFn(bundle.runtime);
|
|
@@ -48,7 +50,8 @@ export async function dispatchChannelRequest(event, routeKey, config) {
|
|
|
48
50
|
response = await matchedChannel.handler(event.req, args);
|
|
49
51
|
}
|
|
50
52
|
else {
|
|
51
|
-
//
|
|
53
|
+
// Framework-internal fetch-only channel (e.g. the connection
|
|
54
|
+
// callback route). Build a RouteContext with the agent handle.
|
|
52
55
|
const ctx = {
|
|
53
56
|
agent: bundle.runtime,
|
|
54
57
|
waitUntil,
|
|
@@ -42,7 +42,7 @@ export function resolveNitroScheduleDispatcher(config) {
|
|
|
42
42
|
if (!channel) {
|
|
43
43
|
throw new Error(`Channel "${channelName}" not found in agent/channels/.`);
|
|
44
44
|
}
|
|
45
|
-
return { receive: channel.receive };
|
|
45
|
+
return { receive: channel.receive, adapter: channel.adapter };
|
|
46
46
|
},
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -2,12 +2,11 @@ import type { NitroArtifactsConfig } from "#internal/nitro/routes/runtime-artifa
|
|
|
2
2
|
/**
|
|
3
3
|
* Dispatches one Ash authored schedule via the execution engine.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Fire-and-forget: the workflow runtime owns terminal completion and
|
|
6
|
+
* its own failure observability. The task return value reports only
|
|
7
|
+
* that the session was dispatched.
|
|
8
8
|
*/
|
|
9
9
|
export declare function dispatchScheduleTask(taskName: string, config: NitroArtifactsConfig): Promise<{
|
|
10
10
|
scheduleId: string;
|
|
11
11
|
sessionId: string;
|
|
12
|
-
status: string;
|
|
13
12
|
}>;
|
|
@@ -4,9 +4,9 @@ import { resolveNitroScheduleDispatcher } from "#internal/nitro/routes/runtime-s
|
|
|
4
4
|
/**
|
|
5
5
|
* Dispatches one Ash authored schedule via the execution engine.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Fire-and-forget: the workflow runtime owns terminal completion and
|
|
8
|
+
* its own failure observability. The task return value reports only
|
|
9
|
+
* that the session was dispatched.
|
|
10
10
|
*/
|
|
11
11
|
export async function dispatchScheduleTask(taskName, config) {
|
|
12
12
|
const compiledArtifactsSource = resolveNitroCompiledArtifactsSource(config);
|
|
@@ -19,11 +19,9 @@ export async function dispatchScheduleTask(taskName, config) {
|
|
|
19
19
|
markdown: schedule.markdown,
|
|
20
20
|
scheduleId: schedule.name,
|
|
21
21
|
};
|
|
22
|
-
const
|
|
23
|
-
const result = await handle.result;
|
|
22
|
+
const session = await dispatcher.trigger(triggerInput);
|
|
24
23
|
return {
|
|
25
24
|
scheduleId: schedule.name,
|
|
26
|
-
sessionId:
|
|
27
|
-
status: result.status,
|
|
25
|
+
sessionId: session.id,
|
|
28
26
|
};
|
|
29
27
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { DeliverInput, GetEventStreamOptions, RunHandle, RunInput, SessionAuthContext } from "#channel/types.js";
|
|
1
|
+
import type { DeliverInput, GetEventStreamOptions, RunHandle, RunInput } from "#channel/types.js";
|
|
3
2
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
4
3
|
export type { GetEventStreamOptions } from "#channel/types.js";
|
|
5
4
|
/**
|
|
@@ -94,59 +93,6 @@ export interface Agent {
|
|
|
94
93
|
*/
|
|
95
94
|
getEventStream(sessionId: string, options?: GetEventStreamOptions): Promise<ReadableStream<HandleMessageStreamEvent>>;
|
|
96
95
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Input for {@link Route.receive} — the universal entry point for
|
|
99
|
-
* inbound messages to a channel.
|
|
100
|
-
*/
|
|
101
|
-
export interface ReceiveInput {
|
|
102
|
-
readonly message: string;
|
|
103
|
-
readonly args: Readonly<Record<string, unknown>>;
|
|
104
|
-
readonly auth: SessionAuthContext | null;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Context passed to {@link Route.receive}.
|
|
108
|
-
*/
|
|
109
|
-
export interface ReceiveContext {
|
|
110
|
-
readonly agent: Agent;
|
|
111
|
-
readonly waitUntil: (task: Promise<unknown>) => void;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Public authored route definition. A route is a Web-standard
|
|
115
|
-
* `(Request, ctx) => Response` handler whose URL path is derived from the
|
|
116
|
-
* file's location under `agent/channels/`.
|
|
117
|
-
*
|
|
118
|
-
* Filename is identity. `agent/channels/slack.ts` mounts at `POST /slack`.
|
|
119
|
-
* Nested directories and Nitro `[name]` path parameters are preserved.
|
|
120
|
-
*/
|
|
121
|
-
export interface Route {
|
|
122
|
-
/**
|
|
123
|
-
* HTTP method this route handles. Optional — defaults to `"POST"`.
|
|
124
|
-
*/
|
|
125
|
-
readonly method?: ChannelMethod;
|
|
126
|
-
/**
|
|
127
|
-
* Optional adapter that this route attaches to sessions it starts.
|
|
128
|
-
*
|
|
129
|
-
* Declared here so the runtime can register the adapter's `kind` in
|
|
130
|
-
* the adapter registry and rehydrate it after workflow step boundaries.
|
|
131
|
-
* Routes that don't start sessions (e.g. stream readers) omit this.
|
|
132
|
-
*/
|
|
133
|
-
readonly adapter?: ChannelAdapter<any>;
|
|
134
|
-
/**
|
|
135
|
-
* The request handler. Receives the inbound `Request` and a
|
|
136
|
-
* {@link RouteContext} carrying the agent handle and host helpers.
|
|
137
|
-
*/
|
|
138
|
-
fetch(request: Request, ctx: RouteContext): Promise<Response>;
|
|
139
|
-
/**
|
|
140
|
-
* Universal entry point for inbound messages. Handles both new
|
|
141
|
-
* sessions (start) and continuations (deliver to existing session).
|
|
142
|
-
* Called by `fetch` after HTTP parsing and by the schedule dispatcher
|
|
143
|
-
* directly.
|
|
144
|
-
*
|
|
145
|
-
* Returns `RunHandle` for new sessions, `void` for deliveries to
|
|
146
|
-
* existing sessions.
|
|
147
|
-
*/
|
|
148
|
-
receive?(input: ReceiveInput, ctx: ReceiveContext): Promise<RunHandle | void>;
|
|
149
|
-
}
|
|
150
96
|
/**
|
|
151
97
|
* Marker discriminator written into every {@link DisabledRouteSentinel}.
|
|
152
98
|
*/
|
|
@@ -171,11 +117,3 @@ export declare function disableRoute(): DisabledRouteSentinel;
|
|
|
171
117
|
* produced by {@link disableRoute}.
|
|
172
118
|
*/
|
|
173
119
|
export declare function isDisabledRouteSentinel(value: unknown): value is DisabledRouteSentinel;
|
|
174
|
-
/**
|
|
175
|
-
* Type guard: returns whether `value` looks like a {@link Route} or a
|
|
176
|
-
* `CompiledChannel` produced by `defineChannel()`.
|
|
177
|
-
*
|
|
178
|
-
* Used by the compiler to distinguish authored channel exports from
|
|
179
|
-
* `DisabledRouteSentinel` exports.
|
|
180
|
-
*/
|
|
181
|
-
export declare function isRouteDefinition(value: unknown): boolean;
|
|
@@ -22,19 +22,3 @@ export function isDisabledRouteSentinel(value) {
|
|
|
22
22
|
value !== null &&
|
|
23
23
|
value.kind === DISABLED_ROUTE_SENTINEL_KIND);
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Type guard: returns whether `value` looks like a {@link Route} or a
|
|
27
|
-
* `CompiledChannel` produced by `defineChannel()`.
|
|
28
|
-
*
|
|
29
|
-
* Used by the compiler to distinguish authored channel exports from
|
|
30
|
-
* `DisabledRouteSentinel` exports.
|
|
31
|
-
*/
|
|
32
|
-
export function isRouteDefinition(value) {
|
|
33
|
-
if (typeof value !== "object" || value === null)
|
|
34
|
-
return false;
|
|
35
|
-
// New CompiledChannel shape from defineChannel()
|
|
36
|
-
if (value.__kind === "ash:channel")
|
|
37
|
-
return true;
|
|
38
|
-
// Old Route shape with fetch handler
|
|
39
|
-
return typeof value.fetch === "function";
|
|
40
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AttachmentResolver } from "#channel/adapter.js";
|
|
2
2
|
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
|
|
3
|
+
import type { SessionAuthContext } from "#channel/types.js";
|
|
3
4
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
4
5
|
import type { RouteDefinition, SendFn } from "#channel/routes.js";
|
|
5
6
|
import type { Session, SessionHandle } from "#channel/session.js";
|
|
@@ -34,8 +35,9 @@ export interface ChannelConfig<TState = undefined, TCtx = void> {
|
|
|
34
35
|
context?(state: NonNullable<TState>): TCtx;
|
|
35
36
|
readonly routes: readonly RouteDefinition<TState>[];
|
|
36
37
|
receive?(input: {
|
|
37
|
-
message: string;
|
|
38
|
-
args: Readonly<Record<string, unknown>>;
|
|
38
|
+
readonly message: string;
|
|
39
|
+
readonly args: Readonly<Record<string, unknown>>;
|
|
40
|
+
readonly auth: SessionAuthContext | null;
|
|
39
41
|
}, args: {
|
|
40
42
|
send: SendFn<TState>;
|
|
41
43
|
}): Promise<Session>;
|
|
@@ -55,8 +57,9 @@ export interface Channel<TState = undefined> {
|
|
|
55
57
|
path: string;
|
|
56
58
|
}[];
|
|
57
59
|
readonly receive?: (input: {
|
|
58
|
-
message: string;
|
|
59
|
-
args: Readonly<Record<string, unknown>>;
|
|
60
|
+
readonly message: string;
|
|
61
|
+
readonly args: Readonly<Record<string, unknown>>;
|
|
62
|
+
readonly auth: SessionAuthContext | null;
|
|
60
63
|
}, args: {
|
|
61
64
|
send: SendFn<TState>;
|
|
62
65
|
}) => Promise<Session>;
|
|
@@ -3,10 +3,15 @@ import type { CompiledModuleMap } from "#compiler/module-map.js";
|
|
|
3
3
|
import type { ResolvedChannelDefinition } from "#runtime/types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Resolves one compiled channel entry into a runtime-owned definition
|
|
6
|
-
* with a live `
|
|
6
|
+
* with a live `handler` (the per-route handler authored via `POST` /
|
|
7
|
+
* `GET` / etc. inside `defineChannel`) and the channel's `receive` hook
|
|
8
|
+
* if the author declared one.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* Every authored channel is a `CompiledChannel` from `defineChannel` —
|
|
11
|
+
* the bare `{ fetch, receive? }` Route shape is rejected by
|
|
12
|
+
* {@link normalizeChannelDefinition}. Framework-internal channels
|
|
13
|
+
* (the connection callback route, the `ash` session channel) build
|
|
14
|
+
* `ResolvedChannelDefinition` values directly and do not flow through
|
|
15
|
+
* this resolver.
|
|
11
16
|
*/
|
|
12
17
|
export declare function resolveChannelDefinition(definition: CompiledChannelDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedChannelDefinition>;
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeChannelDefinition } from "#internal/authored-definition/channel.js";
|
|
2
2
|
import { toErrorMessage } from "#shared/errors.js";
|
|
3
3
|
import { createResolvedModuleSourceRef, loadResolvedModuleExport, ResolveAgentError, } from "#runtime/resolve-helpers.js";
|
|
4
4
|
/**
|
|
5
5
|
* Resolves one compiled channel entry into a runtime-owned definition
|
|
6
|
-
* with a live `
|
|
6
|
+
* with a live `handler` (the per-route handler authored via `POST` /
|
|
7
|
+
* `GET` / etc. inside `defineChannel`) and the channel's `receive` hook
|
|
8
|
+
* if the author declared one.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* Every authored channel is a `CompiledChannel` from `defineChannel` —
|
|
11
|
+
* the bare `{ fetch, receive? }` Route shape is rejected by
|
|
12
|
+
* {@link normalizeChannelDefinition}. Framework-internal channels
|
|
13
|
+
* (the connection callback route, the `ash` session channel) build
|
|
14
|
+
* `ResolvedChannelDefinition` values directly and do not flow through
|
|
15
|
+
* this resolver.
|
|
11
16
|
*/
|
|
12
17
|
export async function resolveChannelDefinition(definition, moduleMap, nodeId) {
|
|
13
18
|
try {
|
|
@@ -23,35 +28,23 @@ export async function resolveChannelDefinition(definition, moduleMap, nodeId) {
|
|
|
23
28
|
logicalPath: definition.logicalPath,
|
|
24
29
|
sourceId: definition.sourceId,
|
|
25
30
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (adapter && adapter.kind !== "http") {
|
|
31
|
-
adapter.kind = `channel:${definition.name}`;
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
name: definition.name,
|
|
35
|
-
method: definition.method,
|
|
36
|
-
urlPath: definition.urlPath,
|
|
37
|
-
fetch: async (req, ctx) => {
|
|
38
|
-
if (matchedRoute)
|
|
39
|
-
return matchedRoute.handler(req, ctx);
|
|
40
|
-
return Response.json({ error: "No matching route handler.", ok: false }, { status: 404 });
|
|
41
|
-
},
|
|
42
|
-
handler: matchedRoute?.handler,
|
|
43
|
-
receive: channelDefinition.receive,
|
|
44
|
-
adapter,
|
|
45
|
-
...sourceRef,
|
|
46
|
-
};
|
|
31
|
+
const matchedRoute = channelDefinition.routes.find((r) => r.method.toUpperCase() === definition.method.toUpperCase() && r.path === definition.urlPath);
|
|
32
|
+
const adapter = channelDefinition.adapter;
|
|
33
|
+
if (adapter && adapter.kind !== "http") {
|
|
34
|
+
adapter.kind = `channel:${definition.name}`;
|
|
47
35
|
}
|
|
48
36
|
return {
|
|
49
37
|
name: definition.name,
|
|
50
38
|
method: definition.method,
|
|
51
39
|
urlPath: definition.urlPath,
|
|
52
|
-
fetch:
|
|
40
|
+
fetch: async (req, ctx) => {
|
|
41
|
+
if (matchedRoute)
|
|
42
|
+
return matchedRoute.handler(req, ctx);
|
|
43
|
+
return Response.json({ error: "No matching route handler.", ok: false }, { status: 404 });
|
|
44
|
+
},
|
|
45
|
+
handler: matchedRoute?.handler,
|
|
53
46
|
receive: channelDefinition.receive,
|
|
54
|
-
adapter
|
|
47
|
+
adapter,
|
|
55
48
|
...sourceRef,
|
|
56
49
|
};
|
|
57
50
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { FlexibleSchema } from "ai";
|
|
2
2
|
import type { ChannelAdapter } from "#channel/adapter.js";
|
|
3
|
+
import type { CompiledChannel } from "#channel/compiled-channel.js";
|
|
3
4
|
import type { DiscoverDiagnosticsSummary } from "#discover/diagnostics.js";
|
|
4
|
-
import type { ChannelMethod,
|
|
5
|
+
import type { ChannelMethod, RouteContext } from "#public/definitions/channel.js";
|
|
5
6
|
import type { RouteHandler } from "#channel/routes.js";
|
|
6
7
|
import type { LifecycleHooks, StreamEventHook } from "#public/definitions/hook.js";
|
|
7
8
|
import type { CompactionHookInput, CompactionHookResult, NeedsApprovalContext, ToolRetentionPolicy } from "#public/definitions/tool.js";
|
|
@@ -172,16 +173,20 @@ export interface ResolvedChannelDefinition extends ResolvedModuleSourceRef {
|
|
|
172
173
|
readonly method: ChannelMethod;
|
|
173
174
|
readonly adapter?: ChannelAdapter;
|
|
174
175
|
readonly urlPath: string;
|
|
175
|
-
readonly fetch:
|
|
176
|
+
readonly fetch: (req: Request, ctx: RouteContext) => Promise<Response>;
|
|
176
177
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
178
|
+
* Universal entry point for new sessions, called by cross-channel
|
|
179
|
+
* initiators (the schedule dispatcher today). Typed precisely as
|
|
180
|
+
* {@link CompiledChannel.receive} — `(input, { send }) => Session` —
|
|
181
|
+
* so any caller passing the wrong context shape is a typecheck error,
|
|
182
|
+
* not a runtime crash.
|
|
179
183
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* `
|
|
184
|
+
* Old Route-style channels do not flow `receive` through here. The
|
|
185
|
+
* resolver sets it to `undefined` for those; callers that need
|
|
186
|
+
* `receive` then throw with a clear error rather than silently
|
|
187
|
+
* accepting a different shape.
|
|
183
188
|
*/
|
|
184
|
-
readonly receive?:
|
|
189
|
+
readonly receive?: CompiledChannel["receive"];
|
|
185
190
|
/**
|
|
186
191
|
* New-style route handler from CompiledChannel. When present, the
|
|
187
192
|
* dispatch layer uses this instead of `fetch`.
|