@effect/ai-openrouter 0.8.2 → 4.0.0-beta.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/Generated.d.ts +19505 -0
- package/dist/Generated.d.ts.map +1 -0
- package/dist/Generated.js +5115 -0
- package/dist/Generated.js.map +1 -0
- package/dist/OpenRouterClient.d.ts +116 -0
- package/dist/OpenRouterClient.d.ts.map +1 -0
- package/dist/OpenRouterClient.js +120 -0
- package/dist/OpenRouterClient.js.map +1 -0
- package/dist/{dts/OpenRouterConfig.d.ts → OpenRouterConfig.d.ts} +9 -9
- package/dist/OpenRouterConfig.d.ts.map +1 -0
- package/dist/{esm/OpenRouterConfig.js → OpenRouterConfig.js} +8 -5
- package/dist/OpenRouterConfig.js.map +1 -0
- package/dist/OpenRouterError.d.ts +83 -0
- package/dist/OpenRouterError.d.ts.map +1 -0
- package/dist/OpenRouterError.js +10 -0
- package/dist/OpenRouterError.js.map +1 -0
- package/dist/OpenRouterLanguageModel.d.ts +285 -0
- package/dist/OpenRouterLanguageModel.d.ts.map +1 -0
- package/dist/OpenRouterLanguageModel.js +1210 -0
- package/dist/OpenRouterLanguageModel.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/errors.d.ts +2 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +347 -0
- package/dist/internal/errors.js.map +1 -0
- package/dist/{dts/internal → internal}/utilities.d.ts.map +1 -1
- package/dist/internal/utilities.js +77 -0
- package/dist/internal/utilities.js.map +1 -0
- package/package.json +45 -62
- package/src/Generated.ts +9312 -5435
- package/src/OpenRouterClient.ts +223 -304
- package/src/OpenRouterConfig.ts +14 -14
- package/src/OpenRouterError.ts +92 -0
- package/src/OpenRouterLanguageModel.ts +941 -572
- package/src/index.ts +20 -4
- package/src/internal/errors.ts +373 -0
- package/src/internal/utilities.ts +78 -11
- package/Generated/package.json +0 -6
- package/OpenRouterClient/package.json +0 -6
- package/OpenRouterConfig/package.json +0 -6
- package/OpenRouterLanguageModel/package.json +0 -6
- package/README.md +0 -5
- package/dist/cjs/Generated.js +0 -5813
- package/dist/cjs/Generated.js.map +0 -1
- package/dist/cjs/OpenRouterClient.js +0 -229
- package/dist/cjs/OpenRouterClient.js.map +0 -1
- package/dist/cjs/OpenRouterConfig.js +0 -30
- package/dist/cjs/OpenRouterConfig.js.map +0 -1
- package/dist/cjs/OpenRouterLanguageModel.js +0 -826
- package/dist/cjs/OpenRouterLanguageModel.js.map +0 -1
- package/dist/cjs/index.js +0 -16
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/utilities.js +0 -29
- package/dist/cjs/internal/utilities.js.map +0 -1
- package/dist/dts/Generated.d.ts +0 -11026
- package/dist/dts/Generated.d.ts.map +0 -1
- package/dist/dts/OpenRouterClient.d.ts +0 -407
- package/dist/dts/OpenRouterClient.d.ts.map +0 -1
- package/dist/dts/OpenRouterConfig.d.ts.map +0 -1
- package/dist/dts/OpenRouterLanguageModel.d.ts +0 -215
- package/dist/dts/OpenRouterLanguageModel.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -17
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/esm/Generated.js +0 -5457
- package/dist/esm/Generated.js.map +0 -1
- package/dist/esm/OpenRouterClient.js +0 -214
- package/dist/esm/OpenRouterClient.js.map +0 -1
- package/dist/esm/OpenRouterConfig.js.map +0 -1
- package/dist/esm/OpenRouterLanguageModel.js +0 -815
- package/dist/esm/OpenRouterLanguageModel.js.map +0 -1
- package/dist/esm/index.js +0 -17
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/utilities.js +0 -21
- package/dist/esm/internal/utilities.js.map +0 -1
- package/dist/esm/package.json +0 -4
- package/index/package.json +0 -6
- /package/dist/{dts/internal → internal}/utilities.d.ts +0 -0
package/src/OpenRouterClient.ts
CHANGED
|
@@ -1,372 +1,291 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import * as
|
|
5
|
-
import * as Sse from "@effect/experimental/Sse"
|
|
6
|
-
import * as HttpBody from "@effect/platform/HttpBody"
|
|
7
|
-
import * as HttpClient from "@effect/platform/HttpClient"
|
|
8
|
-
import * as HttpClientRequest from "@effect/platform/HttpClientRequest"
|
|
9
|
-
import * as Config from "effect/Config"
|
|
10
|
-
import type { ConfigError } from "effect/ConfigError"
|
|
11
|
-
import * as Context from "effect/Context"
|
|
4
|
+
import type * as Config from "effect/Config"
|
|
12
5
|
import * as Effect from "effect/Effect"
|
|
13
6
|
import { identity } from "effect/Function"
|
|
14
7
|
import * as Layer from "effect/Layer"
|
|
8
|
+
import * as Predicate from "effect/Predicate"
|
|
15
9
|
import type * as Redacted from "effect/Redacted"
|
|
16
10
|
import * as Schema from "effect/Schema"
|
|
11
|
+
import * as ServiceMap from "effect/ServiceMap"
|
|
17
12
|
import * as Stream from "effect/Stream"
|
|
18
|
-
import * as
|
|
19
|
-
import
|
|
13
|
+
import type * as AiError from "effect/unstable/ai/AiError"
|
|
14
|
+
import * as Sse from "effect/unstable/encoding/Sse"
|
|
15
|
+
import * as HttpBody from "effect/unstable/http/HttpBody"
|
|
16
|
+
import * as HttpClient from "effect/unstable/http/HttpClient"
|
|
17
|
+
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest"
|
|
18
|
+
import type * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"
|
|
19
|
+
import * as Generated from "./Generated.ts"
|
|
20
|
+
import * as Errors from "./internal/errors.ts"
|
|
21
|
+
import { OpenRouterConfig } from "./OpenRouterConfig.ts"
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*/
|
|
25
|
-
export class OpenRouterClient extends Context.Tag(
|
|
26
|
-
"@effect/ai-openrouter/OpenRouterClient"
|
|
27
|
-
)<OpenRouterClient, Service>() {}
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Service Interface
|
|
25
|
+
// =============================================================================
|
|
28
26
|
|
|
29
27
|
/**
|
|
28
|
+
* The OpenRouter client service interface.
|
|
29
|
+
*
|
|
30
|
+
* Provides methods for interacting with OpenRouter's Chat Completions API,
|
|
31
|
+
* including both synchronous and streaming message creation.
|
|
32
|
+
*
|
|
30
33
|
* @since 1.0.0
|
|
31
|
-
* @category
|
|
34
|
+
* @category models
|
|
32
35
|
*/
|
|
33
36
|
export interface Service {
|
|
34
|
-
|
|
35
|
-
* The underlying HTTP client capable of communicating with the OpenRouter API.
|
|
36
|
-
*
|
|
37
|
-
* This client is pre-configured with authentication, base URL, and standard
|
|
38
|
-
* headers required for OpenRouter API communication. It provides direct access
|
|
39
|
-
* to the generated OpenRouter API client for operations not covered by the
|
|
40
|
-
* higher-level methods.
|
|
41
|
-
*
|
|
42
|
-
* Use this when you need to:
|
|
43
|
-
* - Access provider-specific API endpoints not available through the AI SDK
|
|
44
|
-
* - Implement custom request/response handling
|
|
45
|
-
* - Use OpenRouter API features not yet supported by the Effect AI abstractions
|
|
46
|
-
* - Perform batch operations or non-streaming requests
|
|
47
|
-
*
|
|
48
|
-
* The client automatically handles authentication and follows OpenRouter's
|
|
49
|
-
* API conventions for request formatting and error handling.
|
|
50
|
-
*/
|
|
51
|
-
readonly client: Generated.Client
|
|
37
|
+
readonly client: Generated.OpenRouterClient
|
|
52
38
|
|
|
53
39
|
readonly createChatCompletion: (
|
|
54
40
|
options: typeof Generated.ChatGenerationParams.Encoded
|
|
55
|
-
) => Effect.Effect<
|
|
41
|
+
) => Effect.Effect<
|
|
42
|
+
[body: typeof Generated.SendChatCompletionRequest200.Type, response: HttpClientResponse.HttpClientResponse],
|
|
43
|
+
AiError.AiError
|
|
44
|
+
>
|
|
56
45
|
|
|
57
46
|
readonly createChatCompletionStream: (
|
|
58
|
-
options: Omit<typeof Generated.ChatGenerationParams.Encoded, "stream">
|
|
59
|
-
) =>
|
|
47
|
+
options: Omit<typeof Generated.ChatGenerationParams.Encoded, "stream" | "stream_options">
|
|
48
|
+
) => Effect.Effect<
|
|
49
|
+
[
|
|
50
|
+
response: HttpClientResponse.HttpClientResponse,
|
|
51
|
+
stream: Stream.Stream<ChatStreamingResponseChunkData, AiError.AiError>
|
|
52
|
+
],
|
|
53
|
+
AiError.AiError
|
|
54
|
+
>
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
/**
|
|
63
58
|
* @since 1.0.0
|
|
64
|
-
* @category
|
|
59
|
+
* @category Models
|
|
60
|
+
*/
|
|
61
|
+
export type ChatStreamingResponseChunkData = typeof Generated.ChatStreamingResponseChunk.fields.data.Type
|
|
62
|
+
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// Service Identifier
|
|
65
|
+
// =============================================================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Service identifier for the OpenRouter client.
|
|
69
|
+
*
|
|
70
|
+
* @since 1.0.0
|
|
71
|
+
* @category service
|
|
72
|
+
*/
|
|
73
|
+
export class OpenRouterClient extends ServiceMap.Service<
|
|
74
|
+
OpenRouterClient,
|
|
75
|
+
Service
|
|
76
|
+
>()("@effect/ai-openrouter/OpenRouterClient") {}
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// Options
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Configuration options for creating an OpenRouter client.
|
|
84
|
+
*
|
|
85
|
+
* @since 1.0.0
|
|
86
|
+
* @category models
|
|
65
87
|
*/
|
|
66
|
-
export
|
|
67
|
-
readonly apiKey?: Redacted.Redacted | undefined
|
|
88
|
+
export type Options = {
|
|
89
|
+
readonly apiKey?: Redacted.Redacted<string> | undefined
|
|
90
|
+
|
|
68
91
|
readonly apiUrl?: string | undefined
|
|
92
|
+
|
|
69
93
|
/**
|
|
70
94
|
* Optional URL of your site for rankings on `openrouter.ai`.
|
|
71
95
|
*/
|
|
72
|
-
readonly
|
|
96
|
+
readonly siteReferrer?: string | undefined
|
|
97
|
+
|
|
73
98
|
/**
|
|
74
99
|
* Optional title of your site for rankings on `openrouter.ai`.
|
|
75
100
|
*/
|
|
76
|
-
readonly
|
|
101
|
+
readonly siteTitle?: string | undefined
|
|
102
|
+
|
|
77
103
|
/**
|
|
78
|
-
*
|
|
79
|
-
* API requests.
|
|
104
|
+
* Optional transformer for the underlying HTTP client.
|
|
80
105
|
*
|
|
81
|
-
*
|
|
82
|
-
* a modified version. It's applied after all standard client configuration
|
|
83
|
-
* (authentication, base URL, headers) but before any requests are made.
|
|
84
|
-
*
|
|
85
|
-
* Use this for:
|
|
86
|
-
* - Adding custom middleware (logging, metrics, caching)
|
|
87
|
-
* - Modifying request/response processing behavior
|
|
88
|
-
* - Adding custom retry logic or error handling
|
|
89
|
-
* - Integrating with monitoring or debugging tools
|
|
90
|
-
* - Applying organization-specific HTTP client policies
|
|
91
|
-
*
|
|
92
|
-
* The transformation is applied once during client initialization and affects
|
|
93
|
-
* all subsequent API requests made through this client instance.
|
|
94
|
-
*
|
|
95
|
-
* Leave absent or set to `undefined` if no custom HTTP client behavior is
|
|
96
|
-
* needed.
|
|
106
|
+
* Use this to add middleware, logging, or custom request/response handling.
|
|
97
107
|
*/
|
|
98
108
|
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
99
|
-
}
|
|
100
|
-
const httpClient = (yield* HttpClient.HttpClient).pipe(
|
|
101
|
-
HttpClient.mapRequest((request) =>
|
|
102
|
-
request.pipe(
|
|
103
|
-
HttpClientRequest.prependUrl(options.apiUrl ?? "https://openrouter.ai/api/v1"),
|
|
104
|
-
options.apiKey ? HttpClientRequest.bearerToken(options.apiKey) : identity,
|
|
105
|
-
options.referrer ? HttpClientRequest.setHeader("HTTP-Referrer", options.referrer) : identity,
|
|
106
|
-
options.title ? HttpClientRequest.setHeader("X-Title", options.title) : identity,
|
|
107
|
-
HttpClientRequest.acceptJson
|
|
108
|
-
)
|
|
109
|
-
),
|
|
110
|
-
options.transformClient ?? identity
|
|
111
|
-
)
|
|
109
|
+
}
|
|
112
110
|
|
|
113
|
-
|
|
111
|
+
// =============================================================================
|
|
112
|
+
// Constructor
|
|
113
|
+
// =============================================================================
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
AiError.HttpRequestError.fromRequestError({
|
|
137
|
-
module: "OpenRouterClient",
|
|
138
|
-
method: "streamRequest",
|
|
139
|
-
error
|
|
140
|
-
}),
|
|
141
|
-
ResponseError: (error) =>
|
|
142
|
-
AiError.HttpResponseError.fromResponseError({
|
|
143
|
-
module: "OpenRouterClient",
|
|
144
|
-
method: "streamRequest",
|
|
145
|
-
error
|
|
146
|
-
}),
|
|
147
|
-
ParseError: (error) =>
|
|
148
|
-
AiError.MalformedOutput.fromParseError({
|
|
149
|
-
module: "OpenRouterClient",
|
|
150
|
-
method: "streamRequest",
|
|
151
|
-
error
|
|
152
|
-
})
|
|
153
|
-
})
|
|
115
|
+
/**
|
|
116
|
+
* Creates an OpenRouter client service with the given options.
|
|
117
|
+
*
|
|
118
|
+
* @since 1.0.0
|
|
119
|
+
* @category constructors
|
|
120
|
+
*/
|
|
121
|
+
export const make = Effect.fnUntraced(
|
|
122
|
+
function*(options: Options): Effect.fn.Return<Service, never, HttpClient.HttpClient> {
|
|
123
|
+
const baseClient = yield* HttpClient.HttpClient
|
|
124
|
+
|
|
125
|
+
const httpClient = baseClient.pipe(
|
|
126
|
+
HttpClient.mapRequest((request) =>
|
|
127
|
+
request.pipe(
|
|
128
|
+
HttpClientRequest.prependUrl(options.apiUrl ?? "https://openrouter.ai/api/v1"),
|
|
129
|
+
options.apiKey ? HttpClientRequest.bearerToken(options.apiKey) : identity,
|
|
130
|
+
options.siteReferrer ? HttpClientRequest.setHeader("HTTP-Referrer", options.siteReferrer) : identity,
|
|
131
|
+
options.siteTitle ? HttpClientRequest.setHeader("X-Title", options.siteTitle) : identity,
|
|
132
|
+
HttpClientRequest.acceptJson
|
|
133
|
+
)
|
|
134
|
+
),
|
|
135
|
+
options.transformClient ?? identity
|
|
154
136
|
)
|
|
155
|
-
}
|
|
156
137
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
url: error.request.url,
|
|
172
|
-
urlParams: error.request.urlParams
|
|
173
|
-
},
|
|
174
|
-
response: {
|
|
175
|
-
headers: error.response.headers,
|
|
176
|
-
status: error.response.status
|
|
177
|
-
}
|
|
178
|
-
})),
|
|
138
|
+
const httpClientOk = HttpClient.filterStatusOk(httpClient)
|
|
139
|
+
|
|
140
|
+
const client = Generated.make(httpClient, {
|
|
141
|
+
transformClient: Effect.fnUntraced(function*(client) {
|
|
142
|
+
const config = yield* OpenRouterConfig.getOrUndefined
|
|
143
|
+
if (Predicate.isNotUndefined(config?.transformClient)) {
|
|
144
|
+
return config.transformClient(client)
|
|
145
|
+
}
|
|
146
|
+
return client
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const createChatCompletion: Service["createChatCompletion"] = (payload) =>
|
|
151
|
+
client.sendChatCompletionRequest({ payload, config: { includeResponse: true } }).pipe(
|
|
179
152
|
Effect.catchTags({
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
ResponseError: (error) =>
|
|
187
|
-
AiError.HttpResponseError.fromResponseError({
|
|
188
|
-
module: "OpenRouterClient",
|
|
189
|
-
method: "createChatCompletion",
|
|
190
|
-
error
|
|
191
|
-
}),
|
|
192
|
-
ParseError: (error) =>
|
|
193
|
-
AiError.MalformedOutput.fromParseError({
|
|
194
|
-
module: "OpenRouterClient",
|
|
195
|
-
method: "createChatCompletion",
|
|
196
|
-
error
|
|
197
|
-
})
|
|
153
|
+
SendChatCompletionRequest400: (error) => Effect.fail(Errors.mapClientError(error, "createChatCompletion")),
|
|
154
|
+
SendChatCompletionRequest401: (error) => Effect.fail(Errors.mapClientError(error, "createChatCompletion")),
|
|
155
|
+
SendChatCompletionRequest429: (error) => Effect.fail(Errors.mapClientError(error, "createChatCompletion")),
|
|
156
|
+
SendChatCompletionRequest500: (error) => Effect.fail(Errors.mapClientError(error, "createChatCompletion")),
|
|
157
|
+
HttpClientError: (error) => Errors.mapHttpClientError(error, "createChatCompletion"),
|
|
158
|
+
SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, "createChatCompletion"))
|
|
198
159
|
})
|
|
199
160
|
)
|
|
161
|
+
|
|
162
|
+
const buildChatCompletionStream = (
|
|
163
|
+
response: HttpClientResponse.HttpClientResponse
|
|
164
|
+
): [
|
|
165
|
+
HttpClientResponse.HttpClientResponse,
|
|
166
|
+
Stream.Stream<ChatStreamingResponseChunkData, AiError.AiError>
|
|
167
|
+
] => {
|
|
168
|
+
const stream = response.stream.pipe(
|
|
169
|
+
Stream.decodeText(),
|
|
170
|
+
Stream.pipeThroughChannel(Sse.decode()),
|
|
171
|
+
Stream.mapEffect((event) => decodeChatCompletionSseData(event.data)),
|
|
172
|
+
Stream.takeWhile((data) => data !== "[DONE]"),
|
|
173
|
+
Stream.catchTags({
|
|
174
|
+
// TODO: handle SSE retries
|
|
175
|
+
Retry: (error) => Stream.die(error),
|
|
176
|
+
HttpClientError: (error) => Stream.fromEffect(Errors.mapHttpClientError(error, "createChatCompletionStream")),
|
|
177
|
+
SchemaError: (error) => Stream.fail(Errors.mapSchemaError(error, "createChatCompletionStream"))
|
|
178
|
+
})
|
|
179
|
+
) as any
|
|
180
|
+
return [response, stream]
|
|
200
181
|
}
|
|
201
|
-
)
|
|
202
182
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
183
|
+
const createChatCompletionStream: Service["createChatCompletionStream"] = (payload) =>
|
|
184
|
+
httpClientOk.execute(
|
|
185
|
+
HttpClientRequest.post("/chat/completions", {
|
|
186
|
+
body: HttpBody.jsonUnsafe({
|
|
187
|
+
...payload,
|
|
188
|
+
stream: true,
|
|
189
|
+
stream_options: { include_usage: true }
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
).pipe(
|
|
193
|
+
Effect.map(buildChatCompletionStream),
|
|
194
|
+
Effect.catchTag(
|
|
195
|
+
"HttpClientError",
|
|
196
|
+
(error) => Errors.mapHttpClientError(error, "createChatCompletionStream")
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return OpenRouterClient.of({
|
|
201
|
+
client,
|
|
202
|
+
createChatCompletion,
|
|
203
|
+
createChatCompletionStream
|
|
212
204
|
})
|
|
213
|
-
return streamRequest(request, ChatStreamingResponseChunk)
|
|
214
205
|
}
|
|
206
|
+
)
|
|
215
207
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
createChatCompletionStream
|
|
220
|
-
})
|
|
221
|
-
})
|
|
208
|
+
// =============================================================================
|
|
209
|
+
// Layers
|
|
210
|
+
// =============================================================================
|
|
222
211
|
|
|
223
212
|
/**
|
|
213
|
+
* Creates a layer for the OpenRouter client with the given options.
|
|
214
|
+
*
|
|
224
215
|
* @since 1.0.0
|
|
225
|
-
* @category
|
|
216
|
+
* @category layers
|
|
226
217
|
*/
|
|
227
|
-
export const layer = (options:
|
|
228
|
-
|
|
229
|
-
readonly apiUrl?: string | undefined
|
|
230
|
-
/**
|
|
231
|
-
* Optional URL of your site for rankings on `openrouter.ai`.
|
|
232
|
-
*/
|
|
233
|
-
readonly referrer?: string | undefined
|
|
234
|
-
/**
|
|
235
|
-
* Optional title of your site for rankings on `openrouter.ai`.
|
|
236
|
-
*/
|
|
237
|
-
readonly title?: string | undefined
|
|
238
|
-
/**
|
|
239
|
-
* A function to transform the underlying HTTP client before it's used to send
|
|
240
|
-
* API requests.
|
|
241
|
-
*
|
|
242
|
-
* This transformation function receives the configured HTTP client and returns
|
|
243
|
-
* a modified version. It's applied after all standard client configuration
|
|
244
|
-
* (authentication, base URL, headers) but before any requests are made.
|
|
245
|
-
*
|
|
246
|
-
* Use this for:
|
|
247
|
-
* - Adding custom middleware (logging, metrics, caching)
|
|
248
|
-
* - Modifying request/response processing behavior
|
|
249
|
-
* - Adding custom retry logic or error handling
|
|
250
|
-
* - Integrating with monitoring or debugging tools
|
|
251
|
-
* - Applying organization-specific HTTP client policies
|
|
252
|
-
*
|
|
253
|
-
* The transformation is applied once during client initialization and affects
|
|
254
|
-
* all subsequent API requests made through this client instance.
|
|
255
|
-
*
|
|
256
|
-
* Leave absent or set to `undefined` if no custom HTTP client behavior is
|
|
257
|
-
* needed.
|
|
258
|
-
*/
|
|
259
|
-
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
260
|
-
}): Layer.Layer<OpenRouterClient, never, HttpClient.HttpClient> => Layer.effect(OpenRouterClient, make(options))
|
|
218
|
+
export const layer = (options: Options): Layer.Layer<OpenRouterClient, never, HttpClient.HttpClient> =>
|
|
219
|
+
Layer.effect(OpenRouterClient, make(options))
|
|
261
220
|
|
|
262
221
|
/**
|
|
222
|
+
* Creates a layer for the OpenRouter client, loading the requisite
|
|
223
|
+
* configuration via Effect's `Config` module.
|
|
224
|
+
*
|
|
263
225
|
* @since 1.0.0
|
|
264
|
-
* @category
|
|
226
|
+
* @category layers
|
|
265
227
|
*/
|
|
266
|
-
export const layerConfig = (options
|
|
267
|
-
|
|
228
|
+
export const layerConfig = (options?: {
|
|
229
|
+
/**
|
|
230
|
+
* The config value to load for the API key.
|
|
231
|
+
*/
|
|
232
|
+
readonly apiKey?: Config.Config<Redacted.Redacted<string>> | undefined
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The config value to load for the API URL.
|
|
236
|
+
*/
|
|
268
237
|
readonly apiUrl?: Config.Config<string> | undefined
|
|
238
|
+
|
|
269
239
|
/**
|
|
270
|
-
*
|
|
240
|
+
* The config value to load for the site referrer URL.
|
|
271
241
|
*/
|
|
272
|
-
readonly
|
|
242
|
+
readonly siteReferrer?: Config.Config<string> | undefined
|
|
243
|
+
|
|
273
244
|
/**
|
|
274
|
-
*
|
|
245
|
+
* The config value to load for the site title.
|
|
275
246
|
*/
|
|
276
|
-
readonly
|
|
247
|
+
readonly siteTitle?: Config.Config<string> | undefined
|
|
248
|
+
|
|
277
249
|
/**
|
|
278
|
-
*
|
|
279
|
-
* API requests.
|
|
280
|
-
*
|
|
281
|
-
* This transformation function receives the configured HTTP client and returns
|
|
282
|
-
* a modified version. It's applied after all standard client configuration
|
|
283
|
-
* (authentication, base URL, headers) but before any requests are made.
|
|
284
|
-
*
|
|
285
|
-
* Use this for:
|
|
286
|
-
* - Adding custom middleware (logging, metrics, caching)
|
|
287
|
-
* - Modifying request/response processing behavior
|
|
288
|
-
* - Adding custom retry logic or error handling
|
|
289
|
-
* - Integrating with monitoring or debugging tools
|
|
290
|
-
* - Applying organization-specific HTTP client policies
|
|
291
|
-
*
|
|
292
|
-
* The transformation is applied once during client initialization and affects
|
|
293
|
-
* all subsequent API requests made through this client instance.
|
|
294
|
-
*
|
|
295
|
-
* Leave absent or set to `undefined` if no custom HTTP client behavior is
|
|
296
|
-
* needed.
|
|
250
|
+
* Optional transformer for the HTTP client.
|
|
297
251
|
*/
|
|
298
252
|
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
299
|
-
}): Layer.Layer<OpenRouterClient, ConfigError, HttpClient.HttpClient> =>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
Effect.
|
|
303
|
-
|
|
253
|
+
}): Layer.Layer<OpenRouterClient, Config.ConfigError, HttpClient.HttpClient> =>
|
|
254
|
+
Layer.effect(
|
|
255
|
+
OpenRouterClient,
|
|
256
|
+
Effect.gen(function*() {
|
|
257
|
+
const apiKey = Predicate.isNotUndefined(options?.apiKey)
|
|
258
|
+
? yield* options.apiKey
|
|
259
|
+
: undefined
|
|
260
|
+
const apiUrl = Predicate.isNotUndefined(options?.apiUrl)
|
|
261
|
+
? yield* options.apiUrl
|
|
262
|
+
: undefined
|
|
263
|
+
const siteReferrer = Predicate.isNotUndefined(options?.siteReferrer)
|
|
264
|
+
? yield* options.siteReferrer
|
|
265
|
+
: undefined
|
|
266
|
+
const siteTitle = Predicate.isNotUndefined(options?.siteTitle)
|
|
267
|
+
? yield* options.siteTitle
|
|
268
|
+
: undefined
|
|
269
|
+
return yield* make({
|
|
270
|
+
apiKey,
|
|
271
|
+
apiUrl,
|
|
272
|
+
siteReferrer,
|
|
273
|
+
siteTitle,
|
|
274
|
+
transformClient: options?.transformClient
|
|
275
|
+
})
|
|
276
|
+
})
|
|
304
277
|
)
|
|
305
|
-
}
|
|
306
278
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
*/
|
|
311
|
-
export class ChatStreamingMessageToolCall extends Schema.Class<ChatStreamingMessageToolCall>(
|
|
312
|
-
"@effect/ai-openrouter/ChatStreamingMessageToolCall"
|
|
313
|
-
)({
|
|
314
|
-
index: Schema.Number,
|
|
315
|
-
id: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
316
|
-
type: Schema.Literal("function"),
|
|
317
|
-
function: Schema.Struct({
|
|
318
|
-
name: Schema.String,
|
|
319
|
-
arguments: Schema.String
|
|
320
|
-
})
|
|
321
|
-
}) {}
|
|
279
|
+
// =============================================================================
|
|
280
|
+
// Internal Utilities
|
|
281
|
+
// =============================================================================
|
|
322
282
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
* @category Schemas
|
|
326
|
-
*/
|
|
327
|
-
export class ChatStreamingMessageChunk extends Schema.Class<ChatStreamingMessageChunk>(
|
|
328
|
-
"@effect/ai-openrouter/ChatStreamingMessageChunk"
|
|
329
|
-
)({
|
|
330
|
-
role: Schema.optionalWith(Schema.Literal("assistant"), { nullable: true }),
|
|
331
|
-
content: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
332
|
-
reasoning: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
333
|
-
reasoning_details: Schema.optionalWith(Schema.Array(Generated.ReasoningDetail), { nullable: true }),
|
|
334
|
-
images: Schema.optionalWith(Schema.Array(Generated.ChatMessageContentItemImage), { nullable: true }),
|
|
335
|
-
refusal: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
336
|
-
tool_calls: Schema.optionalWith(Schema.Array(ChatStreamingMessageToolCall), { nullable: true }),
|
|
337
|
-
annotations: Schema.optionalWith(Schema.Array(Generated.AnnotationDetail), { nullable: true })
|
|
338
|
-
}) {}
|
|
283
|
+
const ChatStreamingResponseChunkDataFromString = Schema.fromJsonString(Generated.ChatStreamingResponseChunk.fields.data)
|
|
284
|
+
const decodeChatStreamingResponseChunkData = Schema.decodeUnknownEffect(ChatStreamingResponseChunkDataFromString)
|
|
339
285
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
)({
|
|
347
|
-
index: Schema.Number,
|
|
348
|
-
delta: Schema.optionalWith(ChatStreamingMessageChunk, { nullable: true }),
|
|
349
|
-
finish_reason: Schema.optionalWith(Generated.ChatCompletionFinishReason, { nullable: true }),
|
|
350
|
-
native_finish_reason: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
351
|
-
logprobs: Schema.optionalWith(Generated.ChatMessageTokenLogprobs, { nullable: true })
|
|
352
|
-
}) {}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* @since 1.0.0
|
|
356
|
-
* @category Schemas
|
|
357
|
-
*/
|
|
358
|
-
export class ChatStreamingResponseChunk extends Schema.Class<ChatStreamingResponseChunk>(
|
|
359
|
-
"@effect/ai-openrouter/ChatStreamingResponseChunk"
|
|
360
|
-
)({
|
|
361
|
-
id: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
362
|
-
model: Schema.optionalWith(
|
|
363
|
-
Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.String),
|
|
364
|
-
{ nullable: true }
|
|
365
|
-
),
|
|
366
|
-
provider: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
367
|
-
created: Schema.DateTimeUtcFromNumber,
|
|
368
|
-
choices: Schema.Array(ChatStreamingChoice),
|
|
369
|
-
error: Schema.optionalWith(Generated.ChatError.fields.error, { nullable: true }),
|
|
370
|
-
system_fingerprint: Schema.optionalWith(Schema.String, { nullable: true }),
|
|
371
|
-
usage: Schema.optionalWith(Generated.ChatGenerationTokenUsage, { nullable: true })
|
|
372
|
-
}) {}
|
|
286
|
+
const decodeChatCompletionSseData = (
|
|
287
|
+
data: string
|
|
288
|
+
): Effect.Effect<ChatStreamingResponseChunkData | "[DONE]", Schema.SchemaError> =>
|
|
289
|
+
data === "[DONE]"
|
|
290
|
+
? Effect.succeed(data)
|
|
291
|
+
: decodeChatStreamingResponseChunkData(data)
|
package/src/OpenRouterConfig.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import type { HttpClient } from "@effect/platform/HttpClient"
|
|
5
|
-
import * as Context from "effect/Context"
|
|
6
4
|
import * as Effect from "effect/Effect"
|
|
7
5
|
import { dual } from "effect/Function"
|
|
6
|
+
import * as ServiceMap from "effect/ServiceMap"
|
|
7
|
+
import type { HttpClient } from "effect/unstable/http/HttpClient"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @since 1.0.0
|
|
11
|
-
* @category
|
|
11
|
+
* @category services
|
|
12
12
|
*/
|
|
13
|
-
export class OpenRouterConfig extends
|
|
13
|
+
export class OpenRouterConfig extends ServiceMap.Service<
|
|
14
14
|
OpenRouterConfig,
|
|
15
15
|
OpenRouterConfig.Service
|
|
16
|
-
>() {
|
|
16
|
+
>()("@effect/ai-openrouter/OpenRouterConfig") {
|
|
17
17
|
/**
|
|
18
18
|
* @since 1.0.0
|
|
19
19
|
*/
|
|
20
20
|
static readonly getOrUndefined: Effect.Effect<typeof OpenRouterConfig.Service | undefined> = Effect.map(
|
|
21
|
-
Effect.
|
|
22
|
-
(
|
|
21
|
+
Effect.services<never>(),
|
|
22
|
+
(services) => services.mapUnsafe.get(OpenRouterConfig.key)
|
|
23
23
|
)
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -29,26 +29,26 @@ export class OpenRouterConfig extends Context.Tag("@effect/ai-openrouter/OpenRou
|
|
|
29
29
|
export declare namespace OpenRouterConfig {
|
|
30
30
|
/**
|
|
31
31
|
* @since 1.0.0
|
|
32
|
-
* @category
|
|
32
|
+
* @category models
|
|
33
33
|
*/
|
|
34
34
|
export interface Service {
|
|
35
|
-
readonly transformClient?: (client: HttpClient) => HttpClient
|
|
35
|
+
readonly transformClient?: ((client: HttpClient) => HttpClient) | undefined
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* @since 1.0.0
|
|
41
|
-
* @category
|
|
41
|
+
* @category configuration
|
|
42
42
|
*/
|
|
43
43
|
export const withClientTransform: {
|
|
44
44
|
/**
|
|
45
45
|
* @since 1.0.0
|
|
46
|
-
* @category
|
|
46
|
+
* @category configuration
|
|
47
47
|
*/
|
|
48
48
|
(transform: (client: HttpClient) => HttpClient): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>
|
|
49
49
|
/**
|
|
50
50
|
* @since 1.0.0
|
|
51
|
-
* @category
|
|
51
|
+
* @category configuration
|
|
52
52
|
*/
|
|
53
53
|
<A, E, R>(
|
|
54
54
|
self: Effect.Effect<A, E, R>,
|
|
@@ -57,12 +57,12 @@ export const withClientTransform: {
|
|
|
57
57
|
} = dual<
|
|
58
58
|
/**
|
|
59
59
|
* @since 1.0.0
|
|
60
|
-
* @category
|
|
60
|
+
* @category configuration
|
|
61
61
|
*/
|
|
62
62
|
(transform: (client: HttpClient) => HttpClient) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>,
|
|
63
63
|
/**
|
|
64
64
|
* @since 1.0.0
|
|
65
|
-
* @category
|
|
65
|
+
* @category configuration
|
|
66
66
|
*/
|
|
67
67
|
<A, E, R>(
|
|
68
68
|
self: Effect.Effect<A, E, R>,
|