@llm4ts/js 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Riccardo Merolla
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # @llm4ts/js
2
+
3
+ The fastest way to try [llm4ts](https://github.com/riccardomerolla/llm4ts):
4
+ a Promise-based client for plain JavaScript and TypeScript consumers — no
5
+ Effect knowledge required.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @llm4ts/js
11
+ ```
12
+
13
+ Requires Node.js >= 22.
14
+
15
+ ## Usage
16
+
17
+ Works out of the box with the built-in mock provider — no credentials needed:
18
+
19
+ ```js
20
+ import { createClient } from "@llm4ts/js"
21
+
22
+ const client = createClient({ provider: "mock", model: "mock" })
23
+ const response = await client.complete("Say hello")
24
+ console.log(response.content)
25
+ ```
26
+
27
+ Swap in a real provider by name (`openai`, `anthropic`, `gemini`,
28
+ `lm-studio`, `ollama`) — API keys are read from the standard environment
29
+ variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`):
30
+
31
+ ```js
32
+ const client = createClient({
33
+ provider: "anthropic",
34
+ model: "claude-sonnet-4-5"
35
+ })
36
+ const answer = await client.complete("Summarize the Effect library in one line")
37
+ ```
38
+
39
+ The client also exposes `health()` for checking provider availability and
40
+ credentials.
41
+
42
+ For full flows — plans, review loops, Git integration, CLI coding agents —
43
+ use [`@llm4ts/runner`](https://www.npmjs.com/package/@llm4ts/runner).
44
+
45
+ ## License
46
+
47
+ MIT
@@ -0,0 +1,53 @@
1
+ import * as Schema from "effect/Schema";
2
+ export declare const JsProvider: Schema.Literals<readonly ["mock", "openai", "anthropic", "gemini", "lm-studio", "ollama"]>;
3
+ export type JsProvider = typeof JsProvider.Type;
4
+ declare const ClientConfig_base: Schema.Class<ClientConfig, Schema.Struct<{
5
+ readonly provider: Schema.Literals<readonly ["mock", "openai", "anthropic", "gemini", "lm-studio", "ollama"]>;
6
+ readonly model: Schema.optionalKey<Schema.String>;
7
+ readonly baseUrl: Schema.optionalKey<Schema.String>;
8
+ readonly apiKey: Schema.optionalKey<Schema.String>;
9
+ readonly timeoutSeconds: Schema.optionalKey<Schema.Number>;
10
+ readonly temperature: Schema.optionalKey<Schema.Number>;
11
+ readonly maxTokens: Schema.optionalKey<Schema.Int>;
12
+ }>, {}>;
13
+ export declare class ClientConfig extends ClientConfig_base {
14
+ }
15
+ declare const CompletionUsage_base: Schema.Class<CompletionUsage, Schema.Struct<{
16
+ readonly prompt: Schema.Int;
17
+ readonly completion: Schema.Int;
18
+ readonly total: Schema.Int;
19
+ readonly cached: Schema.optionalKey<Schema.Int>;
20
+ }>, {}>;
21
+ export declare class CompletionUsage extends CompletionUsage_base {
22
+ }
23
+ declare const Completion_base: Schema.Class<Completion, Schema.Struct<{
24
+ readonly content: Schema.String;
25
+ readonly usage: Schema.optionalKey<typeof CompletionUsage>;
26
+ readonly metadata: Schema.$Record<Schema.String, Schema.String>;
27
+ }>, {}>;
28
+ export declare class Completion extends Completion_base {
29
+ }
30
+ declare const ClientHealth_base: Schema.Class<ClientHealth, Schema.Struct<{
31
+ readonly available: Schema.Boolean;
32
+ readonly availability: Schema.String;
33
+ readonly authentication: Schema.String;
34
+ }>, {}>;
35
+ export declare class ClientHealth extends ClientHealth_base {
36
+ }
37
+ export type ErrorCategory = "Configuration" | "Authentication" | "RateLimit" | "Timeout" | "Parse" | "Provider" | "Interrupted" | "Unknown";
38
+ export declare class Llm4tsError extends Error {
39
+ readonly category: ErrorCategory;
40
+ readonly detail: unknown;
41
+ constructor(category: ErrorCategory, message: string, detail?: unknown);
42
+ }
43
+ export interface CallOptions {
44
+ readonly signal?: AbortSignal;
45
+ }
46
+ export interface LlmClient {
47
+ readonly complete: (prompt: string, options?: CallOptions) => Promise<Completion>;
48
+ readonly health: (options?: CallOptions) => Promise<ClientHealth>;
49
+ }
50
+ export declare const createClient: (input: unknown) => LlmClient;
51
+ export declare const mockClient: () => LlmClient;
52
+ export {};
53
+ //# sourceMappingURL=Client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAavC,eAAO,MAAM,UAAU,4FAOrB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;;;;;;;;;;AAE/C,qBAAa,YAAa,SAAQ,iBAQhC;CAAG;;;;;;;AAEL,qBAAa,eAAgB,SAAQ,oBAKnC;CAAG;;;;;;AAEL,qBAAa,UAAW,SAAQ,eAI9B;CAAG;;;;;;AAEL,qBAAa,YAAa,SAAQ,iBAIhC;CAAG;AAEL,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,OAAO,GACP,UAAU,GACV,aAAa,GACb,SAAS,CAAA;AAEb,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;gBAEZ,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO;CAMvE;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IACjF,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAA;CAClE;AAoFD,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,SAiC7C,CAAA;AAED,eAAO,MAAM,UAAU,QAAO,SAA8D,CAAA"}
package/dist/Client.js ADDED
@@ -0,0 +1,143 @@
1
+ import * as Duration from "effect/Duration";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Redacted from "effect/Redacted";
4
+ import * as Schema from "effect/Schema";
5
+ import { ApiConnectorConfig } from "@llm4ts/core/ConnectorConfig";
6
+ import { AuthenticationError, ConfigError, ParseError, RateLimitError, TimeoutError } from "@llm4ts/core/Errors";
7
+ import { ConnectorIds } from "@llm4ts/core/Models";
8
+ import { collect } from "@llm4ts/core/Streaming";
9
+ import { nodeFlowRunnerDependencies } from "@llm4ts/runner/FlowRunner";
10
+ export const JsProvider = Schema.Literals([
11
+ "mock",
12
+ "openai",
13
+ "anthropic",
14
+ "gemini",
15
+ "lm-studio",
16
+ "ollama"
17
+ ]);
18
+ export class ClientConfig extends Schema.Class("ClientConfig")({
19
+ provider: JsProvider,
20
+ model: Schema.optionalKey(Schema.String),
21
+ baseUrl: Schema.optionalKey(Schema.String),
22
+ apiKey: Schema.optionalKey(Schema.String),
23
+ timeoutSeconds: Schema.optionalKey(Schema.Number),
24
+ temperature: Schema.optionalKey(Schema.Number),
25
+ maxTokens: Schema.optionalKey(Schema.Int)
26
+ }) {
27
+ }
28
+ export class CompletionUsage extends Schema.Class("CompletionUsage")({
29
+ prompt: Schema.Int,
30
+ completion: Schema.Int,
31
+ total: Schema.Int,
32
+ cached: Schema.optionalKey(Schema.Int)
33
+ }) {
34
+ }
35
+ export class Completion extends Schema.Class("Completion")({
36
+ content: Schema.String,
37
+ usage: Schema.optionalKey(CompletionUsage),
38
+ metadata: Schema.Record(Schema.String, Schema.String)
39
+ }) {
40
+ }
41
+ export class ClientHealth extends Schema.Class("ClientHealth")({
42
+ available: Schema.Boolean,
43
+ availability: Schema.String,
44
+ authentication: Schema.String
45
+ }) {
46
+ }
47
+ export class Llm4tsError extends Error {
48
+ category;
49
+ detail;
50
+ constructor(category, message, detail) {
51
+ super(message, { cause: detail });
52
+ this.name = "Llm4tsError";
53
+ this.category = category;
54
+ this.detail = detail;
55
+ }
56
+ }
57
+ const connectorId = (provider) => {
58
+ switch (provider) {
59
+ case "mock":
60
+ return ConnectorIds.Mock;
61
+ case "openai":
62
+ return ConnectorIds.OpenAI;
63
+ case "anthropic":
64
+ return ConnectorIds.Anthropic;
65
+ case "gemini":
66
+ return ConnectorIds.GeminiApi;
67
+ case "lm-studio":
68
+ return ConnectorIds.LmStudio;
69
+ case "ollama":
70
+ return ConnectorIds.Ollama;
71
+ }
72
+ };
73
+ const categoryOf = (error) => error instanceof ConfigError
74
+ ? "Configuration"
75
+ : error instanceof AuthenticationError
76
+ ? "Authentication"
77
+ : error instanceof RateLimitError
78
+ ? "RateLimit"
79
+ : error instanceof TimeoutError
80
+ ? "Timeout"
81
+ : error instanceof ParseError
82
+ ? "Parse"
83
+ : "Provider";
84
+ const messageOf = (error) => error instanceof Error && error.message.length > 0 ? error.message : String(error);
85
+ const bridge = async (effect, options) => {
86
+ try {
87
+ const result = await Effect.runPromise(Effect.result(effect), {
88
+ ...(options?.signal === undefined ? {} : { signal: options.signal })
89
+ });
90
+ if (result._tag === "Failure") {
91
+ const failure = result.failure;
92
+ const category = categoryOf(failure);
93
+ throw new Llm4tsError(category, messageOf(failure), failure);
94
+ }
95
+ return result.success;
96
+ }
97
+ catch (error) {
98
+ if (error instanceof Llm4tsError) {
99
+ throw error;
100
+ }
101
+ const interrupted = options?.signal?.aborted === true;
102
+ throw new Llm4tsError(interrupted ? "Interrupted" : "Unknown", interrupted ? "operation interrupted" : messageOf(error), error);
103
+ }
104
+ };
105
+ const decodeConfig = (input) => {
106
+ try {
107
+ return Schema.decodeUnknownSync(ClientConfig)(input);
108
+ }
109
+ catch (error) {
110
+ throw new Llm4tsError("Configuration", `invalid client configuration: ${messageOf(error)}`, error);
111
+ }
112
+ };
113
+ const apiConfig = (config) => ApiConnectorConfig.make({
114
+ connectorId: connectorId(config.provider),
115
+ model: config.model ?? (config.provider === "mock" ? "mock" : ""),
116
+ ...(config.baseUrl === undefined ? {} : { baseUrl: config.baseUrl }),
117
+ ...(config.apiKey === undefined ? {} : { apiKey: Redacted.make(config.apiKey) }),
118
+ ...(config.timeoutSeconds === undefined
119
+ ? {}
120
+ : { timeout: Duration.seconds(config.timeoutSeconds) }),
121
+ ...(config.temperature === undefined ? {} : { temperature: config.temperature }),
122
+ ...(config.maxTokens === undefined ? {} : { maxTokens: config.maxTokens })
123
+ });
124
+ export const createClient = (input) => {
125
+ const config = apiConfig(decodeConfig(input));
126
+ const connector = nodeFlowRunnerDependencies().registry.resolve(config);
127
+ return {
128
+ complete: (prompt, options) => bridge(Effect.flatMap(connector, (service) => collect(service.executeStream(prompt))).pipe(Effect.map((response) => Completion.make({
129
+ content: response.content,
130
+ metadata: response.metadata,
131
+ ...(response.usage === undefined
132
+ ? {}
133
+ : { usage: CompletionUsage.make(response.usage) })
134
+ }))), options),
135
+ health: (options) => bridge(Effect.flatMap(connector, (service) => service.healthCheck).pipe(Effect.map((health) => ClientHealth.make({
136
+ available: health.availability === "Healthy" || health.availability === "Degraded",
137
+ availability: health.availability,
138
+ authentication: health.authStatus
139
+ }))), options)
140
+ };
141
+ };
142
+ export const mockClient = () => createClient({ provider: "mock", model: "mock" });
143
+ //# sourceMappingURL=Client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Client.js","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const packageName = "@llm4ts/js";
2
+ //# sourceMappingURL=Package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Package.d.ts","sourceRoot":"","sources":["../src/Package.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,eAAe,CAAA"}
@@ -0,0 +1,2 @@
1
+ export const packageName = "@llm4ts/js";
2
+ //# sourceMappingURL=Package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Package.js","sourceRoot":"","sources":["../src/Package.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAA"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@llm4ts/js",
3
+ "version": "0.1.0",
4
+ "description": "Promise and exception facade for llm4ts",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "exports": {
16
+ ".": "./dist/Client.js",
17
+ "./Client": "./dist/Client.js",
18
+ "./Package": "./dist/Package.js",
19
+ "./package.json": "./package.json"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "provenance": true
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/riccardomerolla/llm4ts.git",
28
+ "directory": "packages/js"
29
+ },
30
+ "homepage": "https://github.com/riccardomerolla/llm4ts#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/riccardomerolla/llm4ts/issues"
33
+ },
34
+ "keywords": [
35
+ "llm",
36
+ "effect",
37
+ "ai",
38
+ "agents",
39
+ "workflow",
40
+ "typescript"
41
+ ],
42
+ "dependencies": {
43
+ "@llm4ts/flow": "0.1.0",
44
+ "@llm4ts/core": "0.1.0",
45
+ "@llm4ts/runner": "0.1.0"
46
+ },
47
+ "peerDependencies": {
48
+ "effect": "^4.0.0-beta.102"
49
+ },
50
+ "devDependencies": {
51
+ "effect": "^4.0.0-beta.102"
52
+ },
53
+ "scripts": {
54
+ "clean": "tsc -b tsconfig.json --clean",
55
+ "test": "vitest run test"
56
+ }
57
+ }
package/src/Client.ts ADDED
@@ -0,0 +1,204 @@
1
+ import * as Duration from "effect/Duration"
2
+ import * as Effect from "effect/Effect"
3
+ import * as Redacted from "effect/Redacted"
4
+ import * as Schema from "effect/Schema"
5
+ import { ApiConnectorConfig } from "@llm4ts/core/ConnectorConfig"
6
+ import {
7
+ AuthenticationError,
8
+ ConfigError,
9
+ ParseError,
10
+ RateLimitError,
11
+ TimeoutError
12
+ } from "@llm4ts/core/Errors"
13
+ import { ConnectorIds, type ConnectorId } from "@llm4ts/core/Models"
14
+ import { collect } from "@llm4ts/core/Streaming"
15
+ import { nodeFlowRunnerDependencies } from "@llm4ts/runner/FlowRunner"
16
+
17
+ export const JsProvider = Schema.Literals([
18
+ "mock",
19
+ "openai",
20
+ "anthropic",
21
+ "gemini",
22
+ "lm-studio",
23
+ "ollama"
24
+ ])
25
+ export type JsProvider = typeof JsProvider.Type
26
+
27
+ export class ClientConfig extends Schema.Class<ClientConfig>("ClientConfig")({
28
+ provider: JsProvider,
29
+ model: Schema.optionalKey(Schema.String),
30
+ baseUrl: Schema.optionalKey(Schema.String),
31
+ apiKey: Schema.optionalKey(Schema.String),
32
+ timeoutSeconds: Schema.optionalKey(Schema.Number),
33
+ temperature: Schema.optionalKey(Schema.Number),
34
+ maxTokens: Schema.optionalKey(Schema.Int)
35
+ }) {}
36
+
37
+ export class CompletionUsage extends Schema.Class<CompletionUsage>("CompletionUsage")({
38
+ prompt: Schema.Int,
39
+ completion: Schema.Int,
40
+ total: Schema.Int,
41
+ cached: Schema.optionalKey(Schema.Int)
42
+ }) {}
43
+
44
+ export class Completion extends Schema.Class<Completion>("Completion")({
45
+ content: Schema.String,
46
+ usage: Schema.optionalKey(CompletionUsage),
47
+ metadata: Schema.Record(Schema.String, Schema.String)
48
+ }) {}
49
+
50
+ export class ClientHealth extends Schema.Class<ClientHealth>("ClientHealth")({
51
+ available: Schema.Boolean,
52
+ availability: Schema.String,
53
+ authentication: Schema.String
54
+ }) {}
55
+
56
+ export type ErrorCategory =
57
+ | "Configuration"
58
+ | "Authentication"
59
+ | "RateLimit"
60
+ | "Timeout"
61
+ | "Parse"
62
+ | "Provider"
63
+ | "Interrupted"
64
+ | "Unknown"
65
+
66
+ export class Llm4tsError extends Error {
67
+ readonly category: ErrorCategory
68
+ readonly detail: unknown
69
+
70
+ constructor(category: ErrorCategory, message: string, detail?: unknown) {
71
+ super(message, { cause: detail })
72
+ this.name = "Llm4tsError"
73
+ this.category = category
74
+ this.detail = detail
75
+ }
76
+ }
77
+
78
+ export interface CallOptions {
79
+ readonly signal?: AbortSignal
80
+ }
81
+
82
+ export interface LlmClient {
83
+ readonly complete: (prompt: string, options?: CallOptions) => Promise<Completion>
84
+ readonly health: (options?: CallOptions) => Promise<ClientHealth>
85
+ }
86
+
87
+ const connectorId = (provider: JsProvider): ConnectorId => {
88
+ switch (provider) {
89
+ case "mock":
90
+ return ConnectorIds.Mock
91
+ case "openai":
92
+ return ConnectorIds.OpenAI
93
+ case "anthropic":
94
+ return ConnectorIds.Anthropic
95
+ case "gemini":
96
+ return ConnectorIds.GeminiApi
97
+ case "lm-studio":
98
+ return ConnectorIds.LmStudio
99
+ case "ollama":
100
+ return ConnectorIds.Ollama
101
+ }
102
+ }
103
+
104
+ const categoryOf = (error: unknown): ErrorCategory =>
105
+ error instanceof ConfigError
106
+ ? "Configuration"
107
+ : error instanceof AuthenticationError
108
+ ? "Authentication"
109
+ : error instanceof RateLimitError
110
+ ? "RateLimit"
111
+ : error instanceof TimeoutError
112
+ ? "Timeout"
113
+ : error instanceof ParseError
114
+ ? "Parse"
115
+ : "Provider"
116
+
117
+ const messageOf = (error: unknown): string =>
118
+ error instanceof Error && error.message.length > 0 ? error.message : String(error)
119
+
120
+ const bridge = async <A, E>(effect: Effect.Effect<A, E>, options?: CallOptions): Promise<A> => {
121
+ try {
122
+ const result = await Effect.runPromise(Effect.result(effect), {
123
+ ...(options?.signal === undefined ? {} : { signal: options.signal })
124
+ })
125
+ if (result._tag === "Failure") {
126
+ const failure = result.failure
127
+ const category = categoryOf(failure)
128
+ throw new Llm4tsError(category, messageOf(failure), failure)
129
+ }
130
+ return result.success
131
+ } catch (error) {
132
+ if (error instanceof Llm4tsError) {
133
+ throw error
134
+ }
135
+ const interrupted = options?.signal?.aborted === true
136
+ throw new Llm4tsError(
137
+ interrupted ? "Interrupted" : "Unknown",
138
+ interrupted ? "operation interrupted" : messageOf(error),
139
+ error
140
+ )
141
+ }
142
+ }
143
+
144
+ const decodeConfig = (input: unknown): ClientConfig => {
145
+ try {
146
+ return Schema.decodeUnknownSync(ClientConfig)(input)
147
+ } catch (error) {
148
+ throw new Llm4tsError(
149
+ "Configuration",
150
+ `invalid client configuration: ${messageOf(error)}`,
151
+ error
152
+ )
153
+ }
154
+ }
155
+
156
+ const apiConfig = (config: ClientConfig): ApiConnectorConfig =>
157
+ ApiConnectorConfig.make({
158
+ connectorId: connectorId(config.provider),
159
+ model: config.model ?? (config.provider === "mock" ? "mock" : ""),
160
+ ...(config.baseUrl === undefined ? {} : { baseUrl: config.baseUrl }),
161
+ ...(config.apiKey === undefined ? {} : { apiKey: Redacted.make(config.apiKey) }),
162
+ ...(config.timeoutSeconds === undefined
163
+ ? {}
164
+ : { timeout: Duration.seconds(config.timeoutSeconds) }),
165
+ ...(config.temperature === undefined ? {} : { temperature: config.temperature }),
166
+ ...(config.maxTokens === undefined ? {} : { maxTokens: config.maxTokens })
167
+ })
168
+
169
+ export const createClient = (input: unknown): LlmClient => {
170
+ const config = apiConfig(decodeConfig(input))
171
+ const connector = nodeFlowRunnerDependencies().registry.resolve(config)
172
+ return {
173
+ complete: (prompt, options) =>
174
+ bridge(
175
+ Effect.flatMap(connector, (service) => collect(service.executeStream(prompt))).pipe(
176
+ Effect.map((response) =>
177
+ Completion.make({
178
+ content: response.content,
179
+ metadata: response.metadata,
180
+ ...(response.usage === undefined
181
+ ? {}
182
+ : { usage: CompletionUsage.make(response.usage) })
183
+ })
184
+ )
185
+ ),
186
+ options
187
+ ),
188
+ health: (options) =>
189
+ bridge(
190
+ Effect.flatMap(connector, (service) => service.healthCheck).pipe(
191
+ Effect.map((health) =>
192
+ ClientHealth.make({
193
+ available: health.availability === "Healthy" || health.availability === "Degraded",
194
+ availability: health.availability,
195
+ authentication: health.authStatus
196
+ })
197
+ )
198
+ ),
199
+ options
200
+ )
201
+ }
202
+ }
203
+
204
+ export const mockClient = (): LlmClient => createClient({ provider: "mock", model: "mock" })
package/src/Package.ts ADDED
@@ -0,0 +1 @@
1
+ export const packageName = "@llm4ts/js"