@effect-uai/core 0.7.0 → 0.9.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/dist/{AiError-CAX_48RU.d.mts → AiError-CrdR1EQi.d.mts} +2 -2
- package/dist/{AiError-CAX_48RU.d.mts.map → AiError-CrdR1EQi.d.mts.map} +1 -1
- package/dist/{Audio-DPlTsNdz.d.mts → Audio-DDSKCkSe.d.mts} +2 -2
- package/dist/{Audio-DPlTsNdz.d.mts.map → Audio-DDSKCkSe.d.mts.map} +1 -1
- package/dist/{Image-HNmMpMTh.d.mts → Image-C_Zjpwhc.d.mts} +2 -2
- package/dist/{Image-HNmMpMTh.d.mts.map → Image-C_Zjpwhc.d.mts.map} +1 -1
- package/dist/{Items-D8UaXQx_.d.mts → Items-CgKD6Npw.d.mts} +5 -5
- package/dist/{Items-D8UaXQx_.d.mts.map → Items-CgKD6Npw.d.mts.map} +1 -1
- package/dist/Loop-B5_cqumi.d.mts +173 -0
- package/dist/Loop-B5_cqumi.d.mts.map +1 -0
- package/dist/{Media-D_CpcM1Z.d.mts → Media-DOLyaygI.d.mts} +1 -1
- package/dist/{Media-D_CpcM1Z.d.mts.map → Media-DOLyaygI.d.mts.map} +1 -1
- package/dist/{SandboxError-BvKypkJm.d.mts → SandboxError-CIrVDOMV.d.mts} +2 -2
- package/dist/{SandboxError-BvKypkJm.d.mts.map → SandboxError-CIrVDOMV.d.mts.map} +1 -1
- package/dist/{StructuredFormat-BbN4dosH.d.mts → StructuredFormat-CMJFD3sn.d.mts} +2 -2
- package/dist/{StructuredFormat-BbN4dosH.d.mts.map → StructuredFormat-CMJFD3sn.d.mts.map} +1 -1
- package/dist/Tool-0XUIT2A2.d.mts +232 -0
- package/dist/Tool-0XUIT2A2.d.mts.map +1 -0
- package/dist/ToolEvent-DYrAUJGs.d.mts +151 -0
- package/dist/ToolEvent-DYrAUJGs.d.mts.map +1 -0
- package/dist/ToolResult-BZd-cEWW.d.mts +151 -0
- package/dist/ToolResult-BZd-cEWW.d.mts.map +1 -0
- package/dist/Toolkit-BKC8b8Xo.d.mts +155 -0
- package/dist/Toolkit-BKC8b8Xo.d.mts.map +1 -0
- package/dist/{dist-DV5ISja1.mjs → dist-B04dlFHg.mjs} +3 -3
- package/dist/{dist-DV5ISja1.mjs.map → dist-B04dlFHg.mjs.map} +1 -1
- package/dist/dist-DWgRbDN3.mjs +140 -0
- package/dist/dist-DWgRbDN3.mjs.map +1 -0
- package/dist/domain/AiError.d.mts +1 -1
- package/dist/domain/Audio.d.mts +1 -1
- package/dist/domain/Image.d.mts +1 -1
- package/dist/domain/Items.d.mts +1 -1
- package/dist/domain/Media.d.mts +1 -1
- package/dist/domain/Music.d.mts +1 -1
- package/dist/domain/Turn.d.mts +4 -4
- package/dist/domain/Turn.test.mjs +1 -1
- package/dist/embedding-model/Embedding.d.mts +1 -1
- package/dist/embedding-model/EmbeddingModel.d.mts +1 -1
- package/dist/embedding-model/EmbeddingModel.test.mjs +1 -1
- package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
- package/dist/index.d.mts +16 -13
- package/dist/index.mjs +5 -2
- package/dist/language-model/LanguageModel.d.mts +10 -5
- package/dist/language-model/LanguageModel.d.mts.map +1 -1
- package/dist/language-model/LanguageModel.mjs.map +1 -1
- package/dist/language-model/LanguageModel.test.mjs +1 -1
- package/dist/loop/Loop.d.mts +2 -141
- package/dist/loop/Loop.mjs +16 -20
- package/dist/loop/Loop.mjs.map +1 -1
- package/dist/loop/Loop.test.mjs +18 -1
- package/dist/loop/Loop.test.mjs.map +1 -1
- package/dist/{magic-string.es-BgIV5Mu3.mjs → magic-string.es-Dk-MMA0F.mjs} +1 -1
- package/dist/{magic-string.es-BgIV5Mu3.mjs.map → magic-string.es-Dk-MMA0F.mjs.map} +1 -1
- package/dist/music-generator/MusicGenerator.d.mts +2 -2
- package/dist/music-generator/MusicGenerator.test.mjs +1 -1
- package/dist/observability/Metrics.d.mts +116 -28
- package/dist/observability/Metrics.d.mts.map +1 -1
- package/dist/observability/Metrics.mjs +250 -38
- package/dist/observability/Metrics.mjs.map +1 -1
- package/dist/observability/Metrics.test.d.mts +1 -0
- package/dist/observability/Metrics.test.mjs +187 -0
- package/dist/observability/Metrics.test.mjs.map +1 -0
- package/dist/observability/Telemetry.d.mts +37 -0
- package/dist/observability/Telemetry.d.mts.map +1 -0
- package/dist/observability/Telemetry.mjs +57 -0
- package/dist/observability/Telemetry.mjs.map +1 -0
- package/dist/observability/Telemetry.test.d.mts +1 -0
- package/dist/observability/Telemetry.test.mjs +92 -0
- package/dist/observability/Telemetry.test.mjs.map +1 -0
- package/dist/retry/Retry.d.mts +2 -2
- package/dist/retry/Retry.test.mjs +1 -1
- package/dist/sandbox/Sandbox.d.mts +1 -1
- package/dist/sandbox/SandboxError.d.mts +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +2 -2
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +1 -1
- package/dist/streaming/JSONL.d.mts +1 -1
- package/dist/streaming/JSONL.test.mjs +1 -1
- package/dist/streaming/SSE.test.mjs +1 -1
- package/dist/structured-format/StructuredFormat.d.mts +1 -1
- package/dist/structured-format/StructuredFormat.mjs.map +1 -1
- package/dist/structured-format/StructuredFormat.test.mjs +1 -1
- package/dist/testing/MockMusicGenerator.d.mts +1 -1
- package/dist/testing/MockProvider.d.mts +1 -1
- package/dist/testing/MockSpeechSynthesizer.d.mts +1 -1
- package/dist/tool/Approval.d.mts +3 -3
- package/dist/tool/Approval.test.mjs +35 -34
- package/dist/tool/Approval.test.mjs.map +1 -1
- package/dist/tool/HistoryCheck.d.mts +2 -2
- package/dist/tool/Tool.d.mts +2 -2
- package/dist/tool/Tool.mjs +112 -22
- package/dist/tool/Tool.mjs.map +1 -1
- package/dist/tool/Tool.test.mjs +41 -3
- package/dist/tool/Tool.test.mjs.map +1 -1
- package/dist/tool/ToolEvent.d.mts +2 -151
- package/dist/tool/ToolResult.d.mts +2 -138
- package/dist/tool/ToolResult.mjs +18 -3
- package/dist/tool/ToolResult.mjs.map +1 -1
- package/dist/tool/Toolkit.d.mts +2 -73
- package/dist/tool/Toolkit.mjs +106 -28
- package/dist/tool/Toolkit.mjs.map +1 -1
- package/dist/tool/Toolkit.test.mjs +113 -7
- package/dist/tool/Toolkit.test.mjs.map +1 -1
- package/dist/transcriber/Transcriber.d.mts +2 -2
- package/dist/transcriber/Transcriber.test.mjs +1 -1
- package/dist/web-search/WebSearch.d.mts +119 -0
- package/dist/web-search/WebSearch.d.mts.map +1 -0
- package/dist/web-search/WebSearch.mjs +42 -0
- package/dist/web-search/WebSearch.mjs.map +1 -0
- package/dist/web-search/WebSearchTool.d.mts +58 -0
- package/dist/web-search/WebSearchTool.d.mts.map +1 -0
- package/dist/web-search/WebSearchTool.mjs +69 -0
- package/dist/web-search/WebSearchTool.mjs.map +1 -0
- package/package.json +9 -1
- package/src/embedding-model/EmbeddingModel.test.ts +4 -0
- package/src/index.ts +3 -0
- package/src/language-model/LanguageModel.ts +7 -2
- package/src/loop/Loop.test.ts +22 -0
- package/src/loop/Loop.ts +27 -4
- package/src/observability/Metrics.test.ts +266 -0
- package/src/observability/Metrics.ts +505 -65
- package/src/observability/Telemetry.test.ts +123 -0
- package/src/observability/Telemetry.ts +96 -0
- package/src/structured-format/StructuredFormat.ts +4 -0
- package/src/tool/Approval.test.ts +22 -21
- package/src/tool/Tool.test.ts +55 -2
- package/src/tool/Tool.ts +221 -55
- package/src/tool/ToolResult.ts +22 -1
- package/src/tool/Toolkit.test.ts +168 -7
- package/src/tool/Toolkit.ts +336 -99
- package/src/web-search/WebSearch.ts +150 -0
- package/src/web-search/WebSearchTool.ts +106 -0
- package/dist/Tool-CiFXYjmR.d.mts +0 -102
- package/dist/Tool-CiFXYjmR.d.mts.map +0 -1
- package/dist/loop/Loop.d.mts.map +0 -1
- package/dist/tool/ToolEvent.d.mts.map +0 -1
- package/dist/tool/ToolResult.d.mts.map +0 -1
- package/dist/tool/Toolkit.d.mts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
2
|
-
import { a as AudioSource, r as AudioFormat } from "../Audio-
|
|
1
|
+
import { t as AiError } from "../AiError-CrdR1EQi.mjs";
|
|
2
|
+
import { a as AudioSource, r as AudioFormat } from "../Audio-DDSKCkSe.mjs";
|
|
3
3
|
import { TranscriptEvent, TranscriptResult } from "../domain/Transcript.mjs";
|
|
4
4
|
import { Context, Effect, Stream } from "effect";
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { streamTranscriptionFrom, transcribe } from "./Transcriber.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as describe, n as globalExpect, o as it, t as import_dist } from "../dist-B04dlFHg.mjs";
|
|
3
3
|
import { layer, layerSyncOnly } from "../testing/MockTranscriber.mjs";
|
|
4
4
|
import { Duration, Effect, Stream } from "effect";
|
|
5
5
|
//#region src/transcriber/Transcriber.test.ts
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { t as AiError } from "../AiError-CrdR1EQi.mjs";
|
|
2
|
+
import { Context, DateTime, Effect, Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/web-search/WebSearch.d.ts
|
|
5
|
+
declare namespace WebSearch_d_exports {
|
|
6
|
+
export { CommonSearchRequest, SearchRecency, SearchResponse, SearchResult, WebSearch, WebSearchService, search };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Convenience freshness enum shared by every provider. A coarse "published
|
|
10
|
+
* within the last …" filter that maps onto each provider's native recency
|
|
11
|
+
* knob (Perplexity `search_recency_filter`, Brave `freshness`, Tavily
|
|
12
|
+
* `time_range`, You.com `freshness`), or onto a computed published-date
|
|
13
|
+
* range where a provider has no enum (Exa).
|
|
14
|
+
*
|
|
15
|
+
* For a precise window use {@link CommonSearchRequest.startDate} /
|
|
16
|
+
* {@link CommonSearchRequest.endDate} instead; `recency` is the sugar for
|
|
17
|
+
* the common "past week / past month" case.
|
|
18
|
+
*
|
|
19
|
+
* Exposed as a `Schema` so {@link "../web-search/WebSearchTool".webSearchTool}
|
|
20
|
+
* can hand it straight to a model as a tool parameter; the
|
|
21
|
+
* {@link SearchRecency} type is derived from it.
|
|
22
|
+
*/
|
|
23
|
+
declare const SearchRecency: Schema.Literals<readonly ["hour", "day", "week", "month", "year"]>;
|
|
24
|
+
type SearchRecency = typeof SearchRecency.Type;
|
|
25
|
+
/**
|
|
26
|
+
* Cross-provider web-search request. A field earns a place here only if
|
|
27
|
+
* most of the supported providers honor it and a developer would expect it
|
|
28
|
+
* from a generic search interface; everything provider-specific (Exa
|
|
29
|
+
* `type`, Tavily `searchDepth`, Brave `goggles`, pagination `offset`,
|
|
30
|
+
* `safeSearch`, `topic`, …) lives on that provider's typed request.
|
|
31
|
+
*
|
|
32
|
+
* Note the one structural difference from `EmbeddingModel` /
|
|
33
|
+
* `Transcriber`: there is no `model`. None of the pure-`/search` endpoints
|
|
34
|
+
* take one - what looks model-shaped on a provider (Exa `type`, Tavily
|
|
35
|
+
* `searchDepth`) is a mode knob, so it stays on the provider-typed request.
|
|
36
|
+
*/
|
|
37
|
+
type CommonSearchRequest = {
|
|
38
|
+
/** The search query. The one field every provider requires. */readonly query: string;
|
|
39
|
+
/**
|
|
40
|
+
* Upper bound on the number of results to return in this one call.
|
|
41
|
+
* Providers cap differently (Perplexity / Tavily / Brave at ~20, Exa /
|
|
42
|
+
* You.com at ~100); a value above a provider's cap is clamped by that
|
|
43
|
+
* provider. There is no common pagination - only two providers paginate
|
|
44
|
+
* and only shallowly, so `offset` is provider-typed.
|
|
45
|
+
*/
|
|
46
|
+
readonly maxResults?: number; /** Restrict results to these domains (e.g. `["docs.foo.com"]`). */
|
|
47
|
+
readonly includeDomains?: ReadonlyArray<string>; /** Drop results from these domains. */
|
|
48
|
+
readonly excludeDomains?: ReadonlyArray<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Coarse freshness filter - see {@link SearchRecency}. Sugar over an
|
|
51
|
+
* explicit `startDate`; ignored where {@link startDate} is also set and
|
|
52
|
+
* the provider takes only one.
|
|
53
|
+
*/
|
|
54
|
+
readonly recency?: SearchRecency; /** Published-after bound. The precise alternative to {@link recency}. */
|
|
55
|
+
readonly startDate?: DateTime.DateTime; /** Published-before bound. */
|
|
56
|
+
readonly endDate?: DateTime.DateTime; /** ISO 3166-1 alpha-2 country code to localize results (e.g. `"us"`). */
|
|
57
|
+
readonly country?: string; /** ISO 639-1 language code to bias results toward (e.g. `"en"`). */
|
|
58
|
+
readonly language?: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* One normalized web-search hit. A flat record with optionals rather than a
|
|
62
|
+
* tagged union: the providers differ by *which fields are present*, not by
|
|
63
|
+
* *kind*. The provider's untouched result object is always on `raw`, so a
|
|
64
|
+
* caller holding a typed provider tag can recover anything not promoted
|
|
65
|
+
* here (`author`, `favicon`, multi-chunk `snippets[]`, …).
|
|
66
|
+
*/
|
|
67
|
+
type SearchResult = {
|
|
68
|
+
/** Canonical result URL. Always present. */readonly url: string; /** Result title / headline, when the provider returns one. */
|
|
69
|
+
readonly title?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Primary short excerpt - the one text field all providers return (under
|
|
72
|
+
* various wire names: `snippet`, `content`, `description`). The richer
|
|
73
|
+
* extract fields (`text`, `highlights`, `summary`) belong to the
|
|
74
|
+
* out-of-scope extract feature and stay on the provider-typed result.
|
|
75
|
+
*/
|
|
76
|
+
readonly snippet?: string; /** Publication date, when the provider reports one. */
|
|
77
|
+
readonly publishedDate?: DateTime.DateTime;
|
|
78
|
+
/**
|
|
79
|
+
* Relevance score, only from providers that rank (Exa, Tavily);
|
|
80
|
+
* `undefined` for providers that return an unscored list. Kept despite
|
|
81
|
+
* being non-universal because ranking is core to what a "search result"
|
|
82
|
+
* means - and `undefined` cleanly says "this backend doesn't score."
|
|
83
|
+
*/
|
|
84
|
+
readonly score?: number; /** The provider-native result object, never lossy. */
|
|
85
|
+
readonly raw: unknown;
|
|
86
|
+
};
|
|
87
|
+
type SearchResponse = {
|
|
88
|
+
readonly results: ReadonlyArray<SearchResult>;
|
|
89
|
+
/**
|
|
90
|
+
* The provider-native top-level response object. Cost / usage reporting
|
|
91
|
+
* is deliberately not modeled on this surface yet: providers disagree on
|
|
92
|
+
* both what (Exa returns USD, Tavily credits, Brave nothing in-body) and
|
|
93
|
+
* where (Brave reports cost in response headers), so it is deferred to the
|
|
94
|
+
* unified usage design (see plans/usage-tracking.md). Anything a provider
|
|
95
|
+
* reports survives here on `raw`.
|
|
96
|
+
*/
|
|
97
|
+
readonly raw: unknown;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* The portable web-search surface: one operation, `search`. Pure search is
|
|
101
|
+
* the one thing every provider does, so - unlike `SpeechSynthesizer` /
|
|
102
|
+
* `Transcriber` - this capability needs no marker tags; every provider
|
|
103
|
+
* Layer can answer.
|
|
104
|
+
*/
|
|
105
|
+
type WebSearchService = {
|
|
106
|
+
readonly search: (request: CommonSearchRequest) => Effect.Effect<SearchResponse, AiError>;
|
|
107
|
+
};
|
|
108
|
+
declare const WebSearch_base: Context.ServiceClass<WebSearch, "@betalyra/effect-uai/WebSearch", WebSearchService>;
|
|
109
|
+
/**
|
|
110
|
+
* Generic web-search service tag. Yield this for provider-portable code;
|
|
111
|
+
* yield a provider tag (`PerplexitySearch`, `ExaSearch`, …) when you need
|
|
112
|
+
* that provider's own knobs. A provider's `layer` registers both.
|
|
113
|
+
*/
|
|
114
|
+
declare class WebSearch extends WebSearch_base {}
|
|
115
|
+
/** Run one web search against whichever provider Layer is in scope. */
|
|
116
|
+
declare const search: (request: CommonSearchRequest) => Effect.Effect<SearchResponse, AiError, WebSearch>;
|
|
117
|
+
//#endregion
|
|
118
|
+
export { CommonSearchRequest, SearchRecency, SearchResponse, SearchResult, WebSearch, WebSearchService, search, WebSearch_d_exports as t };
|
|
119
|
+
//# sourceMappingURL=WebSearch.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSearch.d.mts","names":[],"sources":["../../src/web-search/WebSearch.ts"],"mappings":";;;;;;;;;;;;;;;;;;;AAsBA;;;cAAa,aAAA,EAAa,MAAA,CAAA,QAAA;AAAA,KAEd,aAAA,UAAuB,aAAA,CAAc,IAAA;AAAjD;;;;;AAkBA;;;;;;;AAlBA,KAkBY,mBAAA;EAwB0B,wEAtB3B,KAAA;EAAA;;;;;;;EAAA,SAQA,UAAA,WAYA;EAAA,SAVA,cAAA,GAAiB,aAAA,UAUI;EAAA,SARrB,cAAA,GAAiB,aAAA;EAUP;;;;;EAAA,SAJV,OAAA,GAAU,aAAA,EAsBT;EAAA,SApBD,SAAA,GAAY,QAAA,CAAS,QAAA;WAErB,OAAA,GAAU,QAAA,CAAS,QAAA,EAoBnB;EAAA,SAlBA,OAAA,WA2BA;EAAA,SAzBA,QAAA;AAAA;;;;;;AAuCX;;KAzBY,YAAA;EA0BqB,qDAxBtB,GAAA,UAwBS;EAAA,SAtBT,KAAA;EA+BA;;;AAaX;;;EAbW,SAxBA,OAAA,WAsCwD;EAAA,SApCxD,aAAA,GAAgB,QAAA,CAAS,QAAA;EAoCiB;;;;;;EAAA,SA7B1C,KAAA,WA6BiD;EAAA,SA3BjD,GAAA;AAAA;AAAA,KAGC,cAAA;EAAA,SACD,OAAA,EAAS,aAAA,CAAc,YAAA;EAuBgE;AACjG;;;;;;;EADiG,SAdvF,GAAA;AAAA;;;;;;AAsBX;KATY,gBAAA;EAAA,SACD,MAAA,GAAS,OAAA,EAAS,mBAAA,KAAwB,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB,OAAA;AAAA;AAAA,cAClF,cAAA;AAYD;;;;;AAAA,cALa,SAAA,SAAkB,cAAA;;cAKlB,MAAA,GACX,OAAA,EAAS,mBAAA,KACR,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB,OAAA,EAAiB,SAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
2
|
+
import { Context, Effect, Schema } from "effect";
|
|
3
|
+
//#region src/web-search/WebSearch.ts
|
|
4
|
+
var WebSearch_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
SearchRecency: () => SearchRecency,
|
|
6
|
+
WebSearch: () => WebSearch,
|
|
7
|
+
search: () => search
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Convenience freshness enum shared by every provider. A coarse "published
|
|
11
|
+
* within the last …" filter that maps onto each provider's native recency
|
|
12
|
+
* knob (Perplexity `search_recency_filter`, Brave `freshness`, Tavily
|
|
13
|
+
* `time_range`, You.com `freshness`), or onto a computed published-date
|
|
14
|
+
* range where a provider has no enum (Exa).
|
|
15
|
+
*
|
|
16
|
+
* For a precise window use {@link CommonSearchRequest.startDate} /
|
|
17
|
+
* {@link CommonSearchRequest.endDate} instead; `recency` is the sugar for
|
|
18
|
+
* the common "past week / past month" case.
|
|
19
|
+
*
|
|
20
|
+
* Exposed as a `Schema` so {@link "../web-search/WebSearchTool".webSearchTool}
|
|
21
|
+
* can hand it straight to a model as a tool parameter; the
|
|
22
|
+
* {@link SearchRecency} type is derived from it.
|
|
23
|
+
*/
|
|
24
|
+
const SearchRecency = Schema.Literals([
|
|
25
|
+
"hour",
|
|
26
|
+
"day",
|
|
27
|
+
"week",
|
|
28
|
+
"month",
|
|
29
|
+
"year"
|
|
30
|
+
]);
|
|
31
|
+
/**
|
|
32
|
+
* Generic web-search service tag. Yield this for provider-portable code;
|
|
33
|
+
* yield a provider tag (`PerplexitySearch`, `ExaSearch`, …) when you need
|
|
34
|
+
* that provider's own knobs. A provider's `layer` registers both.
|
|
35
|
+
*/
|
|
36
|
+
var WebSearch = class extends Context.Service()("@betalyra/effect-uai/WebSearch") {};
|
|
37
|
+
/** Run one web search against whichever provider Layer is in scope. */
|
|
38
|
+
const search = (request) => Effect.flatMap(WebSearch.asEffect(), (s) => s.search(request));
|
|
39
|
+
//#endregion
|
|
40
|
+
export { SearchRecency, WebSearch, search, WebSearch_exports as t };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=WebSearch.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSearch.mjs","names":[],"sources":["../../src/web-search/WebSearch.ts"],"sourcesContent":["import { Context, type DateTime, Effect, Schema } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\n\n// ---------------------------------------------------------------------------\n// Recency\n// ---------------------------------------------------------------------------\n\n/**\n * Convenience freshness enum shared by every provider. A coarse \"published\n * within the last …\" filter that maps onto each provider's native recency\n * knob (Perplexity `search_recency_filter`, Brave `freshness`, Tavily\n * `time_range`, You.com `freshness`), or onto a computed published-date\n * range where a provider has no enum (Exa).\n *\n * For a precise window use {@link CommonSearchRequest.startDate} /\n * {@link CommonSearchRequest.endDate} instead; `recency` is the sugar for\n * the common \"past week / past month\" case.\n *\n * Exposed as a `Schema` so {@link \"../web-search/WebSearchTool\".webSearchTool}\n * can hand it straight to a model as a tool parameter; the\n * {@link SearchRecency} type is derived from it.\n */\nexport const SearchRecency = Schema.Literals([\"hour\", \"day\", \"week\", \"month\", \"year\"])\n\nexport type SearchRecency = typeof SearchRecency.Type\n\n// ---------------------------------------------------------------------------\n// Request\n// ---------------------------------------------------------------------------\n\n/**\n * Cross-provider web-search request. A field earns a place here only if\n * most of the supported providers honor it and a developer would expect it\n * from a generic search interface; everything provider-specific (Exa\n * `type`, Tavily `searchDepth`, Brave `goggles`, pagination `offset`,\n * `safeSearch`, `topic`, …) lives on that provider's typed request.\n *\n * Note the one structural difference from `EmbeddingModel` /\n * `Transcriber`: there is no `model`. None of the pure-`/search` endpoints\n * take one - what looks model-shaped on a provider (Exa `type`, Tavily\n * `searchDepth`) is a mode knob, so it stays on the provider-typed request.\n */\nexport type CommonSearchRequest = {\n /** The search query. The one field every provider requires. */\n readonly query: string\n /**\n * Upper bound on the number of results to return in this one call.\n * Providers cap differently (Perplexity / Tavily / Brave at ~20, Exa /\n * You.com at ~100); a value above a provider's cap is clamped by that\n * provider. There is no common pagination - only two providers paginate\n * and only shallowly, so `offset` is provider-typed.\n */\n readonly maxResults?: number\n /** Restrict results to these domains (e.g. `[\"docs.foo.com\"]`). */\n readonly includeDomains?: ReadonlyArray<string>\n /** Drop results from these domains. */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Coarse freshness filter - see {@link SearchRecency}. Sugar over an\n * explicit `startDate`; ignored where {@link startDate} is also set and\n * the provider takes only one.\n */\n readonly recency?: SearchRecency\n /** Published-after bound. The precise alternative to {@link recency}. */\n readonly startDate?: DateTime.DateTime\n /** Published-before bound. */\n readonly endDate?: DateTime.DateTime\n /** ISO 3166-1 alpha-2 country code to localize results (e.g. `\"us\"`). */\n readonly country?: string\n /** ISO 639-1 language code to bias results toward (e.g. `\"en\"`). */\n readonly language?: string\n}\n\n// ---------------------------------------------------------------------------\n// Response\n// ---------------------------------------------------------------------------\n\n/**\n * One normalized web-search hit. A flat record with optionals rather than a\n * tagged union: the providers differ by *which fields are present*, not by\n * *kind*. The provider's untouched result object is always on `raw`, so a\n * caller holding a typed provider tag can recover anything not promoted\n * here (`author`, `favicon`, multi-chunk `snippets[]`, …).\n */\nexport type SearchResult = {\n /** Canonical result URL. Always present. */\n readonly url: string\n /** Result title / headline, when the provider returns one. */\n readonly title?: string\n /**\n * Primary short excerpt - the one text field all providers return (under\n * various wire names: `snippet`, `content`, `description`). The richer\n * extract fields (`text`, `highlights`, `summary`) belong to the\n * out-of-scope extract feature and stay on the provider-typed result.\n */\n readonly snippet?: string\n /** Publication date, when the provider reports one. */\n readonly publishedDate?: DateTime.DateTime\n /**\n * Relevance score, only from providers that rank (Exa, Tavily);\n * `undefined` for providers that return an unscored list. Kept despite\n * being non-universal because ranking is core to what a \"search result\"\n * means - and `undefined` cleanly says \"this backend doesn't score.\"\n */\n readonly score?: number\n /** The provider-native result object, never lossy. */\n readonly raw: unknown\n}\n\nexport type SearchResponse = {\n readonly results: ReadonlyArray<SearchResult>\n /**\n * The provider-native top-level response object. Cost / usage reporting\n * is deliberately not modeled on this surface yet: providers disagree on\n * both what (Exa returns USD, Tavily credits, Brave nothing in-body) and\n * where (Brave reports cost in response headers), so it is deferred to the\n * unified usage design (see plans/usage-tracking.md). Anything a provider\n * reports survives here on `raw`.\n */\n readonly raw: unknown\n}\n\n// ---------------------------------------------------------------------------\n// Service + helper\n// ---------------------------------------------------------------------------\n\n/**\n * The portable web-search surface: one operation, `search`. Pure search is\n * the one thing every provider does, so - unlike `SpeechSynthesizer` /\n * `Transcriber` - this capability needs no marker tags; every provider\n * Layer can answer.\n */\nexport type WebSearchService = {\n readonly search: (request: CommonSearchRequest) => Effect.Effect<SearchResponse, AiError.AiError>\n}\n\n/**\n * Generic web-search service tag. Yield this for provider-portable code;\n * yield a provider tag (`PerplexitySearch`, `ExaSearch`, …) when you need\n * that provider's own knobs. A provider's `layer` registers both.\n */\nexport class WebSearch extends Context.Service<WebSearch, WebSearchService>()(\n \"@betalyra/effect-uai/WebSearch\",\n) {}\n\n/** Run one web search against whichever provider Layer is in scope. */\nexport const search = (\n request: CommonSearchRequest,\n): Effect.Effect<SearchResponse, AiError.AiError, WebSearch> =>\n Effect.flatMap(WebSearch.asEffect(), (s) => s.search(request))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,gBAAgB,OAAO,SAAS;CAAC;CAAQ;CAAO;CAAQ;CAAS;CAAO,CAAC;;;;;;AAuHtF,IAAa,YAAb,cAA+B,QAAQ,SAAsC,CAC3E,iCACD,CAAC;;AAGF,MAAa,UACX,YAEA,OAAO,QAAQ,UAAU,UAAU,GAAG,MAAM,EAAE,OAAO,QAAQ,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { c as Tool } from "../Tool-0XUIT2A2.mjs";
|
|
2
|
+
import { SearchResult, WebSearch } from "./WebSearch.mjs";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/web-search/WebSearchTool.d.ts
|
|
6
|
+
declare namespace WebSearchTool_d_exports {
|
|
7
|
+
export { WebSearchToolArgs, WebSearchToolOptions, webSearchTool };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Model-facing argument schema. Deliberately narrow: `query` plus the one
|
|
11
|
+
* filter that is genuinely the model's call - `recency` (it knows whether a
|
|
12
|
+
* question is about current events or evergreen). App-policy scoping
|
|
13
|
+
* (`includeDomains` / `excludeDomains`) and the `maxResults` cost ceiling
|
|
14
|
+
* are pinned on the constructor instead, so they are guaranteed rather than
|
|
15
|
+
* left to the model to remember each call.
|
|
16
|
+
*/
|
|
17
|
+
declare const WebSearchToolArgs: Schema.Struct<{
|
|
18
|
+
readonly query: Schema.String;
|
|
19
|
+
readonly recency: Schema.optional<Schema.Literals<readonly ["hour", "day", "week", "month", "year"]>>;
|
|
20
|
+
}>;
|
|
21
|
+
type WebSearchToolArgs = typeof WebSearchToolArgs.Type;
|
|
22
|
+
type WebSearchToolOptions = {
|
|
23
|
+
/** Tool name the model sees. Default `"web_search"`. */readonly name?: string;
|
|
24
|
+
/**
|
|
25
|
+
* App-fixed ceiling on results per call - a cost guard, not exposed to
|
|
26
|
+
* the model. Default `5`.
|
|
27
|
+
*/
|
|
28
|
+
readonly maxResults?: number;
|
|
29
|
+
/**
|
|
30
|
+
* App-fixed allowlist applied to every search. A policy scope ("only
|
|
31
|
+
* search our docs"), not a model knob - so it is enforced, not requested.
|
|
32
|
+
*/
|
|
33
|
+
readonly includeDomains?: ReadonlyArray<string>; /** App-fixed denylist applied to every search ("never return X"). */
|
|
34
|
+
readonly excludeDomains?: ReadonlyArray<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Override how results are rendered into the model-facing string.
|
|
37
|
+
* Default: a numbered `title / url / snippet` list.
|
|
38
|
+
*/
|
|
39
|
+
readonly render?: (results: ReadonlyArray<SearchResult>) => string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The canonical web-search tool. Its `R` is just `WebSearch`, so providing
|
|
43
|
+
* any search-provider Layer satisfies it and the model-facing contract
|
|
44
|
+
* (name, description, schema) is identical no matter which backend answers
|
|
45
|
+
* - swap `PerplexitySearch.layer` for `ExaSearch.layer` and the tool the
|
|
46
|
+
* model sees does not change. Drops straight into a `Toolkit` and the
|
|
47
|
+
* `LanguageModel` tool-calling loop.
|
|
48
|
+
*
|
|
49
|
+
* The model controls only `query` and `recency`; domain scoping and the
|
|
50
|
+
* result cap are app policy, fixed here on the constructor. `Output` is
|
|
51
|
+
* rendered text, not raw `SearchResult[]`: the model reads the list, while
|
|
52
|
+
* the app still gets the structured results through the normal tool-result
|
|
53
|
+
* channel. Pass `render` to change the format.
|
|
54
|
+
*/
|
|
55
|
+
declare const webSearchTool: (options?: WebSearchToolOptions) => Tool<string, WebSearchToolArgs, never, string, WebSearch>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { WebSearchToolArgs, WebSearchToolOptions, WebSearchTool_d_exports as t, webSearchTool };
|
|
58
|
+
//# sourceMappingURL=WebSearchTool.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSearchTool.d.mts","names":[],"sources":["../../src/web-search/WebSearchTool.ts"],"mappings":";;;;;;;;;;;;;;;;cAYM,iBAAA,EAAiB,MAAA,CAAA,MAAA;EAAA;;;KAKX,iBAAA,UAA2B,iBAAA,CAAkB,IAAA;AAAA,KAa7C,oBAAA;EAlBW,iEAoBZ,IAAA;EApBY;;;;EAAA,SAyBZ,UAAA;;;;;WAKA,cAAA,GAAiB,aAAA;WAEjB,cAAA,GAAiB,aAAA;;AA3B5B;;;WAgCW,MAAA,IAAU,OAAA,EAAS,aAAA,CAAc,YAAA;AAAA;AAnB5C;;;;;;;;;;;;;;AAAA,cAoCa,aAAA,GACX,OAAA,GAAU,oBAAA,KACT,IAAA,SAAkB,iBAAA,iBAAkC,SAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
2
|
+
import { SearchRecency, search } from "./WebSearch.mjs";
|
|
3
|
+
import { fromEffectSchema, make } from "../tool/Tool.mjs";
|
|
4
|
+
import { Effect, Schema } from "effect";
|
|
5
|
+
//#region src/web-search/WebSearchTool.ts
|
|
6
|
+
var WebSearchTool_exports = /* @__PURE__ */ __exportAll({ webSearchTool: () => webSearchTool });
|
|
7
|
+
/**
|
|
8
|
+
* Model-facing argument schema. Deliberately narrow: `query` plus the one
|
|
9
|
+
* filter that is genuinely the model's call - `recency` (it knows whether a
|
|
10
|
+
* question is about current events or evergreen). App-policy scoping
|
|
11
|
+
* (`includeDomains` / `excludeDomains`) and the `maxResults` cost ceiling
|
|
12
|
+
* are pinned on the constructor instead, so they are guaranteed rather than
|
|
13
|
+
* left to the model to remember each call.
|
|
14
|
+
*/
|
|
15
|
+
const WebSearchToolArgs = Schema.Struct({
|
|
16
|
+
query: Schema.String,
|
|
17
|
+
recency: Schema.optional(SearchRecency)
|
|
18
|
+
});
|
|
19
|
+
/** Numbered `title / url / snippet` list - what a model reads best. */
|
|
20
|
+
const defaultRender = (results) => results.length === 0 ? "No results found." : results.map((r, i) => {
|
|
21
|
+
const head = `${i + 1}. ${r.title ?? r.url}\n ${r.url}`;
|
|
22
|
+
return r.snippet === void 0 ? head : `${head}\n ${r.snippet}`;
|
|
23
|
+
}).join("\n\n");
|
|
24
|
+
/**
|
|
25
|
+
* The canonical web-search tool. Its `R` is just `WebSearch`, so providing
|
|
26
|
+
* any search-provider Layer satisfies it and the model-facing contract
|
|
27
|
+
* (name, description, schema) is identical no matter which backend answers
|
|
28
|
+
* - swap `PerplexitySearch.layer` for `ExaSearch.layer` and the tool the
|
|
29
|
+
* model sees does not change. Drops straight into a `Toolkit` and the
|
|
30
|
+
* `LanguageModel` tool-calling loop.
|
|
31
|
+
*
|
|
32
|
+
* The model controls only `query` and `recency`; domain scoping and the
|
|
33
|
+
* result cap are app policy, fixed here on the constructor. `Output` is
|
|
34
|
+
* rendered text, not raw `SearchResult[]`: the model reads the list, while
|
|
35
|
+
* the app still gets the structured results through the normal tool-result
|
|
36
|
+
* channel. Pass `render` to change the format.
|
|
37
|
+
*/
|
|
38
|
+
const webSearchTool = (options) => {
|
|
39
|
+
const name = options?.name ?? "web_search";
|
|
40
|
+
const render = options?.render ?? defaultRender;
|
|
41
|
+
const maxResults = options?.maxResults ?? 5;
|
|
42
|
+
const includeDomains = options?.includeDomains;
|
|
43
|
+
const excludeDomains = options?.excludeDomains;
|
|
44
|
+
return make({
|
|
45
|
+
name,
|
|
46
|
+
description: "Search the web for current information. Returns ranked results with titles, URLs, and snippets.",
|
|
47
|
+
inputSchema: fromEffectSchema(WebSearchToolArgs),
|
|
48
|
+
run: (args) => search({
|
|
49
|
+
query: args.query,
|
|
50
|
+
maxResults,
|
|
51
|
+
...args.recency !== void 0 && { recency: args.recency },
|
|
52
|
+
...includeDomains !== void 0 && { includeDomains },
|
|
53
|
+
...excludeDomains !== void 0 && { excludeDomains }
|
|
54
|
+
}).pipe(Effect.tap((r) => Effect.annotateCurrentSpan("web_search.result_count", r.results.length)), Effect.map((r) => render(r.results)), Effect.withSpan(name, {
|
|
55
|
+
kind: "client",
|
|
56
|
+
attributes: {
|
|
57
|
+
"web_search.query": args.query,
|
|
58
|
+
"web_search.max_results": maxResults,
|
|
59
|
+
...args.recency !== void 0 && { "web_search.recency": args.recency },
|
|
60
|
+
...includeDomains !== void 0 && { "web_search.include_domains": includeDomains },
|
|
61
|
+
...excludeDomains !== void 0 && { "web_search.exclude_domains": excludeDomains }
|
|
62
|
+
}
|
|
63
|
+
}))
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
//#endregion
|
|
67
|
+
export { WebSearchTool_exports as t, webSearchTool };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=WebSearchTool.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSearchTool.mjs","names":["Tool.make","Tool.fromEffectSchema"],"sources":["../../src/web-search/WebSearchTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport * as Tool from \"../tool/Tool.js\"\nimport { search, SearchRecency, type SearchResult, WebSearch } from \"./WebSearch.js\"\n\n/**\n * Model-facing argument schema. Deliberately narrow: `query` plus the one\n * filter that is genuinely the model's call - `recency` (it knows whether a\n * question is about current events or evergreen). App-policy scoping\n * (`includeDomains` / `excludeDomains`) and the `maxResults` cost ceiling\n * are pinned on the constructor instead, so they are guaranteed rather than\n * left to the model to remember each call.\n */\nconst WebSearchToolArgs = Schema.Struct({\n query: Schema.String,\n recency: Schema.optional(SearchRecency),\n})\n\nexport type WebSearchToolArgs = typeof WebSearchToolArgs.Type\n\n/** Numbered `title / url / snippet` list - what a model reads best. */\nconst defaultRender = (results: ReadonlyArray<SearchResult>): string =>\n results.length === 0\n ? \"No results found.\"\n : results\n .map((r, i) => {\n const head = `${i + 1}. ${r.title ?? r.url}\\n ${r.url}`\n return r.snippet === undefined ? head : `${head}\\n ${r.snippet}`\n })\n .join(\"\\n\\n\")\n\nexport type WebSearchToolOptions = {\n /** Tool name the model sees. Default `\"web_search\"`. */\n readonly name?: string\n /**\n * App-fixed ceiling on results per call - a cost guard, not exposed to\n * the model. Default `5`.\n */\n readonly maxResults?: number\n /**\n * App-fixed allowlist applied to every search. A policy scope (\"only\n * search our docs\"), not a model knob - so it is enforced, not requested.\n */\n readonly includeDomains?: ReadonlyArray<string>\n /** App-fixed denylist applied to every search (\"never return X\"). */\n readonly excludeDomains?: ReadonlyArray<string>\n /**\n * Override how results are rendered into the model-facing string.\n * Default: a numbered `title / url / snippet` list.\n */\n readonly render?: (results: ReadonlyArray<SearchResult>) => string\n}\n\n/**\n * The canonical web-search tool. Its `R` is just `WebSearch`, so providing\n * any search-provider Layer satisfies it and the model-facing contract\n * (name, description, schema) is identical no matter which backend answers\n * - swap `PerplexitySearch.layer` for `ExaSearch.layer` and the tool the\n * model sees does not change. Drops straight into a `Toolkit` and the\n * `LanguageModel` tool-calling loop.\n *\n * The model controls only `query` and `recency`; domain scoping and the\n * result cap are app policy, fixed here on the constructor. `Output` is\n * rendered text, not raw `SearchResult[]`: the model reads the list, while\n * the app still gets the structured results through the normal tool-result\n * channel. Pass `render` to change the format.\n */\nexport const webSearchTool = (\n options?: WebSearchToolOptions,\n): Tool.Tool<string, WebSearchToolArgs, never, string, WebSearch> => {\n const name = options?.name ?? \"web_search\"\n const render = options?.render ?? defaultRender\n const maxResults = options?.maxResults ?? 5\n const includeDomains = options?.includeDomains\n const excludeDomains = options?.excludeDomains\n return Tool.make({\n name,\n description:\n \"Search the web for current information. Returns ranked results with titles, URLs, and snippets.\",\n inputSchema: Tool.fromEffectSchema(WebSearchToolArgs),\n // The call is wrapped in a tracing span so agent traces show the tool\n // invocation (query, filters, result count) nested under the model turn.\n // `withSpan` is a no-op until a Tracer is installed, so this is free by\n // default and adds nothing to the requirements.\n run: (args) =>\n search({\n query: args.query,\n maxResults,\n ...(args.recency !== undefined && { recency: args.recency }),\n ...(includeDomains !== undefined && { includeDomains }),\n ...(excludeDomains !== undefined && { excludeDomains }),\n }).pipe(\n Effect.tap((r) => Effect.annotateCurrentSpan(\"web_search.result_count\", r.results.length)),\n Effect.map((r) => render(r.results)),\n Effect.withSpan(name, {\n kind: \"client\",\n attributes: {\n \"web_search.query\": args.query,\n \"web_search.max_results\": maxResults,\n ...(args.recency !== undefined && { \"web_search.recency\": args.recency }),\n ...(includeDomains !== undefined && { \"web_search.include_domains\": includeDomains }),\n ...(excludeDomains !== undefined && { \"web_search.exclude_domains\": excludeDomains }),\n },\n }),\n ),\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,MAAM,oBAAoB,OAAO,OAAO;CACtC,OAAO,OAAO;CACd,SAAS,OAAO,SAAS,cAAc;CACxC,CAAC;;AAKF,MAAM,iBAAiB,YACrB,QAAQ,WAAW,IACf,sBACA,QACG,KAAK,GAAG,MAAM;CACb,MAAM,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,OAAO,EAAE;AACpD,QAAO,EAAE,YAAY,KAAA,IAAY,OAAO,GAAG,KAAK,OAAO,EAAE;EACzD,CACD,KAAK,OAAO;;;;;;;;;;;;;;;AAsCrB,MAAa,iBACX,YACmE;CACnE,MAAM,OAAO,SAAS,QAAQ;CAC9B,MAAM,SAAS,SAAS,UAAU;CAClC,MAAM,aAAa,SAAS,cAAc;CAC1C,MAAM,iBAAiB,SAAS;CAChC,MAAM,iBAAiB,SAAS;AAChC,QAAOA,KAAU;EACf;EACA,aACE;EACF,aAAaC,iBAAsB,kBAAkB;EAKrD,MAAM,SACJ,OAAO;GACL,OAAO,KAAK;GACZ;GACA,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,SAAS,KAAK,SAAS;GAC3D,GAAI,mBAAmB,KAAA,KAAa,EAAE,gBAAgB;GACtD,GAAI,mBAAmB,KAAA,KAAa,EAAE,gBAAgB;GACvD,CAAC,CAAC,KACD,OAAO,KAAK,MAAM,OAAO,oBAAoB,2BAA2B,EAAE,QAAQ,OAAO,CAAC,EAC1F,OAAO,KAAK,MAAM,OAAO,EAAE,QAAQ,CAAC,EACpC,OAAO,SAAS,MAAM;GACpB,MAAM;GACN,YAAY;IACV,oBAAoB,KAAK;IACzB,0BAA0B;IAC1B,GAAI,KAAK,YAAY,KAAA,KAAa,EAAE,sBAAsB,KAAK,SAAS;IACxE,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,gBAAgB;IACpF,GAAI,mBAAmB,KAAA,KAAa,EAAE,8BAA8B,gBAAgB;IACrF;GACF,CAAC,CACH;EACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-uai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Low-level primitives (loop, conversation, items, tools, streaming codecs) for building AI agents with Effect.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -110,6 +110,14 @@
|
|
|
110
110
|
"types": "./dist/transcriber/Transcriber.d.mts",
|
|
111
111
|
"import": "./dist/transcriber/Transcriber.mjs"
|
|
112
112
|
},
|
|
113
|
+
"./WebSearch": {
|
|
114
|
+
"types": "./dist/web-search/WebSearch.d.mts",
|
|
115
|
+
"import": "./dist/web-search/WebSearch.mjs"
|
|
116
|
+
},
|
|
117
|
+
"./WebSearchTool": {
|
|
118
|
+
"types": "./dist/web-search/WebSearchTool.d.mts",
|
|
119
|
+
"import": "./dist/web-search/WebSearchTool.mjs"
|
|
120
|
+
},
|
|
113
121
|
"./Loop": {
|
|
114
122
|
"types": "./dist/loop/Loop.d.mts",
|
|
115
123
|
"import": "./dist/loop/Loop.mjs"
|
|
@@ -81,10 +81,14 @@ describe("embed / embedMany free exports preserve E in their return type", () =>
|
|
|
81
81
|
// of the cross-provider request set. Requesting them on the generic
|
|
82
82
|
// helper is a compile error; they're reachable only via the typed
|
|
83
83
|
// `JinaEmbedding` tag.
|
|
84
|
+
// These calls exist only to assert the encoding is a compile error; they
|
|
85
|
+
// are intentionally never run, so the floating-effect check is off here.
|
|
86
|
+
// @effect-diagnostics effect/floatingEffect:off
|
|
84
87
|
// @ts-expect-error "multivector" is not an EmbedEncoding
|
|
85
88
|
embedMany({ inputs: ["x"], model: "m", encoding: "multivector" })
|
|
86
89
|
// @ts-expect-error "sparse" is not an EmbedEncoding
|
|
87
90
|
embed({ input: "x", model: "m", encoding: "sparse" })
|
|
91
|
+
// @effect-diagnostics effect/floatingEffect:error
|
|
88
92
|
})
|
|
89
93
|
|
|
90
94
|
it("when the request is widened to CommonEmbedRequest, the response is the open union", () => {
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ export * as SandboxImage from "./sandbox/SandboxImage.js"
|
|
|
18
18
|
export * as SandboxNetwork from "./sandbox/SandboxNetwork.js"
|
|
19
19
|
export * as SpeechSynthesizer from "./speech-synthesizer/SpeechSynthesizer.js"
|
|
20
20
|
export * as Transcriber from "./transcriber/Transcriber.js"
|
|
21
|
+
export * as WebSearch from "./web-search/WebSearch.js"
|
|
22
|
+
export * as WebSearchTool from "./web-search/WebSearchTool.js"
|
|
21
23
|
export * as Vector from "./math/Vector.js"
|
|
22
24
|
export * as Loop from "./loop/Loop.js"
|
|
23
25
|
export * as Retry from "./retry/Retry.js"
|
|
@@ -32,3 +34,4 @@ export * as Lines from "./streaming/Lines.js"
|
|
|
32
34
|
export * as SSE from "./streaming/SSE.js"
|
|
33
35
|
export * as StructuredFormat from "./structured-format/StructuredFormat.js"
|
|
34
36
|
export * as Metrics from "./observability/Metrics.js"
|
|
37
|
+
export * as Telemetry from "./observability/Telemetry.js"
|
|
@@ -2,7 +2,7 @@ import { Array as Arr, Context, Effect, Option, Stream } from "effect"
|
|
|
2
2
|
import * as AiError from "../domain/AiError.js"
|
|
3
3
|
import type { HistoryItem } from "../domain/Items.js"
|
|
4
4
|
import type * as StructuredFormat from "../structured-format/StructuredFormat.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { Toolkit } from "../tool/Toolkit.js"
|
|
6
6
|
import { isTurnComplete, type Turn, type TurnEvent } from "../domain/Turn.js"
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -18,7 +18,12 @@ export type CommonRequest = {
|
|
|
18
18
|
* so code that yields a typed provider tag gets autocompletion.
|
|
19
19
|
*/
|
|
20
20
|
readonly model: string
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The model-visible tools for this request, as a `Toolkit`. The provider
|
|
23
|
+
* renders it to wire descriptors (`Tool.descriptorsOf`); omit it for a turn
|
|
24
|
+
* with no tools.
|
|
25
|
+
*/
|
|
26
|
+
readonly tools?: Toolkit
|
|
22
27
|
readonly toolChoice?:
|
|
23
28
|
| "auto"
|
|
24
29
|
| "required"
|
package/src/loop/Loop.test.ts
CHANGED
|
@@ -179,6 +179,28 @@ describe("Loop.loop", () => {
|
|
|
179
179
|
expect(b.length).toBe(3)
|
|
180
180
|
})
|
|
181
181
|
|
|
182
|
+
it("onTurnComplete: handler may return a step stream directly (not just Effect<Stream>)", async () => {
|
|
183
|
+
// The handler can skip the Effect wrapper when no effect is needed -
|
|
184
|
+
// bare stop() / next(s), mirroring loop's body.
|
|
185
|
+
const turnComplete: TurnEvent = TurnEvent.TurnComplete({
|
|
186
|
+
turn: { items: [], usage: { input_tokens: 0, output_tokens: 0 }, stop_reason: "stop" },
|
|
187
|
+
})
|
|
188
|
+
const deltas: Stream.Stream<TurnEvent> = Stream.fromIterable([
|
|
189
|
+
TurnEvent.TextDelta({ text: "hi" }),
|
|
190
|
+
turnComplete,
|
|
191
|
+
])
|
|
192
|
+
|
|
193
|
+
const plain = deltas.pipe(onTurnComplete(() => stop()))
|
|
194
|
+
const effectful = deltas.pipe(onTurnComplete(() => Effect.sync(() => stop())))
|
|
195
|
+
|
|
196
|
+
const a = await Effect.runPromise(Stream.runCollect(plain))
|
|
197
|
+
const b = await Effect.runPromise(Stream.runCollect(effectful))
|
|
198
|
+
|
|
199
|
+
// Two value(delta) wraps + one stop sentinel; both return forms behave identically.
|
|
200
|
+
expect(a.length).toBe(3)
|
|
201
|
+
expect(b.length).toBe(3)
|
|
202
|
+
})
|
|
203
|
+
|
|
182
204
|
it("is stack-safe and linear-time across many iterations", async () => {
|
|
183
205
|
// 100k iterations far exceeds V8's typical stack depth (~10–15k frames).
|
|
184
206
|
const N = 100_000
|
package/src/loop/Loop.ts
CHANGED
|
@@ -67,6 +67,16 @@ interface StepDef extends Data.TaggedEnum.WithGenerics<2> {
|
|
|
67
67
|
|
|
68
68
|
const Step = Data.taggedEnum<StepDef>()
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Bare step constructors, so a loop body can emit `Value(...)`, `Next(...)`,
|
|
72
|
+
* `Stop()`, `StopWith(...)` directly inside a `Stream.make(...)` without the
|
|
73
|
+
* `Step.` prefix. (The `Step` object itself can't be exported under that name
|
|
74
|
+
* because it collides with the exported `Step` type.) For the common cases
|
|
75
|
+
* prefer the `value` / `next` / `stop` helpers, which also handle the
|
|
76
|
+
* single-element-stream wrapping for `next` / `stop`.
|
|
77
|
+
*/
|
|
78
|
+
export const { Value, Next, Stop, StopWith } = Step
|
|
79
|
+
|
|
70
80
|
/** Wrap a value so it flows through the loop to downstream consumers. */
|
|
71
81
|
export const value = <A>(a: A): Step<A, never> => Step.Value({ value: a })
|
|
72
82
|
|
|
@@ -103,6 +113,11 @@ export const stop = <S = never>(state?: S): Stream.Stream<Step<never, S>> =>
|
|
|
103
113
|
* Pre-pipe transforms (`Stream.tap` / `Stream.map` / `Stream.filter`) on
|
|
104
114
|
* the raw delta stream cover anything an `emit`-style callback would do.
|
|
105
115
|
*
|
|
116
|
+
* `then` may return the step stream directly, or an `Effect` that produces
|
|
117
|
+
* it (for branches that need to read a `Ref`, decode tool args, log, etc.).
|
|
118
|
+
* Mirrors `loop`'s body: return a bare `stop()` / `next(s)` where no effect
|
|
119
|
+
* is needed, lift to `Effect` only where one is.
|
|
120
|
+
*
|
|
106
121
|
* If the upstream ends without a `TurnComplete`, the resulting stream
|
|
107
122
|
* fails with `AiError.IncompleteTurn`. Catch it via `Stream.catchTag` if
|
|
108
123
|
* you want to recover.
|
|
@@ -110,21 +125,25 @@ export const stop = <S = never>(state?: S): Stream.Stream<Step<never, S>> =>
|
|
|
110
125
|
* Dual: data-first `onTurnComplete(deltas, then)` and data-last
|
|
111
126
|
* `deltas.pipe(onTurnComplete(then))` both work.
|
|
112
127
|
*/
|
|
128
|
+
type TurnContinuation<S, A, E2, R2> =
|
|
129
|
+
| Stream.Stream<Step<A, S>, E2, R2>
|
|
130
|
+
| Effect.Effect<Stream.Stream<Step<A, S>, E2, R2>, E2, R2>
|
|
131
|
+
|
|
113
132
|
export const onTurnComplete: {
|
|
114
133
|
<S, A, E2 = never, R2 = never>(
|
|
115
|
-
then: (turn: Turn) =>
|
|
134
|
+
then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,
|
|
116
135
|
): <E, R>(
|
|
117
136
|
deltas: Stream.Stream<TurnEvent, E, R>,
|
|
118
137
|
) => Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
|
|
119
138
|
<S, A, E, R, E2 = never, R2 = never>(
|
|
120
139
|
deltas: Stream.Stream<TurnEvent, E, R>,
|
|
121
|
-
then: (turn: Turn) =>
|
|
140
|
+
then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,
|
|
122
141
|
): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2>
|
|
123
142
|
} = Function.dual(
|
|
124
143
|
2,
|
|
125
144
|
<S, A, E, R, E2, R2>(
|
|
126
145
|
deltas: Stream.Stream<TurnEvent, E, R>,
|
|
127
|
-
then: (turn: Turn) =>
|
|
146
|
+
then: (turn: Turn) => TurnContinuation<S, A, E2, R2>,
|
|
128
147
|
): Stream.Stream<Step<TurnEvent | A, S>, E | E2 | IncompleteTurn, R | R2> =>
|
|
129
148
|
Stream.unwrap(
|
|
130
149
|
Effect.gen(function* () {
|
|
@@ -141,7 +160,8 @@ export const onTurnComplete: {
|
|
|
141
160
|
Effect.gen(function* () {
|
|
142
161
|
const opt = yield* Ref.get(turnRef)
|
|
143
162
|
if (Option.isNone(opt)) return yield* new IncompleteTurn({})
|
|
144
|
-
|
|
163
|
+
const result = then(opt.value)
|
|
164
|
+
return Effect.isEffect(result) ? yield* result : result
|
|
145
165
|
}),
|
|
146
166
|
)
|
|
147
167
|
|
|
@@ -287,6 +307,9 @@ export const loop: {
|
|
|
287
307
|
}
|
|
288
308
|
})
|
|
289
309
|
|
|
310
|
+
// `Stream.fromPull` expects the generator to RETURN the pull effect,
|
|
311
|
+
// not run it; `return yield* pull` would execute a pull and break it.
|
|
312
|
+
// @effect-diagnostics-next-line effect/returnEffectInGen:off
|
|
290
313
|
return pull
|
|
291
314
|
}),
|
|
292
315
|
),
|