@adia-ai/agent 0.8.26
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 +7 -0
- package/README.md +172 -0
- package/agent.d.ts +53 -0
- package/agent.d.ts.map +1 -0
- package/agent.js +99 -0
- package/agent.js.map +1 -0
- package/events.d.ts +92 -0
- package/events.d.ts.map +1 -0
- package/events.js +112 -0
- package/events.js.map +1 -0
- package/frame.d.ts +60 -0
- package/frame.d.ts.map +1 -0
- package/frame.js +43 -0
- package/frame.js.map +1 -0
- package/index.d.ts +28 -0
- package/index.d.ts.map +1 -0
- package/index.js +18 -0
- package/index.js.map +1 -0
- package/integrations.d.ts +105 -0
- package/integrations.d.ts.map +1 -0
- package/integrations.js +167 -0
- package/integrations.js.map +1 -0
- package/loop.d.ts +44 -0
- package/loop.d.ts.map +1 -0
- package/loop.js +120 -0
- package/loop.js.map +1 -0
- package/package.json +41 -0
- package/prompt.d.ts +36 -0
- package/prompt.d.ts.map +1 -0
- package/prompt.js +38 -0
- package/prompt.js.map +1 -0
- package/resource.d.ts +27 -0
- package/resource.d.ts.map +1 -0
- package/resource.js +46 -0
- package/resource.js.map +1 -0
- package/session.d.ts +30 -0
- package/session.d.ts.map +1 -0
- package/session.js +30 -0
- package/session.js.map +1 -0
- package/stub.d.ts +22 -0
- package/stub.d.ts.map +1 -0
- package/stub.js +52 -0
- package/stub.js.map +1 -0
- package/tools.d.ts +43 -0
- package/tools.d.ts.map +1 -0
- package/tools.js +103 -0
- package/tools.js.map +1 -0
- package/workflow.d.ts +44 -0
- package/workflow.d.ts.map +1 -0
- package/workflow.js +36 -0
- package/workflow.js.map +1 -0
package/prompt.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt layers — ordered, composable system-prompt assembly.
|
|
3
|
+
*
|
|
4
|
+
* A layer is static text (cacheable) or a function (resolved fresh every
|
|
5
|
+
* turn, never cached). composeSystem() places static layers first so the
|
|
6
|
+
* cache breakpoint covers the stable prefix, then dynamic layers.
|
|
7
|
+
*
|
|
8
|
+
* Two output shapes, provider-decided by the agent:
|
|
9
|
+
* - Anthropic: an array of system text blocks with `cache_control:
|
|
10
|
+
* { type: 'ephemeral' }` on the LAST static layer — dynamic layers ride
|
|
11
|
+
* after the breakpoint, so a per-turn context layer never busts the
|
|
12
|
+
* cached identity/capabilities prefix.
|
|
13
|
+
* - Everyone else: one joined string (their adapters take system as text).
|
|
14
|
+
*/
|
|
15
|
+
export interface PromptLayer {
|
|
16
|
+
name: string;
|
|
17
|
+
text: string | (() => string);
|
|
18
|
+
cache?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function promptLayer(name: string, text: string | (() => string), opts?: {
|
|
21
|
+
cache?: boolean;
|
|
22
|
+
}): PromptLayer;
|
|
23
|
+
export interface ComposedSystem {
|
|
24
|
+
/** Joined plain-text form — for providers whose system is a string. */
|
|
25
|
+
text: string;
|
|
26
|
+
/** Block-array form with cache_control markers — for Anthropic. */
|
|
27
|
+
blocks: Array<{
|
|
28
|
+
type: string;
|
|
29
|
+
text: string;
|
|
30
|
+
cache_control?: {
|
|
31
|
+
type: string;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export declare function composeSystem(layers: PromptLayer[]): ComposedSystem;
|
|
36
|
+
//# sourceMappingURL=prompt.d.ts.map
|
package/prompt.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,EAC7B,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,WAAW,CAKb;AAED,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CACjF;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,cAAc,CAqBnE"}
|
package/prompt.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt layers — ordered, composable system-prompt assembly.
|
|
3
|
+
*
|
|
4
|
+
* A layer is static text (cacheable) or a function (resolved fresh every
|
|
5
|
+
* turn, never cached). composeSystem() places static layers first so the
|
|
6
|
+
* cache breakpoint covers the stable prefix, then dynamic layers.
|
|
7
|
+
*
|
|
8
|
+
* Two output shapes, provider-decided by the agent:
|
|
9
|
+
* - Anthropic: an array of system text blocks with `cache_control:
|
|
10
|
+
* { type: 'ephemeral' }` on the LAST static layer — dynamic layers ride
|
|
11
|
+
* after the breakpoint, so a per-turn context layer never busts the
|
|
12
|
+
* cached identity/capabilities prefix.
|
|
13
|
+
* - Everyone else: one joined string (their adapters take system as text).
|
|
14
|
+
*/
|
|
15
|
+
export function promptLayer(name, text, opts = {}) {
|
|
16
|
+
if (typeof text === 'function' && opts.cache) {
|
|
17
|
+
throw new Error(`promptLayer "${name}": a function layer resolves per turn and cannot be cached`);
|
|
18
|
+
}
|
|
19
|
+
return { name, text, ...(opts.cache ? { cache: true } : {}) };
|
|
20
|
+
}
|
|
21
|
+
export function composeSystem(layers) {
|
|
22
|
+
const staticLayers = layers.filter(l => typeof l.text === 'string');
|
|
23
|
+
const dynamicLayers = layers.filter(l => typeof l.text === 'function');
|
|
24
|
+
const resolve = (l) => typeof l.text === 'function' ? l.text() : l.text;
|
|
25
|
+
const ordered = [...staticLayers, ...dynamicLayers];
|
|
26
|
+
const texts = ordered.map(resolve).filter(Boolean);
|
|
27
|
+
const lastCached = [...staticLayers].reverse().find(l => l.cache);
|
|
28
|
+
const blocks = ordered
|
|
29
|
+
.map((l, i) => ({ layer: l, text: texts[i] ?? '' }))
|
|
30
|
+
.filter(e => e.text)
|
|
31
|
+
.map(e => ({
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: e.text,
|
|
34
|
+
...(e.layer === lastCached ? { cache_control: { type: 'ephemeral' } } : {}),
|
|
35
|
+
}));
|
|
36
|
+
return { text: texts.join('\n\n'), blocks };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=prompt.js.map
|
package/prompt.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,IAA6B,EAC7B,OAA4B,EAAE;IAE9B,IAAI,OAAO,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,4DAA4D,CAAC,CAAC;IACpG,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAChE,CAAC;AASD,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACpE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,CAAC,CAAc,EAAU,EAAE,CACzC,OAAO,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnD,MAAM,OAAO,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,aAAa,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnD,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,OAAO;SACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;SACnD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACnB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACT,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAC,CAAC,CAAC;IAEN,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;AAC9C,CAAC"}
|
package/resource.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources — declared ways to bring outside information in.
|
|
3
|
+
*
|
|
4
|
+
* Two modes, mirroring the MCP resource/tool distinction, both riding
|
|
5
|
+
* machinery the harness already has:
|
|
6
|
+
* - 'attach' — application-controlled: the resource is fetched by the
|
|
7
|
+
* harness each turn and attached as a dynamic prompt layer. The model
|
|
8
|
+
* never asks; the data is just there.
|
|
9
|
+
* - 'tool' — model-controlled: the resource becomes a read-only tool
|
|
10
|
+
* (`read_<name>`) the model calls when it decides it needs the data.
|
|
11
|
+
*/
|
|
12
|
+
import type { PromptLayer } from './prompt.js';
|
|
13
|
+
import { type ToolDef } from './tools.js';
|
|
14
|
+
export interface ResourceDef {
|
|
15
|
+
name: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
mode: 'attach' | 'tool';
|
|
18
|
+
get: (input?: Record<string, unknown>) => string | Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function defineResource(def: ResourceDef): ResourceDef;
|
|
21
|
+
/** Attach-mode resources → dynamic prompt layers. Resolution happens at
|
|
22
|
+
* compose time (async), so the layer text is a plain string by the time
|
|
23
|
+
* it reaches composeSystem. */
|
|
24
|
+
export declare function attachLayers(resources: ResourceDef[]): Promise<PromptLayer[]>;
|
|
25
|
+
/** Tool-mode resources → read-only tools the model can call. */
|
|
26
|
+
export declare function resourceTools(resources: ResourceDef[]): ToolDef[];
|
|
27
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["src/resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAS5D;AAED;;gCAEgC;AAChC,wBAAsB,YAAY,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAOnF;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,OAAO,EAAE,CASjE"}
|
package/resource.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources — declared ways to bring outside information in.
|
|
3
|
+
*
|
|
4
|
+
* Two modes, mirroring the MCP resource/tool distinction, both riding
|
|
5
|
+
* machinery the harness already has:
|
|
6
|
+
* - 'attach' — application-controlled: the resource is fetched by the
|
|
7
|
+
* harness each turn and attached as a dynamic prompt layer. The model
|
|
8
|
+
* never asks; the data is just there.
|
|
9
|
+
* - 'tool' — model-controlled: the resource becomes a read-only tool
|
|
10
|
+
* (`read_<name>`) the model calls when it decides it needs the data.
|
|
11
|
+
*/
|
|
12
|
+
import { defineTool } from './tools.js';
|
|
13
|
+
export function defineResource(def) {
|
|
14
|
+
if (!def.name)
|
|
15
|
+
throw new Error('defineResource: name is required');
|
|
16
|
+
if (def.mode !== 'attach' && def.mode !== 'tool') {
|
|
17
|
+
throw new Error(`defineResource "${def.name}": mode is 'attach' | 'tool'`);
|
|
18
|
+
}
|
|
19
|
+
if (typeof def.get !== 'function') {
|
|
20
|
+
throw new Error(`defineResource "${def.name}": get() is required`);
|
|
21
|
+
}
|
|
22
|
+
return def;
|
|
23
|
+
}
|
|
24
|
+
/** Attach-mode resources → dynamic prompt layers. Resolution happens at
|
|
25
|
+
* compose time (async), so the layer text is a plain string by the time
|
|
26
|
+
* it reaches composeSystem. */
|
|
27
|
+
export async function attachLayers(resources) {
|
|
28
|
+
const attach = resources.filter(r => r.mode === 'attach');
|
|
29
|
+
const resolved = await Promise.all(attach.map(async (r) => ({
|
|
30
|
+
name: `resource:${r.name}`,
|
|
31
|
+
text: `<resource name="${r.name}"${r.description ? ` description="${r.description}"` : ''}>\n${await r.get()}\n</resource>`,
|
|
32
|
+
})));
|
|
33
|
+
return resolved.filter(l => l.text);
|
|
34
|
+
}
|
|
35
|
+
/** Tool-mode resources → read-only tools the model can call. */
|
|
36
|
+
export function resourceTools(resources) {
|
|
37
|
+
return resources
|
|
38
|
+
.filter(r => r.mode === 'tool')
|
|
39
|
+
.map(r => defineTool({
|
|
40
|
+
name: `read_${r.name.replace(/[^a-zA-Z0-9_-]/g, '_')}`,
|
|
41
|
+
description: r.description ?? `Read the "${r.name}" resource`,
|
|
42
|
+
inputSchema: { type: 'object', properties: {} },
|
|
43
|
+
execute: (input) => r.get(input),
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=resource.js.map
|
package/resource.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["src/resource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,UAAU,EAAgB,MAAM,YAAY,CAAC;AAStD,MAAM,UAAU,cAAc,CAAC,GAAgB;IAC7C,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACnE,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,IAAI,8BAA8B,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,IAAI,sBAAsB,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;gCAEgC;AAChC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAwB;IACzD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAC,CAAC,EAAC,EAAE,CAAC,CAAC;QACxD,IAAI,EAAE,YAAY,CAAC,CAAC,IAAI,EAAE;QAC1B,IAAI,EAAE,mBAAmB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,MAAM,CAAC,CAAC,GAAG,EAAE,eAAe;KAC5H,CAAC,CAAC,CAAC,CAAC;IACL,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,aAAa,CAAC,SAAwB;IACpD,OAAO,SAAS;SACb,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC;QACnB,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE;QACtD,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,aAAa,CAAC,CAAC,IAAI,YAAY;QAC7D,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QAC/C,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;KACjC,CAAC,CAAC,CAAC;AACR,CAAC"}
|
package/session.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session — the serializable conversation state.
|
|
3
|
+
*
|
|
4
|
+
* The caller owns persistence: a Session is a plain JSON-safe object
|
|
5
|
+
* (localStorage, a DB row, a URL — the package never stores one). All
|
|
6
|
+
* mutation flows through `reduce()` (events.ts), which returns a new
|
|
7
|
+
* Session; nothing in this package holds a reference to the caller's.
|
|
8
|
+
*
|
|
9
|
+
* `draft` is reduce()'s in-flight assistant turn (text snapshot + parts
|
|
10
|
+
* accumulated between a round's first chunk and its close). It is part of
|
|
11
|
+
* the serialized shape on purpose — resuming mid-turn drops nothing.
|
|
12
|
+
*/
|
|
13
|
+
import type { Part } from '@adia-ai/llm';
|
|
14
|
+
export interface Msg {
|
|
15
|
+
role: 'user' | 'assistant' | 'tool';
|
|
16
|
+
content: string | Part[];
|
|
17
|
+
}
|
|
18
|
+
export interface Draft {
|
|
19
|
+
text: string;
|
|
20
|
+
parts: Part[];
|
|
21
|
+
}
|
|
22
|
+
export interface Session {
|
|
23
|
+
id: string;
|
|
24
|
+
messages: Msg[];
|
|
25
|
+
draft?: Draft;
|
|
26
|
+
}
|
|
27
|
+
export declare function createSession(id?: string): Session;
|
|
28
|
+
export declare function toJSON(session: Session): string;
|
|
29
|
+
export declare function fromJSON(json: string): Session;
|
|
30
|
+
//# sourceMappingURL=session.d.ts.map
|
package/session.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,IAAI,EAAE,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAID,wBAAgB,aAAa,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKlD;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAE/C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAM9C"}
|
package/session.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session — the serializable conversation state.
|
|
3
|
+
*
|
|
4
|
+
* The caller owns persistence: a Session is a plain JSON-safe object
|
|
5
|
+
* (localStorage, a DB row, a URL — the package never stores one). All
|
|
6
|
+
* mutation flows through `reduce()` (events.ts), which returns a new
|
|
7
|
+
* Session; nothing in this package holds a reference to the caller's.
|
|
8
|
+
*
|
|
9
|
+
* `draft` is reduce()'s in-flight assistant turn (text snapshot + parts
|
|
10
|
+
* accumulated between a round's first chunk and its close). It is part of
|
|
11
|
+
* the serialized shape on purpose — resuming mid-turn drops nothing.
|
|
12
|
+
*/
|
|
13
|
+
let sessionCounter = 0;
|
|
14
|
+
export function createSession(id) {
|
|
15
|
+
return {
|
|
16
|
+
id: id ?? `s_${Date.now().toString(36)}_${++sessionCounter}`,
|
|
17
|
+
messages: [],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function toJSON(session) {
|
|
21
|
+
return JSON.stringify(session);
|
|
22
|
+
}
|
|
23
|
+
export function fromJSON(json) {
|
|
24
|
+
const parsed = JSON.parse(json);
|
|
25
|
+
if (!parsed || typeof parsed.id !== 'string' || !Array.isArray(parsed.messages)) {
|
|
26
|
+
throw new Error('Not a serialized Session: expected { id, messages[] }');
|
|
27
|
+
}
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=session.js.map
|
package/session.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH,IAAI,cAAc,GAAG,CAAC,CAAC;AAEvB,MAAM,UAAU,aAAa,CAAC,EAAW;IACvC,OAAO;QACL,EAAE,EAAE,EAAE,IAAI,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE;QAC5D,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAgB;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IAC3C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/stub.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scriptClient — a deterministic LLMClient for tests.
|
|
3
|
+
*
|
|
4
|
+
* Feed it turns; each chat()/stream() call consumes the next one. A turn
|
|
5
|
+
* with toolUse yields tool_use chunks (after any text), so a scripted
|
|
6
|
+
* [call-tool, then answer] pair exercises the whole loop keylessly.
|
|
7
|
+
* Complements @adia-ai/llm's StubLLMAdapter (which speaks A2UI JSON, not
|
|
8
|
+
* tool rounds).
|
|
9
|
+
*/
|
|
10
|
+
import type { ChatOpts, LLMClient, ToolUse } from '@adia-ai/llm';
|
|
11
|
+
export interface ScriptedTurn {
|
|
12
|
+
text?: string;
|
|
13
|
+
toolUse?: ToolUse[];
|
|
14
|
+
stopReason?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ScriptClient extends LLMClient {
|
|
17
|
+
/** Every ChatOpts the client was called with, in order — assert on
|
|
18
|
+
* messages/tools/system reaching the wire. */
|
|
19
|
+
calls: Array<Partial<ChatOpts>>;
|
|
20
|
+
}
|
|
21
|
+
export declare function scriptClient(turns: ScriptedTurn[]): ScriptClient;
|
|
22
|
+
//# sourceMappingURL=stub.d.ts.map
|
package/stub.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["src/stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAc,SAAS,EAAe,OAAO,EAAE,MAAM,cAAc,CAAC;AAE1F,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C;mDAC+C;IAC/C,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;CACjC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,YAAY,CA0ChE"}
|
package/stub.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scriptClient — a deterministic LLMClient for tests.
|
|
3
|
+
*
|
|
4
|
+
* Feed it turns; each chat()/stream() call consumes the next one. A turn
|
|
5
|
+
* with toolUse yields tool_use chunks (after any text), so a scripted
|
|
6
|
+
* [call-tool, then answer] pair exercises the whole loop keylessly.
|
|
7
|
+
* Complements @adia-ai/llm's StubLLMAdapter (which speaks A2UI JSON, not
|
|
8
|
+
* tool rounds).
|
|
9
|
+
*/
|
|
10
|
+
export function scriptClient(turns) {
|
|
11
|
+
let cursor = 0;
|
|
12
|
+
const calls = [];
|
|
13
|
+
function next() {
|
|
14
|
+
const turn = turns[cursor];
|
|
15
|
+
if (!turn)
|
|
16
|
+
throw new Error(`scriptClient: call ${cursor + 1} but only ${turns.length} turns scripted`);
|
|
17
|
+
cursor++;
|
|
18
|
+
return turn;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
calls,
|
|
22
|
+
async chat(opts) {
|
|
23
|
+
calls.push(opts);
|
|
24
|
+
const turn = next();
|
|
25
|
+
return {
|
|
26
|
+
text: turn.text ?? '',
|
|
27
|
+
usage: { input: 1, output: 1 },
|
|
28
|
+
stopReason: turn.stopReason ?? (turn.toolUse?.length ? 'tool_use' : 'end'),
|
|
29
|
+
...(turn.toolUse?.length ? { toolUse: turn.toolUse } : {}),
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
async *stream(opts) {
|
|
33
|
+
calls.push(opts);
|
|
34
|
+
const turn = next();
|
|
35
|
+
let snapshot = '';
|
|
36
|
+
if (turn.text) {
|
|
37
|
+
snapshot = turn.text;
|
|
38
|
+
yield { type: 'text', text: turn.text, snapshot };
|
|
39
|
+
}
|
|
40
|
+
for (const call of turn.toolUse ?? []) {
|
|
41
|
+
yield { type: 'tool_use', id: call.id, name: call.name, input: call.input };
|
|
42
|
+
}
|
|
43
|
+
yield {
|
|
44
|
+
type: 'done',
|
|
45
|
+
text: snapshot,
|
|
46
|
+
usage: { input: 1, output: 1 },
|
|
47
|
+
stopReason: turn.stopReason ?? (turn.toolUse?.length ? 'tool_use' : 'end'),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=stub.js.map
|
package/stub.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stub.js","sourceRoot":"","sources":["src/stub.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,KAAK,GAA6B,EAAE,CAAC;IAE3C,SAAS,IAAI;QACX,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,GAAG,CAAC,aAAa,KAAK,CAAC,MAAM,iBAAiB,CAAC,CAAC;QACvG,MAAM,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,KAAK;QACL,KAAK,CAAC,IAAI,CAAC,IAAuB;YAChC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC;YACpB,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;gBACrB,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;gBAC9B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;gBAC1E,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC3D,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAC,IAAuB;YACnC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,IAAI,EAAE,CAAC;YACpB,IAAI,QAAQ,GAAG,EAAE,CAAC;YAClB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;gBACrB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;YACpD,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACtC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9E,CAAC;YACD,MAAM;gBACJ,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;gBAC9B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;aAC3E,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/tools.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools — the typed-call registry.
|
|
3
|
+
*
|
|
4
|
+
* A tool is a JSON-Schema'd contract plus exactly one executor: a local
|
|
5
|
+
* `execute` function or a server `endpoint` (POSTs the input as JSON,
|
|
6
|
+
* returns the response text). Input is checked against the schema at the
|
|
7
|
+
* call boundary — an invalid call fails BEFORE it does anything, and the
|
|
8
|
+
* failure feeds back to the model as an isError tool_result, never a throw.
|
|
9
|
+
*
|
|
10
|
+
* The schema check is deliberately minimal (top-level required / type /
|
|
11
|
+
* enum) — zero dependencies. Consumers wanting full JSON-Schema semantics
|
|
12
|
+
* can validate inside their own `execute`.
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolSpec } from '@adia-ai/llm';
|
|
15
|
+
export interface ToolContext {
|
|
16
|
+
sessionId: string;
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolDef {
|
|
20
|
+
name: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
inputSchema: Record<string, unknown>;
|
|
23
|
+
execute?: (input: Record<string, unknown>, ctx: ToolContext) => unknown | Promise<unknown>;
|
|
24
|
+
endpoint?: {
|
|
25
|
+
url: string;
|
|
26
|
+
method?: string;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function defineTool(def: ToolDef): ToolDef;
|
|
31
|
+
export declare function toSpecs(tools: ToolDef[]): ToolSpec[];
|
|
32
|
+
/** Top-level required / type / enum check. Returns null when valid,
|
|
33
|
+
* a human-readable problem string when not. */
|
|
34
|
+
export declare function checkInput(schema: Record<string, unknown>, input: Record<string, unknown>): string | null;
|
|
35
|
+
export interface ToolOutcome {
|
|
36
|
+
output: string;
|
|
37
|
+
isError?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Run one tool call end to end: schema check → executor → string output.
|
|
40
|
+
* Every failure path returns { isError: true } — the model sees the
|
|
41
|
+
* problem and can retry; the loop never throws over a bad call. */
|
|
42
|
+
export declare function executeTool(tool: ToolDef, input: Record<string, unknown>, ctx: ToolContext): Promise<ToolOutcome>;
|
|
43
|
+
//# sourceMappingURL=tools.d.ts.map
|
package/tools.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3F,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CAC/E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAWhD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAMpD;AAED;gDACgD;AAChD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAmBzG;AAeD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;oEAEoE;AACpE,wBAAsB,WAAW,CAC/B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CA4BtB"}
|
package/tools.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools — the typed-call registry.
|
|
3
|
+
*
|
|
4
|
+
* A tool is a JSON-Schema'd contract plus exactly one executor: a local
|
|
5
|
+
* `execute` function or a server `endpoint` (POSTs the input as JSON,
|
|
6
|
+
* returns the response text). Input is checked against the schema at the
|
|
7
|
+
* call boundary — an invalid call fails BEFORE it does anything, and the
|
|
8
|
+
* failure feeds back to the model as an isError tool_result, never a throw.
|
|
9
|
+
*
|
|
10
|
+
* The schema check is deliberately minimal (top-level required / type /
|
|
11
|
+
* enum) — zero dependencies. Consumers wanting full JSON-Schema semantics
|
|
12
|
+
* can validate inside their own `execute`.
|
|
13
|
+
*/
|
|
14
|
+
export function defineTool(def) {
|
|
15
|
+
if (!def.name || !/^[a-zA-Z0-9_-]+$/.test(def.name)) {
|
|
16
|
+
throw new Error(`defineTool: "${def.name}" — tool names are [a-zA-Z0-9_-]+`);
|
|
17
|
+
}
|
|
18
|
+
if (!def.inputSchema) {
|
|
19
|
+
throw new Error(`defineTool "${def.name}": inputSchema is required`);
|
|
20
|
+
}
|
|
21
|
+
if (!!def.execute === !!def.endpoint) {
|
|
22
|
+
throw new Error(`defineTool "${def.name}": exactly one of execute / endpoint`);
|
|
23
|
+
}
|
|
24
|
+
return def;
|
|
25
|
+
}
|
|
26
|
+
export function toSpecs(tools) {
|
|
27
|
+
return tools.map(t => ({
|
|
28
|
+
name: t.name,
|
|
29
|
+
...(t.description ? { description: t.description } : {}),
|
|
30
|
+
inputSchema: t.inputSchema,
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
/** Top-level required / type / enum check. Returns null when valid,
|
|
34
|
+
* a human-readable problem string when not. */
|
|
35
|
+
export function checkInput(schema, input) {
|
|
36
|
+
const required = Array.isArray(schema['required']) ? schema['required'] : [];
|
|
37
|
+
for (const key of required) {
|
|
38
|
+
if (!(key in input))
|
|
39
|
+
return `missing required property "${key}"`;
|
|
40
|
+
}
|
|
41
|
+
const properties = (schema['properties'] ?? {});
|
|
42
|
+
for (const [key, value] of Object.entries(input)) {
|
|
43
|
+
const prop = properties[key];
|
|
44
|
+
if (!prop)
|
|
45
|
+
continue;
|
|
46
|
+
const type = prop['type'];
|
|
47
|
+
if (typeof type === 'string' && !typeMatches(type, value)) {
|
|
48
|
+
return `property "${key}" expected ${type}, got ${Array.isArray(value) ? 'array' : typeof value}`;
|
|
49
|
+
}
|
|
50
|
+
const allowed = prop['enum'];
|
|
51
|
+
if (Array.isArray(allowed) && !allowed.some(v => v === value)) {
|
|
52
|
+
return `property "${key}" not in enum [${allowed.join(', ')}]`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function typeMatches(type, value) {
|
|
58
|
+
switch (type) {
|
|
59
|
+
case 'string': return typeof value === 'string';
|
|
60
|
+
case 'number': return typeof value === 'number';
|
|
61
|
+
case 'integer': return typeof value === 'number' && Number.isInteger(value);
|
|
62
|
+
case 'boolean': return typeof value === 'boolean';
|
|
63
|
+
case 'array': return Array.isArray(value);
|
|
64
|
+
case 'object': return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
65
|
+
case 'null': return value === null;
|
|
66
|
+
default: return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Run one tool call end to end: schema check → executor → string output.
|
|
70
|
+
* Every failure path returns { isError: true } — the model sees the
|
|
71
|
+
* problem and can retry; the loop never throws over a bad call. */
|
|
72
|
+
export async function executeTool(tool, input, ctx) {
|
|
73
|
+
const problem = checkInput(tool.inputSchema, input);
|
|
74
|
+
if (problem)
|
|
75
|
+
return { output: `Invalid input: ${problem}`, isError: true };
|
|
76
|
+
try {
|
|
77
|
+
if (tool.execute) {
|
|
78
|
+
const result = await tool.execute(input, ctx);
|
|
79
|
+
return { output: typeof result === 'string' ? result : JSON.stringify(result ?? null) };
|
|
80
|
+
}
|
|
81
|
+
const endpoint = tool.endpoint;
|
|
82
|
+
const method = (endpoint.method ?? 'POST').toUpperCase();
|
|
83
|
+
// GET/HEAD carry no body (fetch throws on one); input rides the query.
|
|
84
|
+
const bodyless = method === 'GET' || method === 'HEAD';
|
|
85
|
+
const url = bodyless && Object.keys(input).length
|
|
86
|
+
? `${endpoint.url}${endpoint.url.includes('?') ? '&' : '?'}${new URLSearchParams(input)}`
|
|
87
|
+
: endpoint.url;
|
|
88
|
+
const res = await fetch(url, {
|
|
89
|
+
method,
|
|
90
|
+
headers: { ...(bodyless ? {} : { 'content-type': 'application/json' }), ...endpoint.headers },
|
|
91
|
+
...(bodyless ? {} : { body: JSON.stringify(input) }),
|
|
92
|
+
...(ctx.signal ? { signal: ctx.signal } : {}),
|
|
93
|
+
});
|
|
94
|
+
const body = await res.text();
|
|
95
|
+
if (!res.ok)
|
|
96
|
+
return { output: `Endpoint error ${res.status}: ${body.slice(0, 500)}`, isError: true };
|
|
97
|
+
return { output: body };
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
return { output: `Tool "${tool.name}" failed: ${err.message}`, isError: true };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=tools.js.map
|
package/tools.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["src/tools.ts"],"names":[],"mappings":"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"}
|
package/workflow.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflows — named, declarative step sequences.
|
|
3
|
+
*
|
|
4
|
+
* A workflow is the routing cascade declared once: steps run in order;
|
|
5
|
+
* a step's `until` predicate accepts its result (stop, return it) or
|
|
6
|
+
* rejects it (fall through to the next step); a step without `until` is
|
|
7
|
+
* terminal — its result is always accepted. `when` skips a step entirely
|
|
8
|
+
* for this invocation. Scripted pipeline over per-turn re-decision: the
|
|
9
|
+
* sequence is data, so every consuming surface runs the SAME cascade.
|
|
10
|
+
*/
|
|
11
|
+
export interface WorkflowContext<TInput = unknown> {
|
|
12
|
+
input: TInput;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Step events land here (agent.run forwards them). */
|
|
16
|
+
emit?: (event: {
|
|
17
|
+
type: 'step';
|
|
18
|
+
workflow: string;
|
|
19
|
+
step: string;
|
|
20
|
+
data?: unknown;
|
|
21
|
+
}) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface WorkflowStep<TInput = unknown, TResult = unknown> {
|
|
24
|
+
name?: string;
|
|
25
|
+
run: (ctx: WorkflowContext<TInput>) => TResult | Promise<TResult>;
|
|
26
|
+
/** Accept predicate: true → this result is the workflow's result.
|
|
27
|
+
* Absent → terminal step, always accepted. */
|
|
28
|
+
until?: (result: TResult) => boolean;
|
|
29
|
+
/** Skip guard: false → step doesn't run this invocation. */
|
|
30
|
+
when?: (ctx: WorkflowContext<TInput>) => boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface Workflow<TInput = unknown, TResult = unknown> {
|
|
33
|
+
name: string;
|
|
34
|
+
steps: Array<WorkflowStep<TInput, TResult>>;
|
|
35
|
+
}
|
|
36
|
+
export interface WorkflowResult<TResult = unknown> {
|
|
37
|
+
result: TResult | undefined;
|
|
38
|
+
/** Name/index of the accepting step, or null when every step fell through. */
|
|
39
|
+
step: string | null;
|
|
40
|
+
accepted: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function defineWorkflow<TInput = unknown, TResult = unknown>(name: string, steps: Array<WorkflowStep<TInput, TResult>>): Workflow<TInput, TResult>;
|
|
43
|
+
export declare function runWorkflow<TInput, TResult>(workflow: Workflow<TInput, TResult>, ctx: WorkflowContext<TInput>): Promise<WorkflowResult<TResult>>;
|
|
44
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["src/workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,eAAe,CAAC,MAAM,GAAG,OAAO;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uDAAuD;IACvD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC1F;AAED,MAAM,WAAW,YAAY,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE;mDAC+C;IAC/C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IACrC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC;CAClD;AAED,MAAM,WAAW,QAAQ,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,cAAc,CAAC,OAAO,GAAG,OAAO;IAC/C,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAChE,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC1C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAG3B;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,OAAO,EAC/C,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,GAAG,EAAE,eAAe,CAAC,MAAM,CAAC,GAC3B,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAiBlC"}
|
package/workflow.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflows — named, declarative step sequences.
|
|
3
|
+
*
|
|
4
|
+
* A workflow is the routing cascade declared once: steps run in order;
|
|
5
|
+
* a step's `until` predicate accepts its result (stop, return it) or
|
|
6
|
+
* rejects it (fall through to the next step); a step without `until` is
|
|
7
|
+
* terminal — its result is always accepted. `when` skips a step entirely
|
|
8
|
+
* for this invocation. Scripted pipeline over per-turn re-decision: the
|
|
9
|
+
* sequence is data, so every consuming surface runs the SAME cascade.
|
|
10
|
+
*/
|
|
11
|
+
export function defineWorkflow(name, steps) {
|
|
12
|
+
if (!steps.length)
|
|
13
|
+
throw new Error(`defineWorkflow "${name}": at least one step`);
|
|
14
|
+
return { name, steps };
|
|
15
|
+
}
|
|
16
|
+
export async function runWorkflow(workflow, ctx) {
|
|
17
|
+
let last;
|
|
18
|
+
for (let i = 0; i < workflow.steps.length; i++) {
|
|
19
|
+
const step = workflow.steps[i];
|
|
20
|
+
const stepName = step.name ?? `step-${i + 1}`;
|
|
21
|
+
if (step.when && !step.when(ctx))
|
|
22
|
+
continue;
|
|
23
|
+
last = await step.run(ctx);
|
|
24
|
+
const accepted = step.until ? step.until(last) : true;
|
|
25
|
+
ctx.emit?.({
|
|
26
|
+
type: 'step',
|
|
27
|
+
workflow: workflow.name,
|
|
28
|
+
step: stepName,
|
|
29
|
+
data: { accepted },
|
|
30
|
+
});
|
|
31
|
+
if (accepted)
|
|
32
|
+
return { result: last, step: stepName, accepted: true };
|
|
33
|
+
}
|
|
34
|
+
return { result: last, step: null, accepted: false };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=workflow.js.map
|
package/workflow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["src/workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgCH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,KAA2C;IAE3C,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,sBAAsB,CAAC,CAAC;IAClF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAmC,EACnC,GAA4B;IAE5B,IAAI,IAAyB,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3C,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACtD,GAAG,CAAC,IAAI,EAAE,CAAC;YACT,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,EAAE,QAAQ,EAAE;SACnB,CAAC,CAAC;QACH,IAAI,QAAQ;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACvD,CAAC"}
|