@effect-uai/core 0.1.0 → 0.3.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/README.md +2 -2
- package/dist/{AiError-CqmYjXyx.d.mts → AiError-CBuPHVKA.d.mts} +1 -1
- package/dist/{AiError-CqmYjXyx.d.mts.map → AiError-CBuPHVKA.d.mts.map} +1 -1
- package/dist/Image-BZmKfIdq.d.mts +61 -0
- package/dist/Image-BZmKfIdq.d.mts.map +1 -0
- package/dist/{Items-D1C2686t.d.mts → Items-CB8Bo3FI.d.mts} +132 -80
- package/dist/Items-CB8Bo3FI.d.mts.map +1 -0
- package/dist/Media-D_CpcM1Z.d.mts +57 -0
- package/dist/Media-D_CpcM1Z.d.mts.map +1 -0
- package/dist/{StructuredFormat-B5ueioNr.d.mts → StructuredFormat-BWq5Hd1O.d.mts} +5 -5
- package/dist/StructuredFormat-BWq5Hd1O.d.mts.map +1 -0
- package/dist/{Tool-5wxOCuOh.d.mts → Tool-DjVufH7i.d.mts} +13 -13
- package/dist/Tool-DjVufH7i.d.mts.map +1 -0
- package/dist/{Turn-rlTfuHaQ.d.mts → Turn-OPaILVIB.d.mts} +12 -29
- package/dist/Turn-OPaILVIB.d.mts.map +1 -0
- package/dist/{chunk-CfYAbeIz.mjs → chunk-uyGKjUfl.mjs} +2 -1
- package/dist/dist-DV5ISja1.mjs +13782 -0
- package/dist/dist-DV5ISja1.mjs.map +1 -0
- package/dist/domain/AiError.d.mts +1 -1
- package/dist/domain/AiError.mjs +1 -1
- package/dist/domain/Image.d.mts +2 -0
- package/dist/domain/Image.mjs +58 -0
- package/dist/domain/Image.mjs.map +1 -0
- package/dist/domain/Items.d.mts +2 -2
- package/dist/domain/Items.mjs +19 -42
- package/dist/domain/Items.mjs.map +1 -1
- package/dist/domain/Media.d.mts +2 -0
- package/dist/domain/Media.mjs +14 -0
- package/dist/domain/Media.mjs.map +1 -0
- package/dist/domain/Turn.d.mts +2 -2
- package/dist/domain/Turn.mjs +12 -8
- package/dist/domain/Turn.mjs.map +1 -1
- package/dist/embedding-model/Embedding.d.mts +107 -0
- package/dist/embedding-model/Embedding.d.mts.map +1 -0
- package/dist/embedding-model/Embedding.mjs +18 -0
- package/dist/embedding-model/Embedding.mjs.map +1 -0
- package/dist/embedding-model/EmbeddingModel.d.mts +97 -0
- package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -0
- package/dist/embedding-model/EmbeddingModel.mjs +17 -0
- package/dist/embedding-model/EmbeddingModel.mjs.map +1 -0
- package/dist/index.d.mts +16 -8
- package/dist/index.mjs +10 -2
- package/dist/language-model/LanguageModel.d.mts +12 -20
- package/dist/language-model/LanguageModel.d.mts.map +1 -1
- package/dist/language-model/LanguageModel.mjs +3 -20
- package/dist/language-model/LanguageModel.mjs.map +1 -1
- package/dist/loop/Loop.d.mts +111 -2
- package/dist/loop/Loop.d.mts.map +1 -0
- package/dist/loop/Loop.mjs +39 -6
- package/dist/loop/Loop.mjs.map +1 -1
- package/dist/loop/Loop.test.d.mts +1 -0
- package/dist/loop/Loop.test.mjs +411 -0
- package/dist/loop/Loop.test.mjs.map +1 -0
- package/dist/magic-string.es-BgIV5Mu3.mjs +1013 -0
- package/dist/magic-string.es-BgIV5Mu3.mjs.map +1 -0
- package/dist/math/Vector.d.mts +47 -0
- package/dist/math/Vector.d.mts.map +1 -0
- package/dist/math/Vector.mjs +117 -0
- package/dist/math/Vector.mjs.map +1 -0
- package/dist/observability/Metrics.d.mts +2 -2
- package/dist/observability/Metrics.d.mts.map +1 -1
- package/dist/observability/Metrics.mjs +1 -1
- package/dist/observability/Metrics.mjs.map +1 -1
- package/dist/streaming/JSONL.mjs +1 -1
- package/dist/streaming/JSONL.test.d.mts +1 -0
- package/dist/streaming/JSONL.test.mjs +70 -0
- package/dist/streaming/JSONL.test.mjs.map +1 -0
- package/dist/streaming/Lines.mjs +1 -1
- package/dist/streaming/SSE.d.mts +2 -2
- package/dist/streaming/SSE.d.mts.map +1 -1
- package/dist/streaming/SSE.mjs +1 -1
- package/dist/streaming/SSE.mjs.map +1 -1
- package/dist/streaming/SSE.test.d.mts +1 -0
- package/dist/streaming/SSE.test.mjs +72 -0
- package/dist/streaming/SSE.test.mjs.map +1 -0
- package/dist/structured-format/StructuredFormat.d.mts +1 -1
- package/dist/structured-format/StructuredFormat.mjs +1 -1
- package/dist/structured-format/StructuredFormat.mjs.map +1 -1
- package/dist/testing/MockProvider.d.mts +6 -6
- package/dist/testing/MockProvider.d.mts.map +1 -1
- package/dist/testing/MockProvider.mjs.map +1 -1
- package/dist/tool/HistoryCheck.d.mts +6 -3
- package/dist/tool/HistoryCheck.d.mts.map +1 -1
- package/dist/tool/HistoryCheck.mjs +7 -1
- package/dist/tool/HistoryCheck.mjs.map +1 -1
- package/dist/tool/Outcome.d.mts +138 -2
- package/dist/tool/Outcome.d.mts.map +1 -0
- package/dist/tool/Outcome.mjs +34 -18
- package/dist/tool/Outcome.mjs.map +1 -1
- package/dist/tool/Resolvers.d.mts +30 -25
- package/dist/tool/Resolvers.d.mts.map +1 -1
- package/dist/tool/Resolvers.mjs +54 -44
- package/dist/tool/Resolvers.mjs.map +1 -1
- package/dist/tool/Resolvers.test.d.mts +1 -0
- package/dist/tool/Resolvers.test.mjs +317 -0
- package/dist/tool/Resolvers.test.mjs.map +1 -0
- package/dist/tool/Tool.d.mts +1 -1
- package/dist/tool/Tool.mjs +1 -1
- package/dist/tool/Tool.mjs.map +1 -1
- package/dist/tool/ToolEvent.d.mts +151 -2
- package/dist/tool/ToolEvent.d.mts.map +1 -0
- package/dist/tool/ToolEvent.mjs +30 -4
- package/dist/tool/ToolEvent.mjs.map +1 -1
- package/dist/tool/Toolkit.d.mts +24 -15
- package/dist/tool/Toolkit.d.mts.map +1 -1
- package/dist/tool/Toolkit.mjs +14 -13
- package/dist/tool/Toolkit.mjs.map +1 -1
- package/dist/tool/Toolkit.test.d.mts +1 -0
- package/dist/tool/Toolkit.test.mjs +113 -0
- package/dist/tool/Toolkit.test.mjs.map +1 -0
- package/package.json +29 -13
- package/src/domain/Image.ts +75 -0
- package/src/domain/Items.ts +18 -47
- package/src/domain/Media.ts +61 -0
- package/src/domain/Turn.ts +7 -17
- package/src/embedding-model/Embedding.ts +117 -0
- package/src/embedding-model/EmbeddingModel.ts +107 -0
- package/src/index.ts +9 -1
- package/src/language-model/LanguageModel.ts +2 -22
- package/src/loop/Loop.test.ts +114 -2
- package/src/loop/Loop.ts +69 -5
- package/src/math/Vector.ts +138 -0
- package/src/observability/Metrics.ts +1 -1
- package/src/streaming/SSE.ts +1 -1
- package/src/structured-format/StructuredFormat.ts +2 -2
- package/src/testing/MockProvider.ts +2 -2
- package/src/tool/HistoryCheck.ts +2 -5
- package/src/tool/Outcome.ts +39 -53
- package/src/tool/Resolvers.test.ts +46 -117
- package/src/tool/Resolvers.ts +74 -102
- package/src/tool/Tool.ts +9 -9
- package/src/tool/ToolEvent.ts +30 -26
- package/src/tool/Toolkit.test.ts +97 -2
- package/src/tool/Toolkit.ts +65 -67
- package/dist/Items-D1C2686t.d.mts.map +0 -1
- package/dist/Loop-CzSJo1h8.d.mts +0 -87
- package/dist/Loop-CzSJo1h8.d.mts.map +0 -1
- package/dist/Outcome-C2JYknCu.d.mts +0 -40
- package/dist/Outcome-C2JYknCu.d.mts.map +0 -1
- package/dist/StructuredFormat-B5ueioNr.d.mts.map +0 -1
- package/dist/Tool-5wxOCuOh.d.mts.map +0 -1
- package/dist/ToolEvent-B2N10hr3.d.mts +0 -29
- package/dist/ToolEvent-B2N10hr3.d.mts.map +0 -1
- package/dist/Turn-rlTfuHaQ.d.mts.map +0 -1
- package/dist/match/Match.d.mts +0 -16
- package/dist/match/Match.d.mts.map +0 -1
- package/dist/match/Match.mjs +0 -15
- package/dist/match/Match.mjs.map +0 -1
- package/src/match/Match.ts +0 -9
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { t as AiError } from "../AiError-CBuPHVKA.mjs";
|
|
2
|
+
import { EmbedInput, Embedding, Usage } from "./Embedding.mjs";
|
|
3
|
+
import { Context, Effect } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/embedding-model/EmbeddingModel.d.ts
|
|
6
|
+
declare namespace EmbeddingModel_d_exports {
|
|
7
|
+
export { CommonEmbedManyRequest, CommonEmbedRequest, EmbedManyResponse, EmbedResponse, EmbeddingModel, EmbeddingModelService, Encoding, embed, embedMany };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Output representation requested from the provider.
|
|
11
|
+
*
|
|
12
|
+
* Dense quantizations - same vector at different storage cost:
|
|
13
|
+
* - `float32` — universal default.
|
|
14
|
+
* - `int8` — ~4x smaller; minimal recall loss on most benchmarks.
|
|
15
|
+
* - `binary` — ~32x smaller; meaningful recall loss but pairs well with
|
|
16
|
+
* a float32 reranker pass over a small candidate set.
|
|
17
|
+
*
|
|
18
|
+
* Non-dense representations:
|
|
19
|
+
* - `sparse` — learned sparse vector for hybrid (dense + lexical) search.
|
|
20
|
+
* Currently Jina ELSER only on hosted APIs.
|
|
21
|
+
* - `multivector` — one vector per token for late-interaction (ColBERT-
|
|
22
|
+
* style) scoring via `Vector.maxSim`. Currently Jina v4 only.
|
|
23
|
+
*
|
|
24
|
+
* Each provider's typed request narrows this to its supported set at
|
|
25
|
+
* compile time (e.g. `JinaEncoding = "float32" | "binary" | "sparse" |
|
|
26
|
+
* "multivector"`). On the generic `EmbeddingModel` path, callers can
|
|
27
|
+
* pass any `Encoding` and the provider's API will reject mismatches at
|
|
28
|
+
* runtime.
|
|
29
|
+
*/
|
|
30
|
+
type Encoding = "float32" | "int8" | "binary" | "sparse" | "multivector";
|
|
31
|
+
/**
|
|
32
|
+
* Cross-provider single-embed request. Mirrors the shape of
|
|
33
|
+
* `LanguageModel.CommonRequest`: cross-cutting fields here, vendor
|
|
34
|
+
* specifics in the provider's typed request.
|
|
35
|
+
*
|
|
36
|
+
* Provider-specific extensions (Cohere widened `task` enum, Jina LoRA
|
|
37
|
+
* tasks, Mixedbread free-form `prompt`, etc.) live in that provider's own
|
|
38
|
+
* request interface, which extends this and narrows `model` / widens
|
|
39
|
+
* `task`.
|
|
40
|
+
*/
|
|
41
|
+
type CommonEmbedRequest = {
|
|
42
|
+
readonly input: EmbedInput;
|
|
43
|
+
/**
|
|
44
|
+
* Model identifier. Each provider narrows this to its typed literal
|
|
45
|
+
* union, so code that yields a typed provider tag gets autocompletion.
|
|
46
|
+
*/
|
|
47
|
+
readonly model: string;
|
|
48
|
+
/**
|
|
49
|
+
* Retrieval-task hint. Applies to the input. OpenAI ignores this;
|
|
50
|
+
* Mixedbread doesn't have it; Cohere v3+ requires it on the wire (typed
|
|
51
|
+
* as required in `CohereEmbedRequest`). Provider-specific task enums
|
|
52
|
+
* (classification, clustering, code retrieval, …) live on the
|
|
53
|
+
* provider's own request type.
|
|
54
|
+
*/
|
|
55
|
+
readonly task?: "query" | "document";
|
|
56
|
+
/**
|
|
57
|
+
* Matryoshka truncation. Default: provider's native dimension.
|
|
58
|
+
* Discrete-value providers (Cohere, Vertex `multimodalembedding@001`)
|
|
59
|
+
* narrow this to a literal union in their typed request.
|
|
60
|
+
*/
|
|
61
|
+
readonly dimensions?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Output representation - see {@link Encoding}. Dense float32 is the
|
|
64
|
+
* default; provider layers reject unsupported values up front with
|
|
65
|
+
* `InvalidRequest`.
|
|
66
|
+
*/
|
|
67
|
+
readonly encoding?: Encoding;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Cross-provider batch-embed request. One `task` for the whole batch -
|
|
71
|
+
* mixed-task batches aren't a real provider feature (rerankers exist for
|
|
72
|
+
* that).
|
|
73
|
+
*/
|
|
74
|
+
type CommonEmbedManyRequest = Omit<CommonEmbedRequest, "input"> & {
|
|
75
|
+
readonly inputs: ReadonlyArray<EmbedInput>;
|
|
76
|
+
};
|
|
77
|
+
type EmbedResponse = {
|
|
78
|
+
readonly embedding: Embedding;
|
|
79
|
+
readonly usage: Usage;
|
|
80
|
+
};
|
|
81
|
+
type EmbedManyResponse = {
|
|
82
|
+
readonly embeddings: ReadonlyArray<Embedding>;
|
|
83
|
+
readonly usage: Usage;
|
|
84
|
+
};
|
|
85
|
+
type EmbeddingModelService = {
|
|
86
|
+
readonly embed: (request: CommonEmbedRequest) => Effect.Effect<EmbedResponse, AiError>;
|
|
87
|
+
readonly embedMany: (request: CommonEmbedManyRequest) => Effect.Effect<EmbedManyResponse, AiError>;
|
|
88
|
+
};
|
|
89
|
+
declare const EmbeddingModel_base: Context.ServiceClass<EmbeddingModel, "@betalyra/effect-uai/EmbeddingModel", EmbeddingModelService>;
|
|
90
|
+
declare class EmbeddingModel extends EmbeddingModel_base {}
|
|
91
|
+
/** Embed a single input. */
|
|
92
|
+
declare const embed: (request: CommonEmbedRequest) => Effect.Effect<EmbedResponse, AiError, EmbeddingModel>;
|
|
93
|
+
/** Embed a batch in one provider call. Same `task` for every input. */
|
|
94
|
+
declare const embedMany: (request: CommonEmbedManyRequest) => Effect.Effect<EmbedManyResponse, AiError, EmbeddingModel>;
|
|
95
|
+
//#endregion
|
|
96
|
+
export { CommonEmbedManyRequest, CommonEmbedRequest, EmbedManyResponse, EmbedResponse, EmbeddingModel, EmbeddingModelService, Encoding, embed, embedMany, EmbeddingModel_d_exports as t };
|
|
97
|
+
//# sourceMappingURL=EmbeddingModel.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmbeddingModel.d.mts","names":[],"sources":["../../src/embedding-model/EmbeddingModel.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;;AAYA;;KAZY,QAAA;;;;;;;;;;;KAYA,kBAAA;EAAA,SACD,KAAA,EAAO,UAAA;;;;;WAKP,KAAA;EA6BqB;;;;;;;EAAA,SArBrB,IAAA;EAqBgC;AAG3C;;;;EAH2C,SAfhC,UAAA;EAmBW;;;;;EAAA,SAbX,QAAA,GAAW,QAAA;AAAA;;;;;;KAQV,sBAAA,GAAyB,IAAA,CAAK,kBAAA;EAAA,SAC/B,MAAA,EAAQ,aAAA,CAAc,UAAA;AAAA;AAAA,KAGrB,aAAA;EAAA,SACD,SAAA,EAAW,SAAA;EAAA,SACX,KAAA,EAAO,KAAA;AAAA;AAAA,KAGN,iBAAA;EAAA,SACD,UAAA,EAAY,aAAA,CAAc,SAAA;EAAA,SAC1B,KAAA,EAAO,KAAA;AAAA;AAAA,KAGN,qBAAA;EAAA,SACD,KAAA,GAAQ,OAAA,EAAS,kBAAA,KAAuB,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,OAAA;EAAA,SACrE,SAAA,GACP,OAAA,EAAS,sBAAA,KACN,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,OAAA;AAAA;AAAA,cACvC,mBAAA;cAEY,cAAA,SAAuB,mBAAA;;cAKvB,KAAA,GACX,OAAA,EAAS,kBAAA,KACR,MAAA,CAAO,MAAA,CAAO,aAAA,EAAe,OAAA,EAAiB,cAAA;;cAIpC,SAAA,GACX,OAAA,EAAS,sBAAA,KACR,MAAA,CAAO,MAAA,CAAO,iBAAA,EAAmB,OAAA,EAAiB,cAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
2
|
+
import { Context, Effect } from "effect";
|
|
3
|
+
//#region src/embedding-model/EmbeddingModel.ts
|
|
4
|
+
var EmbeddingModel_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
EmbeddingModel: () => EmbeddingModel,
|
|
6
|
+
embed: () => embed,
|
|
7
|
+
embedMany: () => embedMany
|
|
8
|
+
});
|
|
9
|
+
var EmbeddingModel = class extends Context.Service()("@betalyra/effect-uai/EmbeddingModel") {};
|
|
10
|
+
/** Embed a single input. */
|
|
11
|
+
const embed = (request) => Effect.flatMap(EmbeddingModel.asEffect(), (m) => m.embed(request));
|
|
12
|
+
/** Embed a batch in one provider call. Same `task` for every input. */
|
|
13
|
+
const embedMany = (request) => Effect.flatMap(EmbeddingModel.asEffect(), (m) => m.embedMany(request));
|
|
14
|
+
//#endregion
|
|
15
|
+
export { EmbeddingModel, embed, embedMany, EmbeddingModel_exports as t };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=EmbeddingModel.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmbeddingModel.mjs","names":[],"sources":["../../src/embedding-model/EmbeddingModel.ts"],"sourcesContent":["import { Context, Effect } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { Embedding, EmbedInput, Usage } from \"./Embedding.js\"\n\n/**\n * Output representation requested from the provider.\n *\n * Dense quantizations - same vector at different storage cost:\n * - `float32` — universal default.\n * - `int8` — ~4x smaller; minimal recall loss on most benchmarks.\n * - `binary` — ~32x smaller; meaningful recall loss but pairs well with\n * a float32 reranker pass over a small candidate set.\n *\n * Non-dense representations:\n * - `sparse` — learned sparse vector for hybrid (dense + lexical) search.\n * Currently Jina ELSER only on hosted APIs.\n * - `multivector` — one vector per token for late-interaction (ColBERT-\n * style) scoring via `Vector.maxSim`. Currently Jina v4 only.\n *\n * Each provider's typed request narrows this to its supported set at\n * compile time (e.g. `JinaEncoding = \"float32\" | \"binary\" | \"sparse\" |\n * \"multivector\"`). On the generic `EmbeddingModel` path, callers can\n * pass any `Encoding` and the provider's API will reject mismatches at\n * runtime.\n */\nexport type Encoding = \"float32\" | \"int8\" | \"binary\" | \"sparse\" | \"multivector\"\n\n/**\n * Cross-provider single-embed request. Mirrors the shape of\n * `LanguageModel.CommonRequest`: cross-cutting fields here, vendor\n * specifics in the provider's typed request.\n *\n * Provider-specific extensions (Cohere widened `task` enum, Jina LoRA\n * tasks, Mixedbread free-form `prompt`, etc.) live in that provider's own\n * request interface, which extends this and narrows `model` / widens\n * `task`.\n */\nexport type CommonEmbedRequest = {\n readonly input: EmbedInput\n /**\n * Model identifier. Each provider narrows this to its typed literal\n * union, so code that yields a typed provider tag gets autocompletion.\n */\n readonly model: string\n /**\n * Retrieval-task hint. Applies to the input. OpenAI ignores this;\n * Mixedbread doesn't have it; Cohere v3+ requires it on the wire (typed\n * as required in `CohereEmbedRequest`). Provider-specific task enums\n * (classification, clustering, code retrieval, …) live on the\n * provider's own request type.\n */\n readonly task?: \"query\" | \"document\"\n /**\n * Matryoshka truncation. Default: provider's native dimension.\n * Discrete-value providers (Cohere, Vertex `multimodalembedding@001`)\n * narrow this to a literal union in their typed request.\n */\n readonly dimensions?: number\n /**\n * Output representation - see {@link Encoding}. Dense float32 is the\n * default; provider layers reject unsupported values up front with\n * `InvalidRequest`.\n */\n readonly encoding?: Encoding\n}\n\n/**\n * Cross-provider batch-embed request. One `task` for the whole batch -\n * mixed-task batches aren't a real provider feature (rerankers exist for\n * that).\n */\nexport type CommonEmbedManyRequest = Omit<CommonEmbedRequest, \"input\"> & {\n readonly inputs: ReadonlyArray<EmbedInput>\n}\n\nexport type EmbedResponse = {\n readonly embedding: Embedding\n readonly usage: Usage\n}\n\nexport type EmbedManyResponse = {\n readonly embeddings: ReadonlyArray<Embedding>\n readonly usage: Usage\n}\n\nexport type EmbeddingModelService = {\n readonly embed: (request: CommonEmbedRequest) => Effect.Effect<EmbedResponse, AiError.AiError>\n readonly embedMany: (\n request: CommonEmbedManyRequest,\n ) => Effect.Effect<EmbedManyResponse, AiError.AiError>\n}\n\nexport class EmbeddingModel extends Context.Service<EmbeddingModel, EmbeddingModelService>()(\n \"@betalyra/effect-uai/EmbeddingModel\",\n) {}\n\n/** Embed a single input. */\nexport const embed = (\n request: CommonEmbedRequest,\n): Effect.Effect<EmbedResponse, AiError.AiError, EmbeddingModel> =>\n Effect.flatMap(EmbeddingModel.asEffect(), (m) => m.embed(request))\n\n/** Embed a batch in one provider call. Same `task` for every input. */\nexport const embedMany = (\n request: CommonEmbedManyRequest,\n): Effect.Effect<EmbedManyResponse, AiError.AiError, EmbeddingModel> =>\n Effect.flatMap(EmbeddingModel.asEffect(), (m) => m.embedMany(request))\n"],"mappings":";;;;;;;;AA4FA,IAAa,iBAAb,cAAoC,QAAQ,SAAgD,CAC1F,sCACD,CAAC;;AAGF,MAAa,SACX,YAEA,OAAO,QAAQ,eAAe,UAAU,GAAG,MAAM,EAAE,MAAM,QAAQ,CAAC;;AAGpE,MAAa,aACX,YAEA,OAAO,QAAQ,eAAe,UAAU,GAAG,MAAM,EAAE,UAAU,QAAQ,CAAC"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { n as AiError_d_exports } from "./AiError-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { n as AiError_d_exports } from "./AiError-CBuPHVKA.mjs";
|
|
2
|
+
import { a as Media_d_exports } from "./Media-D_CpcM1Z.mjs";
|
|
3
|
+
import { o as Image_d_exports } from "./Image-BZmKfIdq.mjs";
|
|
4
|
+
import { f as Items_d_exports } from "./Items-CB8Bo3FI.mjs";
|
|
5
|
+
import { a as StructuredFormat_d_exports } from "./StructuredFormat-BWq5Hd1O.mjs";
|
|
6
|
+
import { a as Turn_d_exports } from "./Turn-OPaILVIB.mjs";
|
|
7
|
+
import { t as Embedding_d_exports } from "./embedding-model/Embedding.mjs";
|
|
8
|
+
import { t as EmbeddingModel_d_exports } from "./embedding-model/EmbeddingModel.mjs";
|
|
9
|
+
import { l as Tool_d_exports } from "./Tool-DjVufH7i.mjs";
|
|
6
10
|
import { t as LanguageModel_d_exports } from "./language-model/LanguageModel.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
11
|
+
import { t as Vector_d_exports } from "./math/Vector.mjs";
|
|
12
|
+
import { t as Loop_d_exports } from "./loop/Loop.mjs";
|
|
13
|
+
import { t as Outcome_d_exports } from "./tool/Outcome.mjs";
|
|
14
|
+
import { t as ToolEvent_d_exports } from "./tool/ToolEvent.mjs";
|
|
9
15
|
import { t as Toolkit_d_exports } from "./tool/Toolkit.mjs";
|
|
16
|
+
import { t as Resolvers_d_exports } from "./tool/Resolvers.mjs";
|
|
17
|
+
import { t as HistoryCheck_d_exports } from "./tool/HistoryCheck.mjs";
|
|
10
18
|
import { t as JSONL_d_exports } from "./streaming/JSONL.mjs";
|
|
11
19
|
import { t as Lines_d_exports } from "./streaming/Lines.mjs";
|
|
12
20
|
import { t as SSE_d_exports } from "./streaming/SSE.mjs";
|
|
13
21
|
import { t as Metrics_d_exports } from "./observability/Metrics.mjs";
|
|
14
|
-
export { AiError_d_exports as AiError, Items_d_exports as Items, JSONL_d_exports as JSONL, LanguageModel_d_exports as LanguageModel, Lines_d_exports as Lines, Loop_d_exports as Loop,
|
|
22
|
+
export { AiError_d_exports as AiError, Embedding_d_exports as Embedding, EmbeddingModel_d_exports as EmbeddingModel, HistoryCheck_d_exports as HistoryCheck, Image_d_exports as Image, Items_d_exports as Items, JSONL_d_exports as JSONL, LanguageModel_d_exports as LanguageModel, Lines_d_exports as Lines, Loop_d_exports as Loop, Media_d_exports as Media, Metrics_d_exports as Metrics, Outcome_d_exports as Outcome, Resolvers_d_exports as Resolvers, SSE_d_exports as SSE, StructuredFormat_d_exports as StructuredFormat, Tool_d_exports as Tool, ToolEvent_d_exports as ToolEvent, Toolkit_d_exports as Toolkit, Turn_d_exports as Turn, Vector_d_exports as Vector };
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { t as AiError_exports } from "./domain/AiError.mjs";
|
|
2
|
+
import { t as Image_exports } from "./domain/Image.mjs";
|
|
2
3
|
import { t as Items_exports } from "./domain/Items.mjs";
|
|
4
|
+
import { t as Media_exports } from "./domain/Media.mjs";
|
|
3
5
|
import { t as StructuredFormat_exports } from "./structured-format/StructuredFormat.mjs";
|
|
4
6
|
import { t as Turn_exports } from "./domain/Turn.mjs";
|
|
7
|
+
import { t as Embedding_exports } from "./embedding-model/Embedding.mjs";
|
|
8
|
+
import { t as EmbeddingModel_exports } from "./embedding-model/EmbeddingModel.mjs";
|
|
5
9
|
import { t as LanguageModel_exports } from "./language-model/LanguageModel.mjs";
|
|
10
|
+
import { t as Vector_exports } from "./math/Vector.mjs";
|
|
6
11
|
import { t as Loop_exports } from "./loop/Loop.mjs";
|
|
7
|
-
import { t as Match_exports } from "./match/Match.mjs";
|
|
8
12
|
import { t as Tool_exports } from "./tool/Tool.mjs";
|
|
13
|
+
import { t as Outcome_exports } from "./tool/Outcome.mjs";
|
|
14
|
+
import { t as ToolEvent_exports } from "./tool/ToolEvent.mjs";
|
|
9
15
|
import { t as Toolkit_exports } from "./tool/Toolkit.mjs";
|
|
16
|
+
import { t as Resolvers_exports } from "./tool/Resolvers.mjs";
|
|
17
|
+
import { t as HistoryCheck_exports } from "./tool/HistoryCheck.mjs";
|
|
10
18
|
import { t as JSONL_exports } from "./streaming/JSONL.mjs";
|
|
11
19
|
import { t as Lines_exports } from "./streaming/Lines.mjs";
|
|
12
20
|
import { t as SSE_exports } from "./streaming/SSE.mjs";
|
|
13
21
|
import { t as Metrics_exports } from "./observability/Metrics.mjs";
|
|
14
|
-
export { AiError_exports as AiError, Items_exports as Items, JSONL_exports as JSONL, LanguageModel_exports as LanguageModel, Lines_exports as Lines, Loop_exports as Loop,
|
|
22
|
+
export { AiError_exports as AiError, Embedding_exports as Embedding, EmbeddingModel_exports as EmbeddingModel, HistoryCheck_exports as HistoryCheck, Image_exports as Image, Items_exports as Items, JSONL_exports as JSONL, LanguageModel_exports as LanguageModel, Lines_exports as Lines, Loop_exports as Loop, Media_exports as Media, Metrics_exports as Metrics, Outcome_exports as Outcome, Resolvers_exports as Resolvers, SSE_exports as SSE, StructuredFormat_exports as StructuredFormat, Tool_exports as Tool, ToolEvent_exports as ToolEvent, Toolkit_exports as Toolkit, Turn_exports as Turn, Vector_exports as Vector };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
2
|
-
import {
|
|
3
|
-
import { i as StructuredFormat } from "../StructuredFormat-
|
|
4
|
-
import {
|
|
5
|
-
import { o as ToolDescriptor } from "../Tool-
|
|
6
|
-
import { Context,
|
|
1
|
+
import { t as AiError } from "../AiError-CBuPHVKA.mjs";
|
|
2
|
+
import { d as Item } from "../Items-CB8Bo3FI.mjs";
|
|
3
|
+
import { i as StructuredFormat } from "../StructuredFormat-BWq5Hd1O.mjs";
|
|
4
|
+
import { i as TurnEvent } from "../Turn-OPaILVIB.mjs";
|
|
5
|
+
import { o as ToolDescriptor } from "../Tool-DjVufH7i.mjs";
|
|
6
|
+
import { Context, Stream } from "effect";
|
|
7
7
|
|
|
8
8
|
//#region src/language-model/LanguageModel.d.ts
|
|
9
9
|
declare namespace LanguageModel_d_exports {
|
|
10
|
-
export { CommonRequest, LanguageModel, LanguageModelService, streamTurn
|
|
10
|
+
export { CommonRequest, LanguageModel, LanguageModelService, streamTurn };
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Cross-provider request shape. Every call carries its own `history` and
|
|
@@ -15,7 +15,7 @@ declare namespace LanguageModel_d_exports {
|
|
|
15
15
|
* to a single provider (reasoning effort, prompt caching, store flags,
|
|
16
16
|
* ...) lives in that provider's own request interface, which extends this.
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
type CommonRequest = {
|
|
19
19
|
readonly history: ReadonlyArray<Item>;
|
|
20
20
|
/**
|
|
21
21
|
* Model identifier. Each provider narrows this to its typed literal union,
|
|
@@ -37,24 +37,16 @@ interface CommonRequest {
|
|
|
37
37
|
* `output_config`, Gemini `responseJsonSchema`).
|
|
38
38
|
*/
|
|
39
39
|
readonly structured?: StructuredFormat<unknown>;
|
|
40
|
-
}
|
|
41
|
-
|
|
40
|
+
};
|
|
41
|
+
type LanguageModelService = {
|
|
42
42
|
readonly streamTurn: (request: CommonRequest) => Stream.Stream<TurnEvent, AiError>;
|
|
43
|
-
}
|
|
43
|
+
};
|
|
44
44
|
declare const LanguageModel_base: Context.ServiceClass<LanguageModel, "@betalyra/effect-uai/LanguageModel", LanguageModelService>;
|
|
45
45
|
declare class LanguageModel extends LanguageModel_base {}
|
|
46
46
|
/**
|
|
47
47
|
* Stream the deltas of a single turn.
|
|
48
48
|
*/
|
|
49
49
|
declare const streamTurn: (request: CommonRequest) => Stream.Stream<TurnEvent, AiError, LanguageModel>;
|
|
50
|
-
/**
|
|
51
|
-
* Run a single turn to completion and return the assembled `Turn`.
|
|
52
|
-
*
|
|
53
|
-
* Implementation: drain the delta stream and pluck the terminal
|
|
54
|
-
* `turn_complete` event. The provider is contractually required to emit
|
|
55
|
-
* exactly one such event as the last delta.
|
|
56
|
-
*/
|
|
57
|
-
declare const turn: (request: CommonRequest) => Effect.Effect<Turn, AiError, LanguageModel>;
|
|
58
50
|
//#endregion
|
|
59
|
-
export { CommonRequest, LanguageModel, LanguageModelService, streamTurn, LanguageModel_d_exports as t
|
|
51
|
+
export { CommonRequest, LanguageModel, LanguageModelService, streamTurn, LanguageModel_d_exports as t };
|
|
60
52
|
//# sourceMappingURL=LanguageModel.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LanguageModel.d.mts","names":[],"sources":["../../src/language-model/LanguageModel.ts"],"mappings":";;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"LanguageModel.d.mts","names":[],"sources":["../../src/language-model/LanguageModel.ts"],"mappings":";;;;;;;;;;;;;;;;;KAaY,aAAA;EAAA,SACD,OAAA,EAAS,aAAA,CAAc,IAAA;;AADlC;;;WAMW,KAAA;EAAA,SACA,KAAA,GAAQ,aAAA,CAAc,cAAA;EAAA,SACtB,UAAA;IAAA,SAIM,IAAA;IAAA,SAA2B,IAAA;EAAA;EAAA,SACjC,WAAA;EAAA,SACA,IAAA;EAAA,SACA,eAAA;EAduB;;;;;;EAAA,SAqBvB,UAAA,GAAa,gBAAA;AAAA;AAAA,KAGZ,oBAAA;EAAA,SACD,UAAA,GAAa,OAAA,EAAS,aAAA,KAAkB,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA;AAAA;AAAA,cAC3E,kBAAA;cAEY,aAAA,SAAsB,kBAAA;;;AAJnC;cAWa,UAAA,GACX,OAAA,EAAS,aAAA,KACR,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAA,EAAiB,aAAA"}
|
|
@@ -1,33 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Unavailable } from "../domain/AiError.mjs";
|
|
3
|
-
import { isTurnComplete } from "../domain/Turn.mjs";
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
4
2
|
import { Context, Effect, Stream } from "effect";
|
|
5
3
|
//#region src/language-model/LanguageModel.ts
|
|
6
4
|
var LanguageModel_exports = /* @__PURE__ */ __exportAll({
|
|
7
5
|
LanguageModel: () => LanguageModel,
|
|
8
|
-
streamTurn: () => streamTurn
|
|
9
|
-
turn: () => turn
|
|
6
|
+
streamTurn: () => streamTurn
|
|
10
7
|
});
|
|
11
8
|
var LanguageModel = class extends Context.Service()("@betalyra/effect-uai/LanguageModel") {};
|
|
12
9
|
/**
|
|
13
10
|
* Stream the deltas of a single turn.
|
|
14
11
|
*/
|
|
15
12
|
const streamTurn = (request) => Stream.unwrap(Effect.map(LanguageModel.asEffect(), (m) => m.streamTurn(request)));
|
|
16
|
-
/**
|
|
17
|
-
* Run a single turn to completion and return the assembled `Turn`.
|
|
18
|
-
*
|
|
19
|
-
* Implementation: drain the delta stream and pluck the terminal
|
|
20
|
-
* `turn_complete` event. The provider is contractually required to emit
|
|
21
|
-
* exactly one such event as the last delta.
|
|
22
|
-
*/
|
|
23
|
-
const turn = (request) => Effect.flatMap(Stream.runCollect(streamTurn(request)), (deltas) => {
|
|
24
|
-
const last = deltas[deltas.length - 1];
|
|
25
|
-
return last !== void 0 && isTurnComplete(last) ? Effect.succeed(last.turn) : Effect.fail(new Unavailable({
|
|
26
|
-
provider: "unknown",
|
|
27
|
-
raw: "Provider stream ended without a turn_complete event"
|
|
28
|
-
}));
|
|
29
|
-
});
|
|
30
13
|
//#endregion
|
|
31
|
-
export { LanguageModel, streamTurn, LanguageModel_exports as t
|
|
14
|
+
export { LanguageModel, streamTurn, LanguageModel_exports as t };
|
|
32
15
|
|
|
33
16
|
//# sourceMappingURL=LanguageModel.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LanguageModel.mjs","names":[
|
|
1
|
+
{"version":3,"file":"LanguageModel.mjs","names":[],"sources":["../../src/language-model/LanguageModel.ts"],"sourcesContent":["import { Context, Effect, Stream } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { Item } from \"../domain/Items.js\"\nimport type * as StructuredFormat from \"../structured-format/StructuredFormat.js\"\nimport type { ToolDescriptor } from \"../tool/Tool.js\"\nimport { isTurnComplete, type Turn, type TurnEvent } from \"../domain/Turn.js\"\n\n/**\n * Cross-provider request shape. Every call carries its own `history` and\n * `model` - models are not bound at layer construction. Anything specific\n * to a single provider (reasoning effort, prompt caching, store flags,\n * ...) lives in that provider's own request interface, which extends this.\n */\nexport type CommonRequest = {\n readonly history: ReadonlyArray<Item>\n /**\n * Model identifier. Each provider narrows this to its typed literal union,\n * so code that yields a typed provider tag gets autocompletion.\n */\n readonly model: string\n readonly tools?: ReadonlyArray<ToolDescriptor>\n readonly toolChoice?:\n | \"auto\"\n | \"required\"\n | \"none\"\n | { readonly type: \"function\"; readonly name: string }\n readonly temperature?: number\n readonly topP?: number\n readonly maxOutputTokens?: number\n /**\n * Schema-bound JSON output. The provider constrains the wire to match the\n * schema; pair with `Turn.toStructured` for runtime validation. Supported\n * across all current providers (OpenAI Responses json_schema, Anthropic\n * `output_config`, Gemini `responseJsonSchema`).\n */\n readonly structured?: StructuredFormat.StructuredFormat<unknown>\n}\n\nexport type LanguageModelService = {\n readonly streamTurn: (request: CommonRequest) => Stream.Stream<TurnEvent, AiError.AiError>\n}\n\nexport class LanguageModel extends Context.Service<LanguageModel, LanguageModelService>()(\n \"@betalyra/effect-uai/LanguageModel\",\n) {}\n\n/**\n * Stream the deltas of a single turn.\n */\nexport const streamTurn = (\n request: CommonRequest,\n): Stream.Stream<TurnEvent, AiError.AiError, LanguageModel> =>\n Stream.unwrap(Effect.map(LanguageModel.asEffect(), (m) => m.streamTurn(request)))\n"],"mappings":";;;;;;;AA0CA,IAAa,gBAAb,cAAmC,QAAQ,SAA8C,CACvF,qCACD,CAAC;;;;AAKF,MAAa,cACX,YAEA,OAAO,OAAO,OAAO,IAAI,cAAc,UAAU,GAAG,MAAM,EAAE,WAAW,QAAQ,CAAC,CAAC"}
|
package/dist/loop/Loop.d.mts
CHANGED
|
@@ -1,2 +1,111 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { l as IncompleteTurn } from "../AiError-CBuPHVKA.mjs";
|
|
2
|
+
import { i as TurnEvent, r as Turn } from "../Turn-OPaILVIB.mjs";
|
|
3
|
+
import { Data, Effect, Stream, SubscriptionRef } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/loop/Loop.d.ts
|
|
6
|
+
declare namespace Loop_d_exports {
|
|
7
|
+
export { Event, loop, loopWithState, next, nextAfter, nextAfterFold, onTurnComplete, stop, stopAfter, stopEvent, value };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The tagged union a body emits per pull. `Value` carries a payload that
|
|
11
|
+
* flows downstream. `Next` ends the current iteration and continues with a
|
|
12
|
+
* new state. `Stop` ends the loop entirely.
|
|
13
|
+
*/
|
|
14
|
+
type Event<A, S> = Data.TaggedEnum<{
|
|
15
|
+
Value: {
|
|
16
|
+
readonly value: A;
|
|
17
|
+
};
|
|
18
|
+
Next: {
|
|
19
|
+
readonly state: S;
|
|
20
|
+
};
|
|
21
|
+
Stop: {};
|
|
22
|
+
}>;
|
|
23
|
+
/** Wrap a value so it flows through the loop to downstream consumers. */
|
|
24
|
+
declare const value: <A>(a: A) => Event<A, never>;
|
|
25
|
+
/** End the current iteration and continue with a new state. */
|
|
26
|
+
declare const next: <S>(state: S) => Event<never, S>;
|
|
27
|
+
/** The terminal `Stop` event. Use `stop` (the Stream) to end a loop body. */
|
|
28
|
+
declare const stopEvent: Event<never, never>;
|
|
29
|
+
/**
|
|
30
|
+
* A single-element stream that ends the loop. Return this from a body when
|
|
31
|
+
* there's nothing else to emit; equivalent to `stopAfter(Stream.empty)` but
|
|
32
|
+
* named for the common case.
|
|
33
|
+
*/
|
|
34
|
+
declare const stop: Stream.Stream<Event<never, never>>;
|
|
35
|
+
/**
|
|
36
|
+
* Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the
|
|
37
|
+
* iteration with `next(state)`. Common shape for "stream this turn's
|
|
38
|
+
* deltas, then continue with updated history."
|
|
39
|
+
*/
|
|
40
|
+
declare const nextAfter: <S, A, E, R>(stream: Stream.Stream<A, E, R>, state: S) => Stream.Stream<Event<A, S>, E, R>;
|
|
41
|
+
/**
|
|
42
|
+
* Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the
|
|
43
|
+
* loop. Common shape for "stream this turn's deltas, then we're done."
|
|
44
|
+
*/
|
|
45
|
+
declare const stopAfter: <A, E, R>(stream: Stream.Stream<A, E, R>) => Stream.Stream<Event<A, never>, E, R>;
|
|
46
|
+
/**
|
|
47
|
+
* General `nextAfter` variant: drain `stream` to the consumer, fold elements
|
|
48
|
+
* into an accumulator, and at end-of-stream emit one `next(build(finalAcc))`.
|
|
49
|
+
*
|
|
50
|
+
* Subsumes `nextAfter` when state is constant (`reduce: (s, _) => s`,
|
|
51
|
+
* `build: (s) => s`). Used by `Toolkit.continueWith` to collect tool
|
|
52
|
+
* results and build next state without exposing a Ref to recipes.
|
|
53
|
+
*/
|
|
54
|
+
declare const nextAfterFold: <A, B, S, E, R>(stream: Stream.Stream<A, E, R>, initial: B, reduce: (acc: B, a: A) => B, build: (b: B) => S) => Stream.Stream<Event<A, S>, E, R>;
|
|
55
|
+
/**
|
|
56
|
+
* Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Event<TurnEvent | A, S>>`.
|
|
57
|
+
* Each delta passes through as `value(delta)` (including the terminal
|
|
58
|
+
* `turn_complete`, so the consumer sees turn boundaries naturally). Once
|
|
59
|
+
* the terminal arrives, `then(turn)` runs and its returned stream of loop
|
|
60
|
+
* events (typically tool outputs followed by `next(state)` or `stop`) is
|
|
61
|
+
* concatenated.
|
|
62
|
+
*
|
|
63
|
+
* Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on
|
|
64
|
+
* the raw delta stream cover anything an `emit`-style callback would do.
|
|
65
|
+
*
|
|
66
|
+
* If the upstream ends without a `turn_complete`, the resulting stream
|
|
67
|
+
* fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if
|
|
68
|
+
* you want to recover.
|
|
69
|
+
*/
|
|
70
|
+
declare const onTurnComplete: <S, A, E2 = never, R2 = never>(then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>) => <E, R>(deltas: Stream.Stream<TurnEvent, E, R>) => Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>;
|
|
71
|
+
type LoopBody<S, A, E, R> = (state: S) => Stream.Stream<Event<A, S>, E, R> | Effect.Effect<Stream.Stream<Event<A, S>, E, R>, E, R>;
|
|
72
|
+
/**
|
|
73
|
+
* Drive a state-threaded loop body. Each iteration runs `body(state)` to get
|
|
74
|
+
* a `Stream<Event<A, S>>`; values flow downstream, `next(s)` continues with
|
|
75
|
+
* a new state, `stop` ends the loop. See the file header for the full
|
|
76
|
+
* pull-based execution model.
|
|
77
|
+
*
|
|
78
|
+
* Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`
|
|
79
|
+
* (or `pipe(initial, loop(body))`) both work.
|
|
80
|
+
*/
|
|
81
|
+
declare const loop: {
|
|
82
|
+
<S, A, E, R>(body: LoopBody<S, A, E, R>): (initial: S) => Stream.Stream<A, E, R>;
|
|
83
|
+
<S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R>;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Like `loop`, but exposes the current loop state as a `SubscriptionRef`
|
|
87
|
+
* alongside the value stream.
|
|
88
|
+
*
|
|
89
|
+
* Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the
|
|
90
|
+
* loop with a wrapped body that taps every `Next(s)` event into the ref
|
|
91
|
+
* before forwarding it. The caller decides how to consume both channels:
|
|
92
|
+
*
|
|
93
|
+
* - **Final state**: drain the stream, then `SubscriptionRef.get(state)`
|
|
94
|
+
* - the ref holds the state from the last `Next` (or `initial` if the
|
|
95
|
+
* loop ended without advancing).
|
|
96
|
+
* - **Live transitions**: `SubscriptionRef.changes(state)` is a
|
|
97
|
+
* `Stream<S>` of every state observed; subscribe alongside the value
|
|
98
|
+
* stream.
|
|
99
|
+
* - **Mid-iteration peek**: `SubscriptionRef.get(state)` at any time.
|
|
100
|
+
*
|
|
101
|
+
* The returned stream and ref are independent of each other - the ref
|
|
102
|
+
* lives outside the stream's scope, so reading it after the stream
|
|
103
|
+
* completes is safe.
|
|
104
|
+
*/
|
|
105
|
+
declare const loopWithState: <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>) => Effect.Effect<{
|
|
106
|
+
readonly stream: Stream.Stream<A, E, R>;
|
|
107
|
+
readonly state: SubscriptionRef.SubscriptionRef<S>;
|
|
108
|
+
}>;
|
|
109
|
+
//#endregion
|
|
110
|
+
export { Event, loop, loopWithState, next, nextAfter, nextAfterFold, onTurnComplete, stop, stopAfter, stopEvent, Loop_d_exports as t, value };
|
|
111
|
+
//# sourceMappingURL=Loop.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Loop.d.mts","names":[],"sources":["../../src/loop/Loop.ts"],"mappings":"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"}
|
package/dist/loop/Loop.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
2
2
|
import { IncompleteTurn } from "../domain/AiError.mjs";
|
|
3
3
|
import { isTurnComplete } from "../domain/Turn.mjs";
|
|
4
|
-
import { Cause, Channel, Data, Effect, Exit, Function, Option, Ref, Scope, Stream } from "effect";
|
|
4
|
+
import { Cause, Channel, Data, Effect, Exit, Function, Option, Ref, Scope, Stream, SubscriptionRef } from "effect";
|
|
5
5
|
//#region src/loop/Loop.ts
|
|
6
6
|
/**
|
|
7
7
|
* Pull-based `loop` for state-threaded sub-streams.
|
|
@@ -24,13 +24,14 @@ import { Cause, Channel, Data, Effect, Exit, Function, Option, Ref, Scope, Strea
|
|
|
24
24
|
*/
|
|
25
25
|
var Loop_exports = /* @__PURE__ */ __exportAll({
|
|
26
26
|
loop: () => loop,
|
|
27
|
+
loopWithState: () => loopWithState,
|
|
27
28
|
next: () => next,
|
|
28
29
|
nextAfter: () => nextAfter,
|
|
29
30
|
nextAfterFold: () => nextAfterFold,
|
|
31
|
+
onTurnComplete: () => onTurnComplete,
|
|
30
32
|
stop: () => stop,
|
|
31
33
|
stopAfter: () => stopAfter,
|
|
32
34
|
stopEvent: () => stopEvent,
|
|
33
|
-
streamUntilComplete: () => streamUntilComplete,
|
|
34
35
|
value: () => value
|
|
35
36
|
});
|
|
36
37
|
const Event = Data.taggedEnum();
|
|
@@ -62,7 +63,7 @@ const stopAfter = (stream) => Stream.concat(Stream.map(stream, value), Stream.fr
|
|
|
62
63
|
* into an accumulator, and at end-of-stream emit one `next(build(finalAcc))`.
|
|
63
64
|
*
|
|
64
65
|
* Subsumes `nextAfter` when state is constant (`reduce: (s, _) => s`,
|
|
65
|
-
* `build: (s) => s`). Used by `Toolkit.
|
|
66
|
+
* `build: (s) => s`). Used by `Toolkit.continueWith` to collect tool
|
|
66
67
|
* results and build next state without exposing a Ref to recipes.
|
|
67
68
|
*/
|
|
68
69
|
const nextAfterFold = (stream, initial, reduce, build) => Stream.unwrap(Effect.gen(function* () {
|
|
@@ -86,7 +87,7 @@ const nextAfterFold = (stream, initial, reduce, build) => Stream.unwrap(Effect.g
|
|
|
86
87
|
* fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if
|
|
87
88
|
* you want to recover.
|
|
88
89
|
*/
|
|
89
|
-
const
|
|
90
|
+
const onTurnComplete = (then) => (deltas) => Stream.unwrap(Effect.gen(function* () {
|
|
90
91
|
const turnRef = yield* Ref.make(Option.none());
|
|
91
92
|
const events = deltas.pipe(Stream.tap((delta) => isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void), Stream.map(value));
|
|
92
93
|
const continuation = Stream.unwrap(Effect.gen(function* () {
|
|
@@ -166,7 +167,39 @@ const loop = Function.dual(2, (initial, body) => Stream.scoped(Stream.fromPull(E
|
|
|
166
167
|
}
|
|
167
168
|
});
|
|
168
169
|
}))));
|
|
170
|
+
/**
|
|
171
|
+
* Like `loop`, but exposes the current loop state as a `SubscriptionRef`
|
|
172
|
+
* alongside the value stream.
|
|
173
|
+
*
|
|
174
|
+
* Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the
|
|
175
|
+
* loop with a wrapped body that taps every `Next(s)` event into the ref
|
|
176
|
+
* before forwarding it. The caller decides how to consume both channels:
|
|
177
|
+
*
|
|
178
|
+
* - **Final state**: drain the stream, then `SubscriptionRef.get(state)`
|
|
179
|
+
* - the ref holds the state from the last `Next` (or `initial` if the
|
|
180
|
+
* loop ended without advancing).
|
|
181
|
+
* - **Live transitions**: `SubscriptionRef.changes(state)` is a
|
|
182
|
+
* `Stream<S>` of every state observed; subscribe alongside the value
|
|
183
|
+
* stream.
|
|
184
|
+
* - **Mid-iteration peek**: `SubscriptionRef.get(state)` at any time.
|
|
185
|
+
*
|
|
186
|
+
* The returned stream and ref are independent of each other - the ref
|
|
187
|
+
* lives outside the stream's scope, so reading it after the stream
|
|
188
|
+
* completes is safe.
|
|
189
|
+
*/
|
|
190
|
+
const loopWithState = (initial, body) => Effect.gen(function* () {
|
|
191
|
+
const stateRef = yield* SubscriptionRef.make(initial);
|
|
192
|
+
const tap = (stream) => stream.pipe(Stream.tap((event) => event._tag === "Next" ? SubscriptionRef.set(stateRef, event.state) : Effect.void));
|
|
193
|
+
const wrappedBody = (s) => {
|
|
194
|
+
const result = body(s);
|
|
195
|
+
return Effect.isEffect(result) ? Effect.map(result, tap) : tap(result);
|
|
196
|
+
};
|
|
197
|
+
return {
|
|
198
|
+
stream: loop(initial, wrappedBody),
|
|
199
|
+
state: stateRef
|
|
200
|
+
};
|
|
201
|
+
});
|
|
169
202
|
//#endregion
|
|
170
|
-
export { loop, next, nextAfter, nextAfterFold, stop, stopAfter, stopEvent,
|
|
203
|
+
export { loop, loopWithState, next, nextAfter, nextAfterFold, onTurnComplete, stop, stopAfter, stopEvent, Loop_exports as t, value };
|
|
171
204
|
|
|
172
205
|
//# sourceMappingURL=Loop.mjs.map
|
package/dist/loop/Loop.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Loop.mjs","names":[],"sources":["../../src/loop/Loop.ts"],"sourcesContent":["/**\n * Pull-based `loop` for state-threaded sub-streams.\n *\n * Each iteration runs a body that returns a `Stream<Event<A, S>>`. The body\n * emits values via `Loop.value(a)` and signals iteration control via\n * `Loop.next(state)` (continue with new state) or `Loop.stop` (terminate).\n * The loop unwraps `Value` events back to `A` for downstream consumers, so\n * the resulting stream is a plain `Stream<A>`.\n *\n * The next body stream is only pulled when downstream pulls the outer\n * stream - no producer fiber, no queue buffering. Cancellation, failures,\n * scoped resources, and backpressure stay aligned with normal Stream\n * semantics.\n *\n * Convention: a `Next` or `Stop` event is the terminal element of a body's\n * iteration. Values emitted in the same chunk after one are discarded\n * (their producing side effects may already have run). Prefer the\n * `Loop.nextAfter` / `Loop.stopAfter` helpers to terminate cleanly.\n */\nimport { Cause, Channel, Data, Effect, Exit, Function, Option, Ref, Scope, Stream } from \"effect\"\nimport { IncompleteTurn } from \"../domain/AiError.js\"\nimport { isTurnComplete, type Turn, type TurnEvent } from \"../domain/Turn.js\"\n\n// ---------------------------------------------------------------------------\n// Event type - the body's emit shape\n// ---------------------------------------------------------------------------\n\n/**\n * The tagged union a body emits per pull. `Value` carries a payload that\n * flows downstream. `Next` ends the current iteration and continues with a\n * new state. `Stop` ends the loop entirely.\n */\nexport type Event<A, S> = Data.TaggedEnum<{\n Value: { readonly value: A }\n Next: { readonly state: S }\n Stop: {}\n}>\n\ninterface EventDef extends Data.TaggedEnum.WithGenerics<2> {\n readonly taggedEnum: Event<this[\"A\"], this[\"B\"]>\n}\n\nconst Event = Data.taggedEnum<EventDef>()\n\n/** Wrap a value so it flows through the loop to downstream consumers. */\nexport const value = <A>(a: A): Event<A, never> => Event.Value({ value: a })\n\n/** End the current iteration and continue with a new state. */\nexport const next = <S>(state: S): Event<never, S> => Event.Next({ state })\n\n/** The terminal `Stop` event. Use `stop` (the Stream) to end a loop body. */\nexport const stopEvent: Event<never, never> = Event.Stop()\n\n/**\n * A single-element stream that ends the loop. Return this from a body when\n * there's nothing else to emit; equivalent to `stopAfter(Stream.empty)` but\n * named for the common case.\n */\nexport const stop: Stream.Stream<Event<never, never>> = Stream.succeed(stopEvent)\n\n/**\n * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the\n * iteration with `next(state)`. Common shape for \"stream this turn's\n * deltas, then continue with updated history.\"\n */\nexport const nextAfter = <S, A, E, R>(\n stream: Stream.Stream<A, E, R>,\n state: S,\n): Stream.Stream<Event<A, S>, E, R> =>\n Stream.concat(Stream.map(stream, value), Stream.fromIterable([next(state)]))\n\n/**\n * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the\n * loop. Common shape for \"stream this turn's deltas, then we're done.\"\n */\nexport const stopAfter = <A, E, R>(\n stream: Stream.Stream<A, E, R>,\n): Stream.Stream<Event<A, never>, E, R> =>\n Stream.concat(Stream.map(stream, value), Stream.fromIterable([stopEvent]))\n\n/**\n * General `nextAfter` variant: drain `stream` to the consumer, fold elements\n * into an accumulator, and at end-of-stream emit one `next(build(finalAcc))`.\n *\n * Subsumes `nextAfter` when state is constant (`reduce: (s, _) => s`,\n * `build: (s) => s`). Used by `Toolkit.nextStateFrom` to collect tool\n * results and build next state without exposing a Ref to recipes.\n */\nexport const nextAfterFold = <A, B, S, E, R>(\n stream: Stream.Stream<A, E, R>,\n initial: B,\n reduce: (acc: B, a: A) => B,\n build: (b: B) => S,\n): Stream.Stream<Event<A, S>, E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const ref = yield* Ref.make(initial)\n const tapped = stream.pipe(\n Stream.tap((a) => Ref.update(ref, (acc) => reduce(acc, a))),\n Stream.map(value),\n )\n const continuation = Stream.fromEffect(\n Ref.get(ref).pipe(Effect.map((acc) => next(build(acc)))),\n )\n return tapped.pipe(Stream.concat(continuation))\n }),\n )\n\n// ---------------------------------------------------------------------------\n// streamUntilComplete - turn-aware stream operator for loop bodies\n// ---------------------------------------------------------------------------\n\n/**\n * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Event<TurnEvent | A, S>>`.\n * Each delta passes through as `value(delta)` (including the terminal\n * `turn_complete`, so the consumer sees turn boundaries naturally). Once\n * the terminal arrives, `then(turn)` runs and its returned stream of loop\n * events (typically tool outputs followed by `next(state)` or `stop`) is\n * concatenated.\n *\n * Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on\n * the raw delta stream cover anything an `emit`-style callback would do.\n *\n * If the upstream ends without a `turn_complete`, the resulting stream\n * fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if\n * you want to recover.\n */\nexport const streamUntilComplete =\n <S, A, E2 = never, R2 = never>(\n then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>,\n ) =>\n <E, R>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n ): Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turnRef = yield* Ref.make<Option.Option<Turn>>(Option.none())\n\n const events: Stream.Stream<Event<TurnEvent, S>, E, R> = deltas.pipe(\n Stream.tap((delta) =>\n isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void,\n ),\n Stream.map(value),\n )\n\n const continuation = Stream.unwrap(\n Effect.gen(function* () {\n const opt = yield* Ref.get(turnRef)\n if (Option.isNone(opt)) return yield* Effect.fail(new IncompleteTurn({}))\n return yield* then(opt.value)\n }),\n )\n\n return Stream.concat(events, continuation)\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst isNonEmpty = <A>(array: ReadonlyArray<A>): array is readonly [A, ...Array<A>] =>\n array.length > 0\n\ninterface CurrentBody<S, A, E, R> {\n readonly scope: Scope.Closeable\n readonly pull: Effect.Effect<ReadonlyArray<Event<A, S>>, E | Cause.Done<void>, R>\n}\n\nconst closeBody = <S, A, E, R>(\n current: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n) => Scope.close(current.scope, exit)\n\n/**\n * Walk a chunk of `Event<A, S>` until a terminal `Next` or `Stop` is found.\n * Returns the unwrapped values seen so far and (optionally) the terminal\n * event. Anything in the chunk after the terminal is discarded - its\n * producing side effects may have run, but downstream never sees it.\n */\nconst partitionChunk = <A, S>(\n chunk: ReadonlyArray<Event<A, S>>,\n): { readonly values: Array<A>; readonly decision: Event<A, S> | undefined } => {\n const values: Array<A> = []\n for (let i = 0; i < chunk.length; i++) {\n const event = chunk[i]!\n if (event._tag === \"Value\") {\n values.push(event.value)\n } else {\n return { values, decision: event }\n }\n }\n return { values, decision: undefined }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\ntype LoopBody<S, A, E, R> = (\n state: S,\n) => Stream.Stream<Event<A, S>, E, R> | Effect.Effect<Stream.Stream<Event<A, S>, E, R>, E, R>\n\n/**\n * Drive a state-threaded loop body. Each iteration runs `body(state)` to get\n * a `Stream<Event<A, S>>`; values flow downstream, `next(s)` continues with\n * a new state, `stop` ends the loop. See the file header for the full\n * pull-based execution model.\n *\n * Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`\n * (or `pipe(initial, loop(body))`) both work.\n */\nexport const loop: {\n <S, A, E, R>(body: LoopBody<S, A, E, R>): (initial: S) => Stream.Stream<A, E, R>\n <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R>\n} = Function.dual(\n 2,\n <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>\n Stream.scoped(\n Stream.fromPull(\n Effect.gen(function* () {\n const outerScope = yield* Effect.scope\n let state = initial\n let current: CurrentBody<S, A, E, R> | undefined\n let done = false\n\n const closeActive = (\n active: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n ) => {\n const isActive = current === active\n if (isActive) current = undefined\n // Scope.close is idempotent. Multiple paths can race to close the\n // active body during cancellation/failure, so closing twice is safe.\n return closeBody(active, exit)\n }\n\n yield* Scope.addFinalizerExit(outerScope, (exit) =>\n current === undefined ? Effect.void : closeActive(current, exit),\n )\n\n const pull = Effect.gen(function* () {\n while (true) {\n if (done) return yield* Cause.done()\n\n if (current === undefined) {\n const result = body(state)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n const bodyScope = yield* Scope.fork(outerScope)\n const bodyPull = yield* Channel.toPullScoped(\n Stream.toChannel(stream),\n bodyScope,\n ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))\n current = { scope: bodyScope, pull: bodyPull }\n }\n\n const active = current\n const chunk = yield* active.pull.pipe(\n Effect.catchIf(Cause.isDone, () =>\n closeActive(active, Exit.void).pipe(\n Effect.as(undefined as ReadonlyArray<Event<A, S>> | undefined),\n ),\n ),\n Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),\n )\n\n if (chunk === undefined) {\n done = true\n return yield* Cause.done()\n }\n\n const { values, decision } = partitionChunk(chunk)\n\n if (decision !== undefined) {\n yield* closeActive(active, Exit.void)\n if (decision._tag === \"Stop\") {\n done = true\n } else if (decision._tag === \"Next\") {\n state = decision.state\n }\n }\n\n // Emit the values seen so far if any. Chunks from a Stream pull\n // are non-empty, so when `decision === undefined` every event was\n // a `Value` and `values` is non-empty here. With a decision and\n // no preceding values, fall through to the next iteration.\n if (isNonEmpty(values)) return values\n }\n })\n\n return pull\n }),\n ),\n ),\n)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Loop.mjs","names":[],"sources":["../../src/loop/Loop.ts"],"sourcesContent":["/**\n * Pull-based `loop` for state-threaded sub-streams.\n *\n * Each iteration runs a body that returns a `Stream<Event<A, S>>`. The body\n * emits values via `Loop.value(a)` and signals iteration control via\n * `Loop.next(state)` (continue with new state) or `Loop.stop` (terminate).\n * The loop unwraps `Value` events back to `A` for downstream consumers, so\n * the resulting stream is a plain `Stream<A>`.\n *\n * The next body stream is only pulled when downstream pulls the outer\n * stream - no producer fiber, no queue buffering. Cancellation, failures,\n * scoped resources, and backpressure stay aligned with normal Stream\n * semantics.\n *\n * Convention: a `Next` or `Stop` event is the terminal element of a body's\n * iteration. Values emitted in the same chunk after one are discarded\n * (their producing side effects may already have run). Prefer the\n * `Loop.nextAfter` / `Loop.stopAfter` helpers to terminate cleanly.\n */\nimport {\n Cause,\n Channel,\n Data,\n Effect,\n Exit,\n Function,\n Option,\n Ref,\n Scope,\n Stream,\n SubscriptionRef,\n} from \"effect\"\nimport { IncompleteTurn } from \"../domain/AiError.js\"\nimport { isTurnComplete, type Turn, type TurnEvent } from \"../domain/Turn.js\"\n\n// ---------------------------------------------------------------------------\n// Event type - the body's emit shape\n// ---------------------------------------------------------------------------\n\n/**\n * The tagged union a body emits per pull. `Value` carries a payload that\n * flows downstream. `Next` ends the current iteration and continues with a\n * new state. `Stop` ends the loop entirely.\n */\nexport type Event<A, S> = Data.TaggedEnum<{\n Value: { readonly value: A }\n Next: { readonly state: S }\n Stop: {}\n}>\n\ninterface EventDef extends Data.TaggedEnum.WithGenerics<2> {\n readonly taggedEnum: Event<this[\"A\"], this[\"B\"]>\n}\n\nconst Event = Data.taggedEnum<EventDef>()\n\n/** Wrap a value so it flows through the loop to downstream consumers. */\nexport const value = <A>(a: A): Event<A, never> => Event.Value({ value: a })\n\n/** End the current iteration and continue with a new state. */\nexport const next = <S>(state: S): Event<never, S> => Event.Next({ state })\n\n/** The terminal `Stop` event. Use `stop` (the Stream) to end a loop body. */\nexport const stopEvent: Event<never, never> = Event.Stop()\n\n/**\n * A single-element stream that ends the loop. Return this from a body when\n * there's nothing else to emit; equivalent to `stopAfter(Stream.empty)` but\n * named for the common case.\n */\nexport const stop: Stream.Stream<Event<never, never>> = Stream.succeed(stopEvent)\n\n/**\n * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the\n * iteration with `next(state)`. Common shape for \"stream this turn's\n * deltas, then continue with updated history.\"\n */\nexport const nextAfter = <S, A, E, R>(\n stream: Stream.Stream<A, E, R>,\n state: S,\n): Stream.Stream<Event<A, S>, E, R> =>\n Stream.concat(Stream.map(stream, value), Stream.fromIterable([next(state)]))\n\n/**\n * Pipe a raw `Stream<A>` into the loop's emit shape, then terminate the\n * loop. Common shape for \"stream this turn's deltas, then we're done.\"\n */\nexport const stopAfter = <A, E, R>(\n stream: Stream.Stream<A, E, R>,\n): Stream.Stream<Event<A, never>, E, R> =>\n Stream.concat(Stream.map(stream, value), Stream.fromIterable([stopEvent]))\n\n/**\n * General `nextAfter` variant: drain `stream` to the consumer, fold elements\n * into an accumulator, and at end-of-stream emit one `next(build(finalAcc))`.\n *\n * Subsumes `nextAfter` when state is constant (`reduce: (s, _) => s`,\n * `build: (s) => s`). Used by `Toolkit.continueWith` to collect tool\n * results and build next state without exposing a Ref to recipes.\n */\nexport const nextAfterFold = <A, B, S, E, R>(\n stream: Stream.Stream<A, E, R>,\n initial: B,\n reduce: (acc: B, a: A) => B,\n build: (b: B) => S,\n): Stream.Stream<Event<A, S>, E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const ref = yield* Ref.make(initial)\n const tapped = stream.pipe(\n Stream.tap((a) => Ref.update(ref, (acc) => reduce(acc, a))),\n Stream.map(value),\n )\n const continuation = Stream.fromEffect(\n Ref.get(ref).pipe(Effect.map((acc) => next(build(acc)))),\n )\n return tapped.pipe(Stream.concat(continuation))\n }),\n )\n\n// ---------------------------------------------------------------------------\n// onTurnComplete - turn-aware stream operator for loop bodies\n// ---------------------------------------------------------------------------\n\n/**\n * Lift a provider's `Stream<TurnEvent>` into a loop body's `Stream<Event<TurnEvent | A, S>>`.\n * Each delta passes through as `value(delta)` (including the terminal\n * `turn_complete`, so the consumer sees turn boundaries naturally). Once\n * the terminal arrives, `then(turn)` runs and its returned stream of loop\n * events (typically tool outputs followed by `next(state)` or `stop`) is\n * concatenated.\n *\n * Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on\n * the raw delta stream cover anything an `emit`-style callback would do.\n *\n * If the upstream ends without a `turn_complete`, the resulting stream\n * fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if\n * you want to recover.\n */\nexport const onTurnComplete =\n <S, A, E2 = never, R2 = never>(\n then: (turn: Turn) => Effect.Effect<Stream.Stream<Event<A, S>, E2, R2>, E2, R2>,\n ) =>\n <E, R>(\n deltas: Stream.Stream<TurnEvent, E, R>,\n ): Stream.Stream<Event<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turnRef = yield* Ref.make<Option.Option<Turn>>(Option.none())\n\n const events: Stream.Stream<Event<TurnEvent, S>, E, R> = deltas.pipe(\n Stream.tap((delta) =>\n isTurnComplete(delta) ? Ref.set(turnRef, Option.some(delta.turn)) : Effect.void,\n ),\n Stream.map(value),\n )\n\n const continuation = Stream.unwrap(\n Effect.gen(function* () {\n const opt = yield* Ref.get(turnRef)\n if (Option.isNone(opt)) return yield* Effect.fail(new IncompleteTurn({}))\n return yield* then(opt.value)\n }),\n )\n\n return Stream.concat(events, continuation)\n }),\n )\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst isNonEmpty = <A>(array: ReadonlyArray<A>): array is readonly [A, ...Array<A>] =>\n array.length > 0\n\ntype CurrentBody<S, A, E, R> = {\n readonly scope: Scope.Closeable\n readonly pull: Effect.Effect<ReadonlyArray<Event<A, S>>, E | Cause.Done<void>, R>\n}\n\nconst closeBody = <S, A, E, R>(\n current: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n) => Scope.close(current.scope, exit)\n\n/**\n * Walk a chunk of `Event<A, S>` until a terminal `Next` or `Stop` is found.\n * Returns the unwrapped values seen so far and (optionally) the terminal\n * event. Anything in the chunk after the terminal is discarded - its\n * producing side effects may have run, but downstream never sees it.\n */\nconst partitionChunk = <A, S>(\n chunk: ReadonlyArray<Event<A, S>>,\n): { readonly values: Array<A>; readonly decision: Event<A, S> | undefined } => {\n const values: Array<A> = []\n for (let i = 0; i < chunk.length; i++) {\n const event = chunk[i]!\n if (event._tag === \"Value\") {\n values.push(event.value)\n } else {\n return { values, decision: event }\n }\n }\n return { values, decision: undefined }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\ntype LoopBody<S, A, E, R> = (\n state: S,\n) => Stream.Stream<Event<A, S>, E, R> | Effect.Effect<Stream.Stream<Event<A, S>, E, R>, E, R>\n\n/**\n * Drive a state-threaded loop body. Each iteration runs `body(state)` to get\n * a `Stream<Event<A, S>>`; values flow downstream, `next(s)` continues with\n * a new state, `stop` ends the loop. See the file header for the full\n * pull-based execution model.\n *\n * Dual: data-first `loop(initial, body)` and data-last `loop(body)(initial)`\n * (or `pipe(initial, loop(body))`) both work.\n */\nexport const loop: {\n <S, A, E, R>(body: LoopBody<S, A, E, R>): (initial: S) => Stream.Stream<A, E, R>\n <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R>\n} = Function.dual(\n 2,\n <S, A, E, R>(initial: S, body: LoopBody<S, A, E, R>): Stream.Stream<A, E, R> =>\n Stream.scoped(\n Stream.fromPull(\n Effect.gen(function* () {\n const outerScope = yield* Effect.scope\n let state = initial\n let current: CurrentBody<S, A, E, R> | undefined\n let done = false\n\n const closeActive = (\n active: CurrentBody<S, A, E, R>,\n exit: Exit.Exit<unknown, unknown>,\n ) => {\n const isActive = current === active\n if (isActive) current = undefined\n // Scope.close is idempotent. Multiple paths can race to close the\n // active body during cancellation/failure, so closing twice is safe.\n return closeBody(active, exit)\n }\n\n yield* Scope.addFinalizerExit(outerScope, (exit) =>\n current === undefined ? Effect.void : closeActive(current, exit),\n )\n\n const pull = Effect.gen(function* () {\n while (true) {\n if (done) return yield* Cause.done()\n\n if (current === undefined) {\n const result = body(state)\n const stream = Effect.isEffect(result) ? Stream.unwrap(result) : result\n const bodyScope = yield* Scope.fork(outerScope)\n const bodyPull = yield* Channel.toPullScoped(\n Stream.toChannel(stream),\n bodyScope,\n ).pipe(Effect.onError((cause) => Scope.close(bodyScope, Exit.failCause(cause))))\n current = { scope: bodyScope, pull: bodyPull }\n }\n\n const active = current\n const chunk = yield* active.pull.pipe(\n Effect.catchIf(Cause.isDone, () =>\n closeActive(active, Exit.void).pipe(\n Effect.as(undefined as ReadonlyArray<Event<A, S>> | undefined),\n ),\n ),\n Effect.onError((cause) => closeActive(active, Exit.failCause(cause))),\n )\n\n if (chunk === undefined) {\n done = true\n return yield* Cause.done()\n }\n\n const { values, decision } = partitionChunk(chunk)\n\n if (decision !== undefined) {\n yield* closeActive(active, Exit.void)\n if (decision._tag === \"Stop\") {\n done = true\n } else if (decision._tag === \"Next\") {\n state = decision.state\n }\n }\n\n // Emit the values seen so far if any. Chunks from a Stream pull\n // are non-empty, so when `decision === undefined` every event was\n // a `Value` and `values` is non-empty here. With a decision and\n // no preceding values, fall through to the next iteration.\n if (isNonEmpty(values)) return values\n }\n })\n\n return pull\n }),\n ),\n ),\n)\n\n// ---------------------------------------------------------------------------\n// loopWithState - same body protocol, plus a live state observable.\n// ---------------------------------------------------------------------------\n\n/**\n * Like `loop`, but exposes the current loop state as a `SubscriptionRef`\n * alongside the value stream.\n *\n * Allocates one `SubscriptionRef<S>` seeded with `initial`, then runs the\n * loop with a wrapped body that taps every `Next(s)` event into the ref\n * before forwarding it. The caller decides how to consume both channels:\n *\n * - **Final state**: drain the stream, then `SubscriptionRef.get(state)`\n * - the ref holds the state from the last `Next` (or `initial` if the\n * loop ended without advancing).\n * - **Live transitions**: `SubscriptionRef.changes(state)` is a\n * `Stream<S>` of every state observed; subscribe alongside the value\n * stream.\n * - **Mid-iteration peek**: `SubscriptionRef.get(state)` at any time.\n *\n * The returned stream and ref are independent of each other - the ref\n * lives outside the stream's scope, so reading it after the stream\n * completes is safe.\n */\nexport const loopWithState = <S, A, E, R>(\n initial: S,\n body: LoopBody<S, A, E, R>,\n): Effect.Effect<{\n readonly stream: Stream.Stream<A, E, R>\n readonly state: SubscriptionRef.SubscriptionRef<S>\n}> =>\n Effect.gen(function* () {\n const stateRef = yield* SubscriptionRef.make(initial)\n\n const tap = (stream: Stream.Stream<Event<A, S>, E, R>): Stream.Stream<Event<A, S>, E, R> =>\n stream.pipe(\n Stream.tap((event) =>\n event._tag === \"Next\" ? SubscriptionRef.set(stateRef, event.state) : Effect.void,\n ),\n )\n\n const wrappedBody: LoopBody<S, A, E, R> = (s) => {\n const result = body(s)\n return Effect.isEffect(result) ? Effect.map(result, tap) : tap(result)\n }\n\n return {\n stream: loop(initial, wrappedBody),\n state: stateRef,\n }\n })\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|