experimental-ash 0.7.0 → 0.7.2
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/external-agent-protocol.md +5 -5
- package/dist/docs/internals/message-runtime.md +4 -4
- package/dist/docs/public/auth-and-route-protection.md +10 -10
- package/dist/docs/public/channels/README.md +9 -6
- package/dist/docs/public/cli-build-and-debugging.md +1 -2
- package/dist/docs/public/getting-started.md +0 -11
- package/dist/docs/public/skills.md +2 -2
- package/dist/docs/public/typescript-api.md +1 -1
- package/dist/src/chunks/{dev-authored-source-watcher-HzOplr1S.js → dev-authored-source-watcher-D3ybKVO9.js} +1 -1
- package/dist/src/chunks/{host-Ca8xvEQ1.js → host-Ck0qkepf.js} +2 -2
- package/dist/src/chunks/{paths-BiY7uVwD.js → paths-BFX2EgQO.js} +21 -21
- package/dist/src/chunks/{prewarm-DiZ_sYLy.js → prewarm-DJtOdukm.js} +1 -1
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/run.d.ts +0 -5
- package/dist/src/cli/run.js +2 -2
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/public/channels/{http.d.ts → ash.d.ts} +2 -2
- package/dist/src/public/channels/{http.js → ash.js} +2 -2
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/channels/slack/attachments.d.ts +35 -0
- package/dist/src/public/channels/slack/attachments.js +100 -0
- package/dist/src/public/channels/slack/hitl.d.ts +67 -0
- package/dist/src/public/channels/slack/hitl.js +101 -0
- package/dist/src/public/channels/slack/index.d.ts +1 -0
- package/dist/src/public/channels/slack/slackChannel.d.ts +13 -0
- package/dist/src/public/channels/slack/slackChannel.js +40 -47
- package/dist/src/public/definitions/defineChannel.d.ts +9 -0
- package/dist/src/public/definitions/defineChannel.js +10 -8
- package/dist/src/runtime/framework-channels/index.d.ts +1 -1
- package/dist/src/runtime/framework-channels/index.js +7 -7
- package/package.json +5 -5
- package/dist/src/cli/commands/init.d.ts +0 -13
- package/dist/src/cli/commands/init.js +0 -1
- package/dist/src/cli/templates/init-app/.vercelignore +0 -11
- package/dist/src/cli/templates/init-app/agent/agent.ts +0 -5
- package/dist/src/cli/templates/init-app/agent/instructions.md +0 -3
- package/dist/src/cli/templates/init-app/agent/tools/hello.ts +0 -12
- package/dist/src/cli/templates/init-app/gitignore +0 -8
- package/dist/src/cli/templates/init-app/package.json +0 -18
- package/dist/src/cli/templates/init-app/tsconfig.json +0 -16
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { defineChannel, POST, } from "#public/definitions/defineChannel.js";
|
|
2
1
|
import { createLogger } from "#internal/logging.js";
|
|
2
|
+
import { buildSlackTurnMessage, collectSlackFileParts, createSlackAttachmentResolver, } from "#public/channels/slack/attachments.js";
|
|
3
|
+
import { deriveHitlResponse, isHitlAction, renderInputRequestBlocks, } from "#public/channels/slack/hitl.js";
|
|
4
|
+
import { mergeUploadPolicy } from "#public/channels/upload-policy.js";
|
|
5
|
+
import { defineChannel, POST, } from "#public/definitions/defineChannel.js";
|
|
3
6
|
const log = createLogger("slack.channel");
|
|
4
7
|
function decodeThreadId(id) {
|
|
5
8
|
const parts = id.replace(/^slack:/u, "").split(":");
|
|
@@ -31,30 +34,6 @@ function buildSlackApiHandle(thread, botToken, teamId) {
|
|
|
31
34
|
},
|
|
32
35
|
};
|
|
33
36
|
}
|
|
34
|
-
function renderInputRequestBlocks(requests) {
|
|
35
|
-
const blocks = [];
|
|
36
|
-
for (const request of requests) {
|
|
37
|
-
blocks.push({ type: "section", text: { type: "mrkdwn", text: request.prompt } });
|
|
38
|
-
if (request.options && request.options.length > 0) {
|
|
39
|
-
blocks.push({
|
|
40
|
-
type: "actions",
|
|
41
|
-
elements: request.options.map((opt) => {
|
|
42
|
-
const button = {
|
|
43
|
-
type: "button",
|
|
44
|
-
text: { type: "plain_text", text: opt.label },
|
|
45
|
-
action_id: `ash_input_${request.requestId}_${opt.id}`,
|
|
46
|
-
value: opt.id,
|
|
47
|
-
};
|
|
48
|
-
if (opt.style === "primary" || opt.style === "danger") {
|
|
49
|
-
button.style = opt.style;
|
|
50
|
-
}
|
|
51
|
-
return button;
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return blocks;
|
|
57
|
-
}
|
|
58
37
|
function parseBlockActionsPayload(body) {
|
|
59
38
|
const actions = body.actions;
|
|
60
39
|
if (!Array.isArray(actions))
|
|
@@ -76,6 +55,7 @@ function parseBlockActionsPayload(body) {
|
|
|
76
55
|
actionId: String(a.action_id ?? ""),
|
|
77
56
|
value: a.value != null ? String(a.value) : undefined,
|
|
78
57
|
blockId: a.block_id != null ? String(a.block_id) : undefined,
|
|
58
|
+
selectedOptionValue: extractSelectedOptionValue(a),
|
|
79
59
|
messageTs,
|
|
80
60
|
})),
|
|
81
61
|
channelId: channel,
|
|
@@ -83,6 +63,16 @@ function parseBlockActionsPayload(body) {
|
|
|
83
63
|
teamId,
|
|
84
64
|
};
|
|
85
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Reads `selected_option.value` off a `block_actions` action entry.
|
|
68
|
+
* Slack populates this on `radio_buttons` / `static_select` /
|
|
69
|
+
* `external_select` clicks. Multi-select widgets surface
|
|
70
|
+
* `selected_options[]` instead and are not consumed here.
|
|
71
|
+
*/
|
|
72
|
+
function extractSelectedOptionValue(action) {
|
|
73
|
+
const selected = action.selected_option;
|
|
74
|
+
return typeof selected?.value === "string" ? selected.value : undefined;
|
|
75
|
+
}
|
|
86
76
|
function rebuildSlackContext(state, botToken) {
|
|
87
77
|
const chatModule = require("#compiled/chat/index.js");
|
|
88
78
|
const thread = state.serializedThread
|
|
@@ -99,24 +89,29 @@ function rebuildSlackContext(state, botToken) {
|
|
|
99
89
|
};
|
|
100
90
|
}
|
|
101
91
|
/**
|
|
102
|
-
* Default input.requested handler — renders
|
|
103
|
-
* as Slack block_actions
|
|
92
|
+
* Default `input.requested` handler — renders each pending HITL
|
|
93
|
+
* request as Slack `block_actions`. Buttons by default; radio for
|
|
94
|
+
* ≤6-option select requests; static_select for >6-option select
|
|
95
|
+
* requests. Override by declaring `events["input.requested"]`.
|
|
104
96
|
*/
|
|
105
97
|
function defaultInputRequestedHandler() {
|
|
106
98
|
return async (data, ctx) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
99
|
+
if (data.requests.length === 0)
|
|
100
|
+
return;
|
|
101
|
+
const decoded = decodeThreadId(ctx.thread.id ?? "");
|
|
102
|
+
await ctx.slack.request("chat.postMessage", {
|
|
103
|
+
channel: decoded.channelId,
|
|
104
|
+
thread_ts: decoded.threadTs,
|
|
105
|
+
blocks: data.requests.flatMap(renderInputRequestBlocks),
|
|
106
|
+
text: data.requests.map((r) => r.prompt).join("\n"),
|
|
107
|
+
});
|
|
117
108
|
};
|
|
118
109
|
}
|
|
119
110
|
export function slackChannel(config = {}) {
|
|
111
|
+
const uploadPolicy = mergeUploadPolicy(config.uploadPolicy);
|
|
112
|
+
const slackAttachments = createSlackAttachmentResolver({
|
|
113
|
+
botToken: config.credentials?.botToken,
|
|
114
|
+
});
|
|
120
115
|
let activeSend = null;
|
|
121
116
|
let chatPromise = null;
|
|
122
117
|
async function getChat() {
|
|
@@ -166,7 +161,9 @@ export function slackChannel(config = {}) {
|
|
|
166
161
|
return;
|
|
167
162
|
const decoded = decodeThreadId(thread.id ?? "");
|
|
168
163
|
const continuationToken = `slack:${decoded.channelId}:${decoded.threadTs}`;
|
|
169
|
-
|
|
164
|
+
const fileParts = collectSlackFileParts(message, uploadPolicy);
|
|
165
|
+
const turnMessage = buildSlackTurnMessage(message.text, fileParts);
|
|
166
|
+
await send(turnMessage, {
|
|
170
167
|
auth: runOpts.auth,
|
|
171
168
|
continuationToken,
|
|
172
169
|
state: {
|
|
@@ -183,10 +180,10 @@ export function slackChannel(config = {}) {
|
|
|
183
180
|
});
|
|
184
181
|
return promise;
|
|
185
182
|
}
|
|
186
|
-
// Build the effective event handlers, applying defaults
|
|
187
183
|
const inputHandler = config.events?.["input.requested"] ?? defaultInputRequestedHandler();
|
|
188
184
|
return defineChannel({
|
|
189
185
|
state: { serializedThread: null, teamId: null },
|
|
186
|
+
attachments: slackAttachments,
|
|
190
187
|
context(state) {
|
|
191
188
|
return rebuildSlackContext(state, config.credentials?.botToken);
|
|
192
189
|
},
|
|
@@ -206,13 +203,9 @@ export function slackChannel(config = {}) {
|
|
|
206
203
|
const continuationToken = `slack:${interaction.channelId}:${interaction.threadTs}`;
|
|
207
204
|
const inputResponses = [];
|
|
208
205
|
for (const action of interaction.actions) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const optionId = action.value;
|
|
213
|
-
if (requestId && optionId) {
|
|
214
|
-
inputResponses.push({ requestId, optionId });
|
|
215
|
-
}
|
|
206
|
+
const response = deriveHitlResponse(action);
|
|
207
|
+
if (response !== null) {
|
|
208
|
+
inputResponses.push(response);
|
|
216
209
|
}
|
|
217
210
|
}
|
|
218
211
|
if (inputResponses.length > 0) {
|
|
@@ -228,7 +221,7 @@ export function slackChannel(config = {}) {
|
|
|
228
221
|
}));
|
|
229
222
|
}
|
|
230
223
|
if (config.onInteraction) {
|
|
231
|
-
const customActions = interaction.actions.filter((a) => !a.actionId
|
|
224
|
+
const customActions = interaction.actions.filter((a) => !isHitlAction(a.actionId));
|
|
232
225
|
if (customActions.length > 0) {
|
|
233
226
|
const chatModule = await import("#compiled/chat/index.js");
|
|
234
227
|
const thread = new chatModule.ThreadImpl({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AttachmentResolver } from "#channel/adapter.js";
|
|
1
2
|
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
|
|
2
3
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
3
4
|
import type { RouteDefinition, SendFn } from "#channel/routes.js";
|
|
@@ -5,6 +6,7 @@ import type { Session, SessionHandle } from "#channel/session.js";
|
|
|
5
6
|
export type { Session, SessionHandle } from "#channel/session.js";
|
|
6
7
|
export { POST, GET, PUT, DELETE } from "#channel/routes.js";
|
|
7
8
|
export type { RouteDefinition, RouteHandlerArgs, SendFn, SendOptions, SendPayload, GetSessionFn, } from "#channel/routes.js";
|
|
9
|
+
export type { AttachmentResolver } from "#channel/adapter.js";
|
|
8
10
|
type EventData<T extends HandleMessageStreamEvent["type"]> = Extract<HandleMessageStreamEvent, {
|
|
9
11
|
type: T;
|
|
10
12
|
}> extends {
|
|
@@ -38,6 +40,13 @@ export interface ChannelConfig<TState = undefined, TCtx = void> {
|
|
|
38
40
|
send: SendFn<TState>;
|
|
39
41
|
}): Promise<Session>;
|
|
40
42
|
readonly events?: ChannelEvents<TCtx>;
|
|
43
|
+
/**
|
|
44
|
+
* Resolver for `ash-attachment:` URLs this channel mints during
|
|
45
|
+
* inbound message handling. The framework's staging layer dispatches
|
|
46
|
+
* to `resolve(ref, ctx)` before each model call so the bytes can be
|
|
47
|
+
* written to the sandbox and rewritten as `ash-sandbox:` refs.
|
|
48
|
+
*/
|
|
49
|
+
readonly attachments?: AttachmentResolver;
|
|
41
50
|
}
|
|
42
51
|
export interface Channel<TState = undefined> {
|
|
43
52
|
readonly __kind: typeof CHANNEL_SENTINEL;
|
|
@@ -14,6 +14,7 @@ export function defineChannel(config) {
|
|
|
14
14
|
function buildAdapter(config) {
|
|
15
15
|
const hasState = config.state != null;
|
|
16
16
|
const hasContext = config.context != null;
|
|
17
|
+
const hasAttachments = config.attachments !== undefined;
|
|
17
18
|
const hasBehavior = hasState || hasContext;
|
|
18
19
|
const eventHandlers = {};
|
|
19
20
|
let hasEventHandlers = false;
|
|
@@ -41,19 +42,20 @@ function buildAdapter(config) {
|
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
// When the channel
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
if (!hasBehavior && !hasEventHandlers) {
|
|
45
|
+
// When the channel carries no behavior at all, return a bare
|
|
46
|
+
// pass-through adapter with framework kind "http". This avoids the
|
|
47
|
+
// registry conflict when the adapter would otherwise reserve a
|
|
48
|
+
// framework kind with no behavior to register against it.
|
|
49
|
+
if (!hasBehavior && !hasEventHandlers && !hasAttachments) {
|
|
49
50
|
return { kind: "http" };
|
|
50
51
|
}
|
|
51
|
-
// Channels with
|
|
52
|
-
//
|
|
53
|
-
//
|
|
52
|
+
// Channels with any authored behavior use a dedicated adapter kind so
|
|
53
|
+
// the registry can rehydrate it across step boundaries without
|
|
54
|
+
// conflicting with framework-reserved kinds.
|
|
54
55
|
return {
|
|
55
56
|
kind: "defineChannel",
|
|
56
57
|
state: hasState ? { ...config.state } : {},
|
|
58
|
+
attachments: config.attachments,
|
|
57
59
|
createAdapterContext(base) {
|
|
58
60
|
const state = base.state;
|
|
59
61
|
const channelCtx = hasContext ? config.context(state) : {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ResolvedChannelDefinition } from "#runtime/types.js";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const ASH_CHANNEL_NAME = "ash";
|
|
3
3
|
export declare function getFrameworkChannelDefinitions(): readonly ResolvedChannelDefinition[];
|
|
4
4
|
export declare function getAllFrameworkChannelNames(): ReadonlySet<string>;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { none, vercelOidc } from "#public/channels/auth.js";
|
|
2
|
-
import {
|
|
2
|
+
import { ashChannel } from "#public/channels/ash.js";
|
|
3
3
|
import { getConnectionCallbackChannelDefinitions, getConnectionCallbackChannelNames, } from "#runtime/connections/callback-route.js";
|
|
4
|
-
export const
|
|
4
|
+
export const ASH_CHANNEL_NAME = "ash";
|
|
5
5
|
export function getFrameworkChannelDefinitions() {
|
|
6
|
-
const auth =
|
|
7
|
-
const compiled =
|
|
6
|
+
const auth = resolveFrameworkAshAuth();
|
|
7
|
+
const compiled = ashChannel({ auth });
|
|
8
8
|
const result = [];
|
|
9
9
|
for (const route of compiled.routes) {
|
|
10
10
|
result.push({
|
|
11
|
-
name:
|
|
11
|
+
name: ASH_CHANNEL_NAME,
|
|
12
12
|
method: route.method.toUpperCase(),
|
|
13
13
|
urlPath: route.path,
|
|
14
14
|
fetch: async (req, ctx) => route.handler(req, ctx),
|
|
@@ -23,9 +23,9 @@ export function getFrameworkChannelDefinitions() {
|
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
25
|
export function getAllFrameworkChannelNames() {
|
|
26
|
-
return new Set([
|
|
26
|
+
return new Set([ASH_CHANNEL_NAME, ...getConnectionCallbackChannelNames()]);
|
|
27
27
|
}
|
|
28
|
-
function
|
|
28
|
+
function resolveFrameworkAshAuth() {
|
|
29
29
|
if (process.env.VERCEL) {
|
|
30
30
|
return vercelOidc();
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "experimental-ash",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"bin": {
|
|
5
5
|
"ash": "./bin/ash.js",
|
|
6
6
|
"experimental-ash": "./bin/ash.js"
|
|
@@ -120,10 +120,10 @@
|
|
|
120
120
|
"import": "./dist/src/public/channels/index.js",
|
|
121
121
|
"default": "./dist/src/public/channels/index.js"
|
|
122
122
|
},
|
|
123
|
-
"./channels/
|
|
124
|
-
"types": "./dist/src/public/channels/
|
|
125
|
-
"import": "./dist/src/public/channels/
|
|
126
|
-
"default": "./dist/src/public/channels/
|
|
123
|
+
"./channels/ash": {
|
|
124
|
+
"types": "./dist/src/public/channels/ash.d.ts",
|
|
125
|
+
"import": "./dist/src/public/channels/ash.js",
|
|
126
|
+
"default": "./dist/src/public/channels/ash.js"
|
|
127
127
|
},
|
|
128
128
|
"./channels/auth": {
|
|
129
129
|
"types": "./dist/src/public/channels/auth.d.ts",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
interface CliInitLogger {
|
|
2
|
-
log(message: string): void;
|
|
3
|
-
}
|
|
4
|
-
interface InitializeApplicationInput {
|
|
5
|
-
readonly logger: CliInitLogger;
|
|
6
|
-
readonly parentDirectoryPath: string;
|
|
7
|
-
readonly targetName: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Scaffolds a new Ash application directory from the package-owned init template.
|
|
11
|
-
*/
|
|
12
|
-
export declare function initializeApplication(input: InitializeApplicationInput): Promise<string>;
|
|
13
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e,t}from"../../chunks/package-DmsQgn4v.js";import{createCliTheme as n,renderCliTaggedLine as r}from"../ui/output.js";import{basename as i,dirname as a,extname as o,join as s,resolve as c}from"node:path";import{access as l,cp as u,mkdir as d,readFile as f,readdir as p,rm as m,writeFile as h}from"node:fs/promises";const g=new Set([`.json`,`.md`,`.ts`]),_=new Set([`.gitignore`,`.vercelignore`,`gitignore`]);function v(e){return _.has(e)||g.has(o(e))}async function y(e){try{return await l(e),!0}catch{return!1}}function b(){return e(`src/cli/templates/init-app`)}async function x(e,t){let n=await p(e,{withFileTypes:!0});await Promise.all(n.map(async n=>{let r=s(e,n.name);if(n.isDirectory()){await x(r,t);return}if(!n.isFile()||!v(n.name))return;let i=await f(r,`utf8`),a=s(e,n.name===`gitignore`?`.gitignore`:n.name);for(let[e,n]of Object.entries(t))i=i.replaceAll(e,n);await h(a,i,`utf8`),n.name===`gitignore`&&await m(r)}))}async function S(e){let o=c(e.parentDirectoryPath,e.targetName);if(await y(o))throw Error(`Cannot initialize Ash app because "${o}" already exists.`);let s=i(o);if(s.trim().length===0)throw Error(`Cannot initialize Ash app because "${e.targetName}" is not a valid name.`);let l=t();await d(a(o),{recursive:!0}),await u(b(),o,{recursive:!0}),await x(o,{__ASH_INIT_APP_NAME__:s,__ASH_INIT_PACKAGE_VERSION__:`^${l.version}`});let f=n();return e.logger.log(r(f,{message:`created ${o}`,tag:`init`,tone:`success`})),e.logger.log(r(f,{message:`next: cd ${o}\npnpm install\npnpm dev`,tag:`init`,tone:`info`})),o}export{S as initializeApplication};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineTool } from "experimental-ash/tools";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
|
|
4
|
-
export default defineTool({
|
|
5
|
-
description: "Say hello",
|
|
6
|
-
inputSchema: z.object({
|
|
7
|
-
greeting: z.string(),
|
|
8
|
-
}),
|
|
9
|
-
async execute(input) {
|
|
10
|
-
return `Hello, ${input.greeting}!`;
|
|
11
|
-
},
|
|
12
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__ASH_INIT_APP_NAME__",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"type": "module",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"build": "ash build",
|
|
7
|
-
"dev": "ash dev",
|
|
8
|
-
"typecheck": "tsgo"
|
|
9
|
-
},
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"ai": "7.0.0-canary.131",
|
|
12
|
-
"experimental-ash": "__ASH_INIT_PACKAGE_VERSION__",
|
|
13
|
-
"zod": "^4.3.6"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@typescript/native-preview": "7.0.0-dev.20260320.1"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "dist",
|
|
7
|
-
"rootDir": ".",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"declaration": true,
|
|
13
|
-
"noEmit": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["agent/**/*.ts", "evals/**/*.ts", ".ash/**/*.d.ts"]
|
|
16
|
-
}
|