@effect-uai/ui 0.0.0-stage → 0.17.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/LICENSE +21 -0
- package/README.md +64 -2
- package/dist/Atoms.d.mts +141 -0
- package/dist/Atoms.d.mts.map +1 -0
- package/dist/Atoms.mjs +132 -0
- package/dist/Atoms.mjs.map +1 -0
- package/dist/Client-C9UYN_VK.d.mts +219 -0
- package/dist/Client-C9UYN_VK.d.mts.map +1 -0
- package/dist/Client.d.mts +2 -0
- package/dist/Client.mjs +55 -0
- package/dist/Client.mjs.map +1 -0
- package/dist/Input-Cz-Kxusm.d.mts +277 -0
- package/dist/Input-Cz-Kxusm.d.mts.map +1 -0
- package/dist/Input.d.mts +2 -0
- package/dist/Input.mjs +127 -0
- package/dist/Input.mjs.map +1 -0
- package/dist/Projection.d.mts +44 -0
- package/dist/Projection.d.mts.map +1 -0
- package/dist/Projection.mjs +133 -0
- package/dist/Projection.mjs.map +1 -0
- package/dist/Run.d.mts +44 -0
- package/dist/Run.d.mts.map +1 -0
- package/dist/Run.mjs +117 -0
- package/dist/Run.mjs.map +1 -0
- package/dist/RunEvent.d.mts +1225 -0
- package/dist/RunEvent.d.mts.map +1 -0
- package/dist/RunEvent.mjs +264 -0
- package/dist/RunEvent.mjs.map +1 -0
- package/dist/RunView-nHfJwN8t.d.mts +380 -0
- package/dist/RunView-nHfJwN8t.d.mts.map +1 -0
- package/dist/RunView.d.mts +2 -0
- package/dist/RunView.mjs +452 -0
- package/dist/RunView.mjs.map +1 -0
- package/dist/SseEncoding.d.mts +437 -0
- package/dist/SseEncoding.d.mts.map +1 -0
- package/dist/SseEncoding.mjs +64 -0
- package/dist/SseEncoding.mjs.map +1 -0
- package/dist/Thread-CAXsjhpX.d.mts +474 -0
- package/dist/Thread-CAXsjhpX.d.mts.map +1 -0
- package/dist/Thread.d.mts +2 -0
- package/dist/Thread.mjs +225 -0
- package/dist/Thread.mjs.map +1 -0
- package/dist/Transport.d.mts +96 -0
- package/dist/Transport.d.mts.map +1 -0
- package/dist/Transport.mjs +82 -0
- package/dist/Transport.mjs.map +1 -0
- package/dist/UiContract.d.mts +114 -0
- package/dist/UiContract.d.mts.map +1 -0
- package/dist/UiContract.mjs +229 -0
- package/dist/UiContract.mjs.map +1 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.mjs +12 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +99 -3
- package/src/Atoms.test.ts +163 -0
- package/src/Atoms.ts +355 -0
- package/src/Client.test.ts +53 -0
- package/src/Client.ts +92 -0
- package/src/Input.test.ts +68 -0
- package/src/Input.ts +165 -0
- package/src/Projection.test.ts +198 -0
- package/src/Projection.ts +142 -0
- package/src/Run.test.ts +119 -0
- package/src/Run.ts +166 -0
- package/src/RunEvent.test.ts +84 -0
- package/src/RunEvent.ts +374 -0
- package/src/RunView.test.ts +98 -0
- package/src/RunView.ts +583 -0
- package/src/SseEncoding.test.ts +46 -0
- package/src/SseEncoding.ts +77 -0
- package/src/Thread.test.ts +304 -0
- package/src/Thread.ts +286 -0
- package/src/Transport.ts +182 -0
- package/src/UiContract.test.ts +342 -0
- package/src/UiContract.ts +402 -0
- package/src/index.ts +11 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Effect, Match, Option, Schema, Stream } from "effect";
|
|
3
|
+
import * as Turn from "@effect-uai/core/Turn";
|
|
4
|
+
//#region src/Projection.ts
|
|
5
|
+
var Projection_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
Options: () => Options,
|
|
7
|
+
State: () => State,
|
|
8
|
+
initial: () => initial,
|
|
9
|
+
step: () => step,
|
|
10
|
+
toRunEvents: () => toRunEvents
|
|
11
|
+
});
|
|
12
|
+
const Options = Schema.Struct({
|
|
13
|
+
/**
|
|
14
|
+
* `"signal"` (default): only `reasoning-started`. `"summary"`: also
|
|
15
|
+
* forward summary deltas. `"full"`: also forward raw reasoning traces.
|
|
16
|
+
*/
|
|
17
|
+
reasoning: Schema.optionalKey(Schema.Literals([
|
|
18
|
+
"signal",
|
|
19
|
+
"summary",
|
|
20
|
+
"full"
|
|
21
|
+
])),
|
|
22
|
+
/** Forward raw tool-argument deltas (`tool-call-args-delta`). Default false. */
|
|
23
|
+
toolArgs: Schema.optionalKey(Schema.Boolean)
|
|
24
|
+
});
|
|
25
|
+
const State = Schema.Struct({
|
|
26
|
+
inStep: Schema.Boolean,
|
|
27
|
+
reasoningShown: Schema.Boolean,
|
|
28
|
+
/** Tool names by call id, for outputs that arrive as plain `function_call_output` items. */
|
|
29
|
+
tools: Schema.Record(Schema.String, Schema.String)
|
|
30
|
+
});
|
|
31
|
+
const initial = {
|
|
32
|
+
inStep: false,
|
|
33
|
+
reasoningShown: false,
|
|
34
|
+
tools: {}
|
|
35
|
+
};
|
|
36
|
+
const parseJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json));
|
|
37
|
+
const decodeJson = (raw) => Option.getOrElse(parseJson(raw), () => raw);
|
|
38
|
+
const inStep = (s, events) => s.inStep ? [s, events] : [{
|
|
39
|
+
...s,
|
|
40
|
+
inStep: true,
|
|
41
|
+
reasoningShown: false
|
|
42
|
+
}, [{ type: "step-started" }, ...events]];
|
|
43
|
+
const reasoning = (options) => (s, e) => {
|
|
44
|
+
const mode = options?.reasoning ?? "signal";
|
|
45
|
+
const forward = mode === "full" || mode === "summary" && e.kind === "summary";
|
|
46
|
+
const [opened, prefix] = inStep(s, []);
|
|
47
|
+
const started = opened.reasoningShown ? [] : [{ type: "reasoning-started" }];
|
|
48
|
+
const delta = forward ? [{
|
|
49
|
+
type: "reasoning-delta",
|
|
50
|
+
text: e.text,
|
|
51
|
+
kind: e.kind
|
|
52
|
+
}] : [];
|
|
53
|
+
return [{
|
|
54
|
+
...opened,
|
|
55
|
+
reasoningShown: true
|
|
56
|
+
}, [
|
|
57
|
+
...prefix,
|
|
58
|
+
...started,
|
|
59
|
+
...delta
|
|
60
|
+
]];
|
|
61
|
+
};
|
|
62
|
+
const turnComplete = (s, turn) => {
|
|
63
|
+
const calls = Turn.getToolCalls(turn);
|
|
64
|
+
const ready = calls.map((call) => ({
|
|
65
|
+
type: "tool-call-ready",
|
|
66
|
+
callId: call.call_id,
|
|
67
|
+
name: call.name,
|
|
68
|
+
input: decodeJson(call.arguments)
|
|
69
|
+
}));
|
|
70
|
+
const [, events] = inStep(s, [...ready, {
|
|
71
|
+
type: "step-finished",
|
|
72
|
+
usage: turn.usage
|
|
73
|
+
}]);
|
|
74
|
+
const tools = {
|
|
75
|
+
...s.tools,
|
|
76
|
+
...Object.fromEntries(calls.map((c) => [c.call_id, c.name]))
|
|
77
|
+
};
|
|
78
|
+
return [{
|
|
79
|
+
...initial,
|
|
80
|
+
tools
|
|
81
|
+
}, events];
|
|
82
|
+
};
|
|
83
|
+
const outputResult = (config, s, o) => Effect.map(config.contract.toolOutput(o, s.tools[o.call_id] ?? ""), (event) => [s, [event]]);
|
|
84
|
+
/** Map one loop event onto zero or more `RunEvent`s; tool values are encoded by the contract. */
|
|
85
|
+
const step = (config) => (s, event) => Match.value(event).pipe(Match.when({ type: "function_call_output" }, (o) => outputResult(config, s, o)), Match.tags({
|
|
86
|
+
Partial: (e) => Effect.map(config.contract.toolEvent(e), (r) => [s, [r]]),
|
|
87
|
+
Output: (e) => Effect.map(config.contract.toolEvent(e), (r) => [s, [r]])
|
|
88
|
+
}), Match.orElse((e) => Effect.succeed(turnStep(config)(s, e))));
|
|
89
|
+
const turnStep = (options) => (s, event) => Match.value(event).pipe(Match.tagsExhaustive({
|
|
90
|
+
TextDelta: (e) => inStep(s, [{
|
|
91
|
+
type: "text-delta",
|
|
92
|
+
text: e.text
|
|
93
|
+
}]),
|
|
94
|
+
RefusalDelta: (e) => inStep(s, [{
|
|
95
|
+
type: "refusal-delta",
|
|
96
|
+
text: e.text
|
|
97
|
+
}]),
|
|
98
|
+
ReasoningDelta: (e) => reasoning(options)(s, e),
|
|
99
|
+
ToolCallStart: (e) => inStep(s, [{
|
|
100
|
+
type: "tool-call-started",
|
|
101
|
+
callId: e.call_id,
|
|
102
|
+
name: e.name
|
|
103
|
+
}]),
|
|
104
|
+
ToolCallArgsDelta: (e) => inStep(s, options?.toolArgs === true ? [{
|
|
105
|
+
type: "tool-call-args-delta",
|
|
106
|
+
callId: e.call_id,
|
|
107
|
+
delta: e.delta
|
|
108
|
+
}] : []),
|
|
109
|
+
CitationAdded: (e) => inStep(s, [{
|
|
110
|
+
type: "citation",
|
|
111
|
+
annotation: e.annotation
|
|
112
|
+
}]),
|
|
113
|
+
ImageOutput: (e) => inStep(s, [e.partialIndex === void 0 ? {
|
|
114
|
+
type: "image",
|
|
115
|
+
image: e.image
|
|
116
|
+
} : {
|
|
117
|
+
type: "image",
|
|
118
|
+
image: e.image,
|
|
119
|
+
partialIndex: e.partialIndex
|
|
120
|
+
}]),
|
|
121
|
+
UsageUpdate: () => [s, []],
|
|
122
|
+
WebSearchCall: () => [s, []],
|
|
123
|
+
TurnComplete: (e) => turnComplete(s, e.turn)
|
|
124
|
+
}));
|
|
125
|
+
/**
|
|
126
|
+
* Stream operator: project a loop's events onto `RunEvent`s. A tool value the
|
|
127
|
+
* contract can't encode fails the stream: a contract violation, not data to show.
|
|
128
|
+
*/
|
|
129
|
+
const toRunEvents = (config) => (self) => self.pipe(Stream.mapAccumEffect(() => initial, step(config)));
|
|
130
|
+
//#endregion
|
|
131
|
+
export { Options, State, initial, step, Projection_exports as t, toRunEvents };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=Projection.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Projection.mjs","names":[],"sources":["../src/Projection.ts"],"sourcesContent":["/**\n * Project an effect-uai loop onto `RunEvent`s. The projection is a fold pair\n * (`initial`, `step`) because step boundaries need state; `toRunEvents` runs\n * it over a stream. To add app events (metrics, domain data), map them\n * yourself and delegate the rest to `step`.\n *\n * Never forwards `TurnComplete.turn` itself: it carries `providerData`\n * (encrypted reasoning, item ids) that must not reach a browser.\n */\nimport type * as Items from \"@effect-uai/core/Items\"\nimport type * as ToolEvent from \"@effect-uai/core/ToolEvent\"\nimport * as Turn from \"@effect-uai/core/Turn\"\nimport { Effect, Match, Option, Schema, Stream } from \"effect\"\nimport type { Json, RunEvent } from \"./RunEvent.js\"\nimport * as UiContract from \"./UiContract.js\"\n\n/** What an effect-uai loop emits: turn events, tool events, and plain tool outputs. */\nexport type Source = Turn.TurnEvent | ToolEvent.ToolEvent | Items.ToolCallOutput\n\nexport const Options = Schema.Struct({\n /**\n * `\"signal\"` (default): only `reasoning-started`. `\"summary\"`: also\n * forward summary deltas. `\"full\"`: also forward raw reasoning traces.\n */\n reasoning: Schema.optionalKey(Schema.Literals([\"signal\", \"summary\", \"full\"])),\n /** Forward raw tool-argument deltas (`tool-call-args-delta`). Default false. */\n toolArgs: Schema.optionalKey(Schema.Boolean),\n})\nexport type Options = typeof Options.Type\n\n/** `Options` plus the contract whose tool schemas encode tool values and errors. */\nexport type Config = Options & {\n readonly contract: Pick<UiContract.UiContract<any>, \"toolEvent\" | \"toolOutput\">\n}\n\nexport const State = Schema.Struct({\n inStep: Schema.Boolean,\n reasoningShown: Schema.Boolean,\n /** Tool names by call id, for outputs that arrive as plain `function_call_output` items. */\n tools: Schema.Record(Schema.String, Schema.String),\n})\nexport type State = typeof State.Type\n\nexport const initial: State = { inStep: false, reasoningShown: false, tools: {} }\n\ntype Step = readonly [State, ReadonlyArray<RunEvent>]\n\n// Tool arguments are a JSON string; hand the client the decoded value, falling\n// back to the raw string when it isn't JSON.\nconst parseJson = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json))\nconst decodeJson = (raw: string): Json => Option.getOrElse(parseJson(raw), () => raw)\n\n// Content belongs to a step (one model turn); open one lazily on its first event.\nconst inStep = (s: State, events: ReadonlyArray<RunEvent>): Step =>\n s.inStep\n ? [s, events]\n : [{ ...s, inStep: true, reasoningShown: false }, [{ type: \"step-started\" }, ...events]]\n\nconst reasoning =\n (options: Options | undefined) =>\n (s: State, e: Extract<Turn.TurnEvent, { _tag: \"ReasoningDelta\" }>): Step => {\n const mode = options?.reasoning ?? \"signal\"\n const forward = mode === \"full\" || (mode === \"summary\" && e.kind === \"summary\")\n const [opened, prefix] = inStep(s, [])\n const started: ReadonlyArray<RunEvent> = opened.reasoningShown\n ? []\n : [{ type: \"reasoning-started\" }]\n const delta: ReadonlyArray<RunEvent> = forward\n ? [{ type: \"reasoning-delta\", text: e.text, kind: e.kind }]\n : []\n return [{ ...opened, reasoningShown: true }, [...prefix, ...started, ...delta]]\n }\n\nconst turnComplete = (s: State, turn: Turn.Turn): Step => {\n const calls = Turn.getToolCalls(turn)\n const ready = calls.map((call): RunEvent => ({\n type: \"tool-call-ready\",\n callId: call.call_id,\n name: call.name,\n input: decodeJson(call.arguments),\n }))\n const [, events] = inStep(s, [...ready, { type: \"step-finished\", usage: turn.usage }])\n const tools = { ...s.tools, ...Object.fromEntries(calls.map((c) => [c.call_id, c.name])) }\n return [{ ...initial, tools }, events]\n}\n\n// A history item already holds the encoded value; the contract shapes it for the wire.\nconst outputResult = (config: Config, s: State, o: Items.ToolCallOutput) =>\n Effect.map(config.contract.toolOutput(o, s.tools[o.call_id] ?? \"\"), (event): Step => [s, [event]])\n\n/** Map one loop event onto zero or more `RunEvent`s; tool values are encoded by the contract. */\nexport const step =\n (config: Config) =>\n (s: State, event: Source): Effect.Effect<Step, Schema.SchemaError> =>\n Match.value(event).pipe(\n Match.when({ type: \"function_call_output\" }, (o) => outputResult(config, s, o)),\n Match.tags({\n Partial: (e) => Effect.map(config.contract.toolEvent(e), (r): Step => [s, [r]]),\n Output: (e) => Effect.map(config.contract.toolEvent(e), (r): Step => [s, [r]]),\n }),\n Match.orElse((e) => Effect.succeed(turnStep(config)(s, e))),\n )\n\nconst turnStep =\n (options: Options) =>\n (s: State, event: Turn.TurnEvent): Step =>\n Match.value(event).pipe(\n Match.tagsExhaustive({\n TextDelta: (e) => inStep(s, [{ type: \"text-delta\", text: e.text }]),\n RefusalDelta: (e) => inStep(s, [{ type: \"refusal-delta\", text: e.text }]),\n ReasoningDelta: (e) => reasoning(options)(s, e),\n ToolCallStart: (e) =>\n inStep(s, [{ type: \"tool-call-started\", callId: e.call_id, name: e.name }]),\n ToolCallArgsDelta: (e) =>\n inStep(\n s,\n options?.toolArgs === true\n ? [{ type: \"tool-call-args-delta\", callId: e.call_id, delta: e.delta }]\n : [],\n ),\n CitationAdded: (e) => inStep(s, [{ type: \"citation\", annotation: e.annotation }]),\n ImageOutput: (e) =>\n inStep(s, [\n e.partialIndex === undefined\n ? { type: \"image\", image: e.image }\n : { type: \"image\", image: e.image, partialIndex: e.partialIndex },\n ]),\n // Usage arrives on `step-finished`; search progress has no UI event yet.\n UsageUpdate: (): Step => [s, []],\n WebSearchCall: (): Step => [s, []],\n TurnComplete: (e) => turnComplete(s, e.turn),\n }),\n )\n\n/**\n * Stream operator: project a loop's events onto `RunEvent`s. A tool value the\n * contract can't encode fails the stream: a contract violation, not data to show.\n */\nexport const toRunEvents =\n (config: Config) =>\n <E, R>(self: Stream.Stream<Source, E, R>): Stream.Stream<RunEvent, E | Schema.SchemaError, R> =>\n self.pipe(Stream.mapAccumEffect(() => initial, step(config)))\n"],"mappings":"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"}
|
package/dist/Run.d.mts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Envelope, InputId, RunEvent, RunId, StreamId } from "./RunEvent.mjs";
|
|
2
|
+
import { Cause, Effect, Schema, Stream } from "effect";
|
|
3
|
+
import * as Duration from "effect/Duration";
|
|
4
|
+
declare namespace Run_d_exports {
|
|
5
|
+
export { SequenceState, StartOptions, coalesce, complete, failed, sequence, start, stopWhen };
|
|
6
|
+
}
|
|
7
|
+
type StartOptions = {
|
|
8
|
+
readonly runId: RunId;
|
|
9
|
+
/** Client input ids the run answers. */
|
|
10
|
+
readonly inputs?: ReadonlyArray<InputId>;
|
|
11
|
+
/** Role label when a stream carries several kinds of run. */
|
|
12
|
+
readonly name?: string;
|
|
13
|
+
};
|
|
14
|
+
/** Prepend `run-started`. */
|
|
15
|
+
declare const start: (options: StartOptions) => <E, R>(self: Stream.Stream<RunEvent, E, R>) => Stream.Stream<RunEvent, E, R>;
|
|
16
|
+
/** End the run at its first terminal; append `run-completed` if it ends without one. */
|
|
17
|
+
declare const complete: <E, R>(self: Stream.Stream<RunEvent, E, R>) => Stream.Stream<RunEvent, E, R>;
|
|
18
|
+
/** End the run with `run-stopped` when `signal` completes (e.g. a stop `Deferred`). */
|
|
19
|
+
declare const stopWhen: (signal: Effect.Effect<void>) => <E, R>(self: Stream.Stream<RunEvent, E, R>) => Stream.Stream<RunEvent, E, R>;
|
|
20
|
+
/** A `run-failed` for a failed stream: `reason` is the error's `_tag`, else `"internal"`. */
|
|
21
|
+
declare const failed: (cause: Cause.Cause<unknown>) => RunEvent;
|
|
22
|
+
declare const SequenceState: Schema.Struct<{
|
|
23
|
+
readonly seq: Schema.Int;
|
|
24
|
+
/** Id of the run currently open on this stream. */
|
|
25
|
+
readonly runId: Schema.optionalKey<Schema.brand<Schema.String, "RunId">>;
|
|
26
|
+
}>;
|
|
27
|
+
type SequenceState = typeof SequenceState.Type;
|
|
28
|
+
/**
|
|
29
|
+
* Wrap events in envelopes with a per-stream `seq` (starting after `from`,
|
|
30
|
+
* default 0) and the current run's id, taken from the last `run-started`.
|
|
31
|
+
*/
|
|
32
|
+
declare const sequence: (streamId: StreamId, options?: {
|
|
33
|
+
readonly from?: number;
|
|
34
|
+
}) => <E, R>(self: Stream.Stream<RunEvent, E, R>) => Stream.Stream<Envelope, E, R>;
|
|
35
|
+
/**
|
|
36
|
+
* Merge consecutive text, reasoning and tool-argument deltas that arrive
|
|
37
|
+
* within `window`; every other event passes through unchanged and in order.
|
|
38
|
+
* Bounds frames on the wire and rows in a durable log; adds up to `window`
|
|
39
|
+
* latency.
|
|
40
|
+
*/
|
|
41
|
+
declare const coalesce: (window: Duration.Input) => <E, R>(self: Stream.Stream<RunEvent, E, R>) => Stream.Stream<RunEvent, E, R>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { SequenceState, StartOptions, coalesce, complete, failed, sequence, start, stopWhen, Run_d_exports as t };
|
|
44
|
+
//# sourceMappingURL=Run.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Run.d.mts","names":[],"sources":["../src/Run.ts"],"mappings":";;;;;;KAmCY;WACD,OAAO;;WAEP,SAAS,cAAc;;WAEvB;;;cAIE,QAAK,SACN,kBACT,GAAG,GAAC,MAAQ,OAAO,OAAO,UAAU,GAAG,OAAK,OAAO,OAAO,UAAU,GAAG;;cAY7D,WAAY,GAAG,GAAC,MACrB,OAAO,OAAO,UAAU,GAAG,OAChC,OAAO,OAAO,UAAU,GAAG;;cAcjB,WAAQ,QACV,OAAO,kBACf,GAAG,GAAC,MAAQ,OAAO,OAAO,UAAU,GAAG,OAAK,OAAO,OAAO,UAAU,GAAG;;cAS7D,SAAM,OAAW,MAAM,mBAAiB;cAWxC,eAAa,OAAA;;;;;KAKd,uBAAuB,cAAc;;;;;cAiBpC,WAAQ,UACR,UAAQ;WAAuB;OACzC,GAAG,GAAC,MAAQ,OAAO,OAAO,UAAU,GAAG,OAAK,OAAO,OAAO,UAAU,GAAG;;;;;;;cAuC7D,WAAQ,QACV,SAAS,WACjB,GAAG,GAAC,MAAQ,OAAO,OAAO,UAAU,GAAG,OAAK,OAAO,OAAO,UAAU,GAAG"}
|
package/dist/Run.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { RunId, isTerminal } from "./RunEvent.mjs";
|
|
3
|
+
import { Array, Cause, Effect, Predicate, Schema, Stream } from "effect";
|
|
4
|
+
//#region src/Run.ts
|
|
5
|
+
/**
|
|
6
|
+
* Server-side stream operators for runs. Each does one thing; a run pipes
|
|
7
|
+
* the ones it needs:
|
|
8
|
+
*
|
|
9
|
+
* agent(history).pipe(
|
|
10
|
+
* Projection.toRunEvents({ contract }),
|
|
11
|
+
* Run.coalesce("30 millis"),
|
|
12
|
+
* Stream.catchCause((cause) => Stream.succeed(Run.failed(cause))),
|
|
13
|
+
* Run.stopWhen(Deferred.await(stop)), // durable runs
|
|
14
|
+
* Run.start({ runId, inputs }),
|
|
15
|
+
* Run.complete,
|
|
16
|
+
* Run.sequence(streamId),
|
|
17
|
+
* )
|
|
18
|
+
*
|
|
19
|
+
* In this order they keep the protocol's rule: `run-started` first, exactly
|
|
20
|
+
* one terminal last. Direct mode needs no stop: when the client goes away,
|
|
21
|
+
* the server interrupts the stream (Effect's `HttpServer`, or
|
|
22
|
+
* `HttpRouter.toWebHandler` behind a framework's route).
|
|
23
|
+
*/
|
|
24
|
+
var Run_exports = /* @__PURE__ */ __exportAll({
|
|
25
|
+
SequenceState: () => SequenceState,
|
|
26
|
+
coalesce: () => coalesce,
|
|
27
|
+
complete: () => complete,
|
|
28
|
+
failed: () => failed,
|
|
29
|
+
sequence: () => sequence,
|
|
30
|
+
start: () => start,
|
|
31
|
+
stopWhen: () => stopWhen
|
|
32
|
+
});
|
|
33
|
+
/** Prepend `run-started`. */
|
|
34
|
+
const start = (options) => (self) => {
|
|
35
|
+
const started = {
|
|
36
|
+
type: "run-started",
|
|
37
|
+
runId: options.runId,
|
|
38
|
+
inputs: options.inputs ?? [],
|
|
39
|
+
protocol: 2,
|
|
40
|
+
...options.name !== void 0 ? { name: options.name } : {}
|
|
41
|
+
};
|
|
42
|
+
return Stream.make(started).pipe(Stream.concat(self));
|
|
43
|
+
};
|
|
44
|
+
/** End the run at its first terminal; append `run-completed` if it ends without one. */
|
|
45
|
+
const complete = (self) => self.pipe(Stream.takeUntil(isTerminal), Stream.mapAccum(() => false, (ended, event) => [ended || isTerminal(event), [event]], { onHalt: (ended) => ended ? [] : [{ type: "run-completed" }] }));
|
|
46
|
+
/** End the run with `run-stopped` when `signal` completes (e.g. a stop `Deferred`). */
|
|
47
|
+
const stopWhen = (signal) => (self) => self.pipe(Stream.merge(Stream.fromEffect(Effect.as(signal, { type: "run-stopped" })), { haltStrategy: "left" }), Stream.takeUntil((event) => event.type === "run-stopped"));
|
|
48
|
+
/** A `run-failed` for a failed stream: `reason` is the error's `_tag`, else `"internal"`. */
|
|
49
|
+
const failed = (cause) => {
|
|
50
|
+
const error = Cause.squash(cause);
|
|
51
|
+
return {
|
|
52
|
+
type: "run-failed",
|
|
53
|
+
reason: Predicate.hasProperty(error, "_tag") && Predicate.isString(error._tag) ? error._tag : "internal"
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const SequenceState = Schema.Struct({
|
|
57
|
+
seq: Schema.Int,
|
|
58
|
+
/** Id of the run currently open on this stream. */
|
|
59
|
+
runId: Schema.optionalKey(RunId)
|
|
60
|
+
});
|
|
61
|
+
const sequenceStep = (streamId) => (s, event) => {
|
|
62
|
+
const runId = event.type === "run-started" ? event.runId : s.runId;
|
|
63
|
+
const seq = s.seq + 1;
|
|
64
|
+
const envelope = runId === void 0 ? {
|
|
65
|
+
streamId,
|
|
66
|
+
seq,
|
|
67
|
+
event
|
|
68
|
+
} : {
|
|
69
|
+
streamId,
|
|
70
|
+
seq,
|
|
71
|
+
runId,
|
|
72
|
+
event
|
|
73
|
+
};
|
|
74
|
+
return [runId === void 0 || isTerminal(event) ? { seq } : {
|
|
75
|
+
seq,
|
|
76
|
+
runId
|
|
77
|
+
}, [envelope]];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Wrap events in envelopes with a per-stream `seq` (starting after `from`,
|
|
81
|
+
* default 0) and the current run's id, taken from the last `run-started`.
|
|
82
|
+
*/
|
|
83
|
+
const sequence = (streamId, options) => (self) => self.pipe(Stream.mapAccum(() => ({ seq: options?.from ?? 0 }), sequenceStep(streamId)));
|
|
84
|
+
const merge = (a, b) => {
|
|
85
|
+
if (a.type === "text-delta" && b.type === "text-delta") return {
|
|
86
|
+
...a,
|
|
87
|
+
text: a.text + b.text
|
|
88
|
+
};
|
|
89
|
+
if (a.type === "refusal-delta" && b.type === "refusal-delta") return {
|
|
90
|
+
...a,
|
|
91
|
+
text: a.text + b.text
|
|
92
|
+
};
|
|
93
|
+
if (a.type === "reasoning-delta" && b.type === "reasoning-delta" && a.kind === b.kind) return {
|
|
94
|
+
...a,
|
|
95
|
+
text: a.text + b.text
|
|
96
|
+
};
|
|
97
|
+
if (a.type === "tool-call-args-delta" && b.type === "tool-call-args-delta" && a.callId === b.callId) return {
|
|
98
|
+
...a,
|
|
99
|
+
delta: a.delta + b.delta
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
const mergeAdjacent = (group) => Array.reduce(group, Array.empty(), (acc, event) => {
|
|
103
|
+
const last = acc.at(-1);
|
|
104
|
+
const merged = last === void 0 ? void 0 : merge(last, event);
|
|
105
|
+
return merged === void 0 ? [...acc, event] : [...acc.slice(0, -1), merged];
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Merge consecutive text, reasoning and tool-argument deltas that arrive
|
|
109
|
+
* within `window`; every other event passes through unchanged and in order.
|
|
110
|
+
* Bounds frames on the wire and rows in a durable log; adds up to `window`
|
|
111
|
+
* latency.
|
|
112
|
+
*/
|
|
113
|
+
const coalesce = (window) => (self) => self.pipe(Stream.groupedWithin(1024, window), Stream.flatMap((group) => Stream.fromIterable(mergeAdjacent(group))));
|
|
114
|
+
//#endregion
|
|
115
|
+
export { SequenceState, coalesce, complete, failed, sequence, start, stopWhen, Run_exports as t };
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=Run.mjs.map
|
package/dist/Run.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Run.mjs","names":["Arr"],"sources":["../src/Run.ts"],"sourcesContent":["/**\n * Server-side stream operators for runs. Each does one thing; a run pipes\n * the ones it needs:\n *\n * agent(history).pipe(\n * Projection.toRunEvents({ contract }),\n * Run.coalesce(\"30 millis\"),\n * Stream.catchCause((cause) => Stream.succeed(Run.failed(cause))),\n * Run.stopWhen(Deferred.await(stop)), // durable runs\n * Run.start({ runId, inputs }),\n * Run.complete,\n * Run.sequence(streamId),\n * )\n *\n * In this order they keep the protocol's rule: `run-started` first, exactly\n * one terminal last. Direct mode needs no stop: when the client goes away,\n * the server interrupts the stream (Effect's `HttpServer`, or\n * `HttpRouter.toWebHandler` behind a framework's route).\n */\nimport { Array as Arr, Cause, Effect, Predicate, Schema, Stream } from \"effect\"\nimport type * as Duration from \"effect/Duration\"\nimport {\n type Envelope,\n type InputId,\n isTerminal,\n PROTOCOL_VERSION,\n RunId,\n type RunEvent,\n type StreamId,\n} from \"./RunEvent.js\"\n\n// ---------------------------------------------------------------------------\n// A run's frame: start, stop, failure, completion\n// ---------------------------------------------------------------------------\n\nexport type StartOptions = {\n readonly runId: RunId\n /** Client input ids the run answers. */\n readonly inputs?: ReadonlyArray<InputId>\n /** Role label when a stream carries several kinds of run. */\n readonly name?: string\n}\n\n/** Prepend `run-started`. */\nexport const start =\n (options: StartOptions) =>\n <E, R>(self: Stream.Stream<RunEvent, E, R>): Stream.Stream<RunEvent, E, R> => {\n const started: RunEvent = {\n type: \"run-started\",\n runId: options.runId,\n inputs: options.inputs ?? [],\n protocol: PROTOCOL_VERSION,\n ...(options.name !== undefined ? { name: options.name } : {}),\n }\n return Stream.make(started).pipe(Stream.concat(self))\n }\n\n/** End the run at its first terminal; append `run-completed` if it ends without one. */\nexport const complete = <E, R>(\n self: Stream.Stream<RunEvent, E, R>,\n): Stream.Stream<RunEvent, E, R> =>\n self.pipe(\n Stream.takeUntil(isTerminal),\n Stream.mapAccum(\n () => false,\n (ended, event): readonly [boolean, ReadonlyArray<RunEvent>] => [\n ended || isTerminal(event),\n [event],\n ],\n { onHalt: (ended): ReadonlyArray<RunEvent> => (ended ? [] : [{ type: \"run-completed\" }]) },\n ),\n )\n\n/** End the run with `run-stopped` when `signal` completes (e.g. a stop `Deferred`). */\nexport const stopWhen =\n (signal: Effect.Effect<void>) =>\n <E, R>(self: Stream.Stream<RunEvent, E, R>): Stream.Stream<RunEvent, E, R> =>\n self.pipe(\n Stream.merge(Stream.fromEffect(Effect.as(signal, { type: \"run-stopped\" } as const)), {\n haltStrategy: \"left\",\n }),\n Stream.takeUntil((event) => event.type === \"run-stopped\"),\n )\n\n/** A `run-failed` for a failed stream: `reason` is the error's `_tag`, else `\"internal\"`. */\nexport const failed = (cause: Cause.Cause<unknown>): RunEvent => {\n const error = Cause.squash(cause)\n const reason =\n Predicate.hasProperty(error, \"_tag\") && Predicate.isString(error._tag) ? error._tag : \"internal\"\n return { type: \"run-failed\", reason }\n}\n\n// ---------------------------------------------------------------------------\n// sequence\n// ---------------------------------------------------------------------------\n\nexport const SequenceState = Schema.Struct({\n seq: Schema.Int,\n /** Id of the run currently open on this stream. */\n runId: Schema.optionalKey(RunId),\n})\nexport type SequenceState = typeof SequenceState.Type\n\nconst sequenceStep =\n (streamId: StreamId) =>\n (s: SequenceState, event: RunEvent): readonly [SequenceState, ReadonlyArray<Envelope>] => {\n const runId = event.type === \"run-started\" ? event.runId : s.runId\n const seq = s.seq + 1\n const envelope: Envelope =\n runId === undefined ? { streamId, seq, event } : { streamId, seq, runId, event }\n const next: SequenceState = runId === undefined || isTerminal(event) ? { seq } : { seq, runId }\n return [next, [envelope]]\n }\n\n/**\n * Wrap events in envelopes with a per-stream `seq` (starting after `from`,\n * default 0) and the current run's id, taken from the last `run-started`.\n */\nexport const sequence =\n (streamId: StreamId, options?: { readonly from?: number }) =>\n <E, R>(self: Stream.Stream<RunEvent, E, R>): Stream.Stream<Envelope, E, R> =>\n self.pipe(\n Stream.mapAccum((): SequenceState => ({ seq: options?.from ?? 0 }), sequenceStep(streamId)),\n )\n\n// ---------------------------------------------------------------------------\n// coalesce\n// ---------------------------------------------------------------------------\n\nconst merge = (a: RunEvent, b: RunEvent): RunEvent | undefined => {\n if (a.type === \"text-delta\" && b.type === \"text-delta\") return { ...a, text: a.text + b.text }\n if (a.type === \"refusal-delta\" && b.type === \"refusal-delta\")\n return { ...a, text: a.text + b.text }\n if (a.type === \"reasoning-delta\" && b.type === \"reasoning-delta\" && a.kind === b.kind) {\n return { ...a, text: a.text + b.text }\n }\n if (\n a.type === \"tool-call-args-delta\" &&\n b.type === \"tool-call-args-delta\" &&\n a.callId === b.callId\n ) {\n return { ...a, delta: a.delta + b.delta }\n }\n return undefined\n}\n\nconst mergeAdjacent = (group: ReadonlyArray<RunEvent>): ReadonlyArray<RunEvent> =>\n Arr.reduce(group, Arr.empty<RunEvent>(), (acc: ReadonlyArray<RunEvent>, event) => {\n const last = acc.at(-1)\n const merged = last === undefined ? undefined : merge(last, event)\n return merged === undefined ? [...acc, event] : [...acc.slice(0, -1), merged]\n })\n\n/**\n * Merge consecutive text, reasoning and tool-argument deltas that arrive\n * within `window`; every other event passes through unchanged and in order.\n * Bounds frames on the wire and rows in a durable log; adds up to `window`\n * latency.\n */\nexport const coalesce =\n (window: Duration.Input) =>\n <E, R>(self: Stream.Stream<RunEvent, E, R>): Stream.Stream<RunEvent, E, R> =>\n self.pipe(\n Stream.groupedWithin(1024, window),\n Stream.flatMap((group) => Stream.fromIterable(mergeAdjacent(group))),\n )\n"],"mappings":"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"}
|