@effect/ai-anthropic 0.16.2 → 0.17.1
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/AnthropicTool/package.json +6 -0
- package/dist/cjs/AnthropicClient.js +285 -192
- package/dist/cjs/AnthropicClient.js.map +1 -1
- package/dist/cjs/AnthropicLanguageModel.js +1036 -311
- package/dist/cjs/AnthropicLanguageModel.js.map +1 -1
- package/dist/cjs/AnthropicTokenizer.js +8 -6
- package/dist/cjs/AnthropicTokenizer.js.map +1 -1
- package/dist/cjs/AnthropicTool.js +461 -0
- package/dist/cjs/AnthropicTool.js.map +1 -0
- package/dist/cjs/Generated.js +3507 -1230
- package/dist/cjs/Generated.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/utilities.js +11 -5
- package/dist/cjs/internal/utilities.js.map +1 -1
- package/dist/dts/AnthropicClient.d.ts +675 -17
- package/dist/dts/AnthropicClient.d.ts.map +1 -1
- package/dist/dts/AnthropicLanguageModel.d.ts +217 -26
- package/dist/dts/AnthropicLanguageModel.d.ts.map +1 -1
- package/dist/dts/AnthropicTokenizer.d.ts +1 -1
- package/dist/dts/AnthropicTokenizer.d.ts.map +1 -1
- package/dist/dts/AnthropicTool.d.ts +523 -0
- package/dist/dts/AnthropicTool.d.ts.map +1 -0
- package/dist/dts/Generated.d.ts +7863 -3496
- package/dist/dts/Generated.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/AnthropicClient.js +268 -190
- package/dist/esm/AnthropicClient.js.map +1 -1
- package/dist/esm/AnthropicLanguageModel.js +1032 -306
- package/dist/esm/AnthropicLanguageModel.js.map +1 -1
- package/dist/esm/AnthropicTokenizer.js +8 -6
- package/dist/esm/AnthropicTokenizer.js.map +1 -1
- package/dist/esm/AnthropicTool.js +452 -0
- package/dist/esm/AnthropicTool.js.map +1 -0
- package/dist/esm/Generated.js +3492 -1063
- package/dist/esm/Generated.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/utilities.js +10 -4
- package/dist/esm/internal/utilities.js.map +1 -1
- package/package.json +11 -3
- package/src/AnthropicClient.ts +710 -372
- package/src/AnthropicLanguageModel.ts +1416 -345
- package/src/AnthropicTokenizer.ts +14 -23
- package/src/AnthropicTool.ts +553 -0
- package/src/Generated.ts +4165 -1681
- package/src/index.ts +5 -0
- package/src/internal/utilities.ts +15 -7
package/src/AnthropicClient.ts
CHANGED
|
@@ -2,28 +2,25 @@
|
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
4
|
import * as AiError from "@effect/ai/AiError"
|
|
5
|
-
import * as AiInput from "@effect/ai/AiInput"
|
|
6
|
-
import * as AiResponse from "@effect/ai/AiResponse"
|
|
7
5
|
import * as Sse from "@effect/experimental/Sse"
|
|
6
|
+
import * as Headers from "@effect/platform/Headers"
|
|
8
7
|
import * as HttpBody from "@effect/platform/HttpBody"
|
|
9
8
|
import * as HttpClient from "@effect/platform/HttpClient"
|
|
10
|
-
import type * as HttpClientError from "@effect/platform/HttpClientError"
|
|
11
9
|
import * as HttpClientRequest from "@effect/platform/HttpClientRequest"
|
|
10
|
+
import * as Arr from "effect/Array"
|
|
11
|
+
import * as Chunk from "effect/Chunk"
|
|
12
12
|
import * as Config from "effect/Config"
|
|
13
13
|
import type { ConfigError } from "effect/ConfigError"
|
|
14
14
|
import * as Context from "effect/Context"
|
|
15
15
|
import * as Effect from "effect/Effect"
|
|
16
16
|
import { identity } from "effect/Function"
|
|
17
17
|
import * as Layer from "effect/Layer"
|
|
18
|
-
import * as Option from "effect/Option"
|
|
19
|
-
import * as Predicate from "effect/Predicate"
|
|
20
18
|
import * as Redacted from "effect/Redacted"
|
|
19
|
+
import * as Schema from "effect/Schema"
|
|
20
|
+
import type * as Scope from "effect/Scope"
|
|
21
21
|
import * as Stream from "effect/Stream"
|
|
22
22
|
import { AnthropicConfig } from "./AnthropicConfig.js"
|
|
23
23
|
import * as Generated from "./Generated.js"
|
|
24
|
-
import * as InternalUtilities from "./internal/utilities.js"
|
|
25
|
-
|
|
26
|
-
const constDisableValidation = { disableValidation: true } as const
|
|
27
24
|
|
|
28
25
|
/**
|
|
29
26
|
* @since 1.0.0
|
|
@@ -31,415 +28,756 @@ const constDisableValidation = { disableValidation: true } as const
|
|
|
31
28
|
*/
|
|
32
29
|
export class AnthropicClient extends Context.Tag(
|
|
33
30
|
"@effect/ai-anthropic/AnthropicClient"
|
|
34
|
-
)<AnthropicClient,
|
|
31
|
+
)<AnthropicClient, Service>() {}
|
|
35
32
|
|
|
36
33
|
/**
|
|
34
|
+
* Represents the interface that the `AnthropicClient` service provides.
|
|
35
|
+
*
|
|
36
|
+
* This service abstracts the complexity of communicating with Anthropic's API,
|
|
37
|
+
* providing both high-level text generation methods and low-level HTTP access
|
|
38
|
+
* for advanced use cases.
|
|
39
|
+
*
|
|
37
40
|
* @since 1.0.0
|
|
41
|
+
* @category Models
|
|
38
42
|
*/
|
|
39
|
-
export
|
|
43
|
+
export interface Service {
|
|
40
44
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
45
|
+
* The underlying HTTP client capable of communicating with the Anthropic API.
|
|
46
|
+
*
|
|
47
|
+
* This client is pre-configured with authentication, base URL, and standard
|
|
48
|
+
* headers required for Anthropic API communication. It provides direct access
|
|
49
|
+
* to the generated Anthropic API client for operations not covered by the
|
|
50
|
+
* higher-level methods.
|
|
51
|
+
*
|
|
52
|
+
* Use this when you need to:
|
|
53
|
+
* - Access provider-specific API endpoints not available through the AI SDK
|
|
54
|
+
* - Implement custom request/response handling
|
|
55
|
+
* - Use Anthropic API features not yet supported by the Effect AI abstractions
|
|
56
|
+
* - Perform batch operations or non-streaming requests
|
|
57
|
+
*
|
|
58
|
+
* The client automatically handles authentication and follows Anthropic's
|
|
59
|
+
* API conventions for request formatting and error handling.
|
|
43
60
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
61
|
+
readonly client: Generated.Client
|
|
62
|
+
|
|
63
|
+
readonly streamRequest: <A, I, R>(
|
|
64
|
+
request: HttpClientRequest.HttpClientRequest,
|
|
65
|
+
schema: Schema.Schema<A, I, R>
|
|
66
|
+
) => Stream.Stream<A, AiError.AiError, R>
|
|
67
|
+
|
|
68
|
+
readonly createMessage: (options: {
|
|
69
|
+
readonly params?: typeof Generated.BetaMessagesPostParams.Encoded | undefined
|
|
70
|
+
readonly payload: typeof Generated.BetaCreateMessageParams.Encoded
|
|
71
|
+
}) => Effect.Effect<Generated.BetaMessage, AiError.AiError>
|
|
72
|
+
|
|
73
|
+
readonly createMessageStream: (options: {
|
|
74
|
+
readonly params?: typeof Generated.BetaMessagesPostParams.Encoded | undefined
|
|
75
|
+
readonly payload: Omit<typeof Generated.BetaCreateMessageParams.Encoded, "stream">
|
|
76
|
+
}) => Stream.Stream<MessageStreamEvent, AiError.AiError>
|
|
53
77
|
}
|
|
54
78
|
|
|
55
79
|
/**
|
|
56
80
|
* @since 1.0.0
|
|
57
81
|
* @category Constructors
|
|
58
82
|
*/
|
|
59
|
-
export const make
|
|
83
|
+
export const make: (options: {
|
|
84
|
+
/**
|
|
85
|
+
* The API key that will be used to authenticate with Anthropic's API.
|
|
86
|
+
*
|
|
87
|
+
* The key is wrapped in a `Redacted` type to prevent accidental logging or
|
|
88
|
+
* exposure in debugging output, helping maintain security best practices.
|
|
89
|
+
*
|
|
90
|
+
* The key is automatically included in the `x-api-key` header for all API
|
|
91
|
+
* requests made through this client, which is automatically redacted in logs
|
|
92
|
+
* output by Effect loggers.
|
|
93
|
+
*
|
|
94
|
+
* Leave `undefined` if authentication will be handled through other means
|
|
95
|
+
* (e.g., environment-based authentication, proxy authentication, or when
|
|
96
|
+
* using a mock server that doesn't require authentication).
|
|
97
|
+
*/
|
|
60
98
|
readonly apiKey?: Redacted.Redacted | undefined
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The base URL endpoint used to communicate with Anthropic's API.
|
|
102
|
+
*
|
|
103
|
+
* This property determines the HTTP destination for all API requests made by
|
|
104
|
+
* this client.
|
|
105
|
+
*
|
|
106
|
+
* Defaults to `"https://api.anthropic.com"`.
|
|
107
|
+
*
|
|
108
|
+
* Override this value when you need to:
|
|
109
|
+
* - Point to a different Anthropic environment (e.g., staging or sandbox
|
|
110
|
+
* servers).
|
|
111
|
+
* - Use a proxy between your application and Anthropic's API for security,
|
|
112
|
+
* caching, or logging.
|
|
113
|
+
* - Employ a mock server for local development or testing.
|
|
114
|
+
*
|
|
115
|
+
* You may leave this property `undefined` to accept the default value.
|
|
116
|
+
*/
|
|
61
117
|
readonly apiUrl?: string | undefined
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The Anthropic API version to use for requests.
|
|
121
|
+
*
|
|
122
|
+
* This version string determines which API schema and features are available
|
|
123
|
+
* for your requests. Different versions may have different capabilities,
|
|
124
|
+
* request/response formats, or available models.
|
|
125
|
+
*
|
|
126
|
+
* Defaults to `"2023-06-01"`.
|
|
127
|
+
*
|
|
128
|
+
* You should specify a version that:
|
|
129
|
+
* - Supports the features and models you need
|
|
130
|
+
* - Is stable and well-tested for your use case
|
|
131
|
+
* - Matches your application's integration requirements
|
|
132
|
+
*
|
|
133
|
+
* Consult Anthropic's API documentation for available versions and their
|
|
134
|
+
* differences.
|
|
135
|
+
*/
|
|
62
136
|
readonly anthropicVersion?: string | undefined
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The organization ID to associate with API requests.
|
|
140
|
+
*
|
|
141
|
+
* This identifier links requests to a specific organization within your
|
|
142
|
+
* Anthropic account, enabling proper billing, usage tracking, and access
|
|
143
|
+
* control at the organizational level.
|
|
144
|
+
*
|
|
145
|
+
* Provide this when:
|
|
146
|
+
* - Your account belongs to multiple organizations
|
|
147
|
+
* - You need to ensure requests are billed to the correct organization
|
|
148
|
+
* - Organization-level access policies apply to your use case
|
|
149
|
+
*
|
|
150
|
+
* Leave `undefined` if you're using a personal account or the default
|
|
151
|
+
* organization.
|
|
152
|
+
*/
|
|
63
153
|
readonly organizationId?: Redacted.Redacted | undefined
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The project ID to associate with API requests.
|
|
157
|
+
*
|
|
158
|
+
* This identifier scopes requests to a specific project within your
|
|
159
|
+
* organization, enabling granular resource management, billing allocation,
|
|
160
|
+
* and access control at the project level.
|
|
161
|
+
*
|
|
162
|
+
* Specify this when:
|
|
163
|
+
* - You have multiple projects and need to separate their API usage
|
|
164
|
+
* - Project-level billing or quota management is required
|
|
165
|
+
* - Access policies are configured at the project level
|
|
166
|
+
*
|
|
167
|
+
* Leave `undefined` to use the default project or when project-level
|
|
168
|
+
* scoping is not needed.
|
|
169
|
+
*/
|
|
64
170
|
readonly projectId?: Redacted.Redacted | undefined
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* A function to transform the underlying HTTP client before it's used to send
|
|
174
|
+
* API requests.
|
|
175
|
+
*
|
|
176
|
+
* This transformation function receives the configured HTTP client and returns
|
|
177
|
+
* a modified version. It's applied after all standard client configuration
|
|
178
|
+
* (authentication, base URL, headers) but before any requests are made.
|
|
179
|
+
*
|
|
180
|
+
* Use this for:
|
|
181
|
+
* - Adding custom middleware (logging, metrics, caching)
|
|
182
|
+
* - Modifying request/response processing behavior
|
|
183
|
+
* - Adding custom retry logic or error handling
|
|
184
|
+
* - Integrating with monitoring or debugging tools
|
|
185
|
+
* - Applying organization-specific HTTP client policies
|
|
186
|
+
*
|
|
187
|
+
* The transformation is applied once during client initialization and affects
|
|
188
|
+
* all subsequent API requests made through this client instance.
|
|
189
|
+
*
|
|
190
|
+
* Leave absent or set to `undefined` if no custom HTTP client behavior is
|
|
191
|
+
* needed.
|
|
192
|
+
*/
|
|
65
193
|
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
HttpClientRequest.setHeader(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
HttpClientRequest.acceptJson
|
|
85
|
-
)
|
|
86
|
-
),
|
|
87
|
-
options.transformClient ? options.transformClient : identity
|
|
88
|
-
)
|
|
89
|
-
const httpClientOk = HttpClient.filterStatusOk(httpClient)
|
|
90
|
-
const client = Generated.make(httpClient, {
|
|
91
|
-
transformClient: (client) =>
|
|
92
|
-
AnthropicConfig.getOrUndefined.pipe(
|
|
93
|
-
Effect.map((config) => config?.transformClient ? config.transformClient(client) : client)
|
|
94
|
-
)
|
|
95
|
-
})
|
|
96
|
-
const streamRequest = <A = unknown>(
|
|
97
|
-
request: HttpClientRequest.HttpClientRequest
|
|
98
|
-
) =>
|
|
99
|
-
httpClientOk.execute(request).pipe(
|
|
100
|
-
Effect.map((r) => r.stream),
|
|
101
|
-
Stream.unwrapScoped,
|
|
102
|
-
Stream.decodeText(),
|
|
103
|
-
Stream.pipeThroughChannel(Sse.makeChannel()),
|
|
104
|
-
Stream.takeUntil((event) => event.event === "message_stop"),
|
|
105
|
-
Stream.map((event) => JSON.parse(event.data) as A)
|
|
194
|
+
}) => Effect.Effect<
|
|
195
|
+
Service,
|
|
196
|
+
never,
|
|
197
|
+
HttpClient.HttpClient | Scope.Scope
|
|
198
|
+
> = Effect.fnUntraced(function*(options) {
|
|
199
|
+
const apiKeyHeader = "x-api-key"
|
|
200
|
+
|
|
201
|
+
yield* Effect.locallyScopedWith(Headers.currentRedactedNames, Arr.append(apiKeyHeader))
|
|
202
|
+
|
|
203
|
+
const httpClient = (yield* HttpClient.HttpClient).pipe(
|
|
204
|
+
HttpClient.mapRequest((request) =>
|
|
205
|
+
request.pipe(
|
|
206
|
+
HttpClientRequest.prependUrl(options.apiUrl ?? "https://api.anthropic.com"),
|
|
207
|
+
options.apiKey
|
|
208
|
+
? HttpClientRequest.setHeader(apiKeyHeader, Redacted.value(options.apiKey))
|
|
209
|
+
: identity,
|
|
210
|
+
HttpClientRequest.setHeader("anthropic-version", options.anthropicVersion ?? "2023-06-01"),
|
|
211
|
+
HttpClientRequest.acceptJson
|
|
106
212
|
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
id: chunk.message.id,
|
|
148
|
-
model: chunk.message.model
|
|
149
|
-
},
|
|
150
|
-
constDisableValidation
|
|
151
|
-
)
|
|
152
|
-
)
|
|
153
|
-
break
|
|
154
|
-
}
|
|
155
|
-
case "message_delta": {
|
|
156
|
-
usage = {
|
|
157
|
-
...usage,
|
|
158
|
-
outputTokens: chunk.usage.output_tokens,
|
|
159
|
-
totalTokens: usage.inputTokens + chunk.usage.output_tokens
|
|
160
|
-
}
|
|
161
|
-
if (Predicate.isNotNullable(chunk.delta.stop_sequence)) {
|
|
162
|
-
metadata.stopSequence = chunk.delta.stop_sequence
|
|
163
|
-
}
|
|
164
|
-
finishReason = InternalUtilities.resolveFinishReason(chunk.delta.stop_reason)
|
|
165
|
-
break
|
|
166
|
-
}
|
|
167
|
-
case "message_stop": {
|
|
168
|
-
parts.push(
|
|
169
|
-
new AiResponse.FinishPart({
|
|
170
|
-
usage,
|
|
171
|
-
reason: finishReason,
|
|
172
|
-
providerMetadata: { [InternalUtilities.ProviderMetadataKey]: metadata }
|
|
173
|
-
}, constDisableValidation)
|
|
174
|
-
)
|
|
175
|
-
break
|
|
176
|
-
}
|
|
177
|
-
case "content_block_start": {
|
|
178
|
-
const content = chunk.content_block
|
|
179
|
-
switch (content.type) {
|
|
180
|
-
case "text": {
|
|
181
|
-
break
|
|
182
|
-
}
|
|
183
|
-
case "thinking": {
|
|
184
|
-
reasoning = { content: [content.thinking] }
|
|
185
|
-
break
|
|
186
|
-
}
|
|
187
|
-
case "tool_use": {
|
|
188
|
-
toolCalls[chunk.index] = {
|
|
189
|
-
id: content.id,
|
|
190
|
-
name: content.name,
|
|
191
|
-
params: ""
|
|
192
|
-
}
|
|
193
|
-
break
|
|
194
|
-
}
|
|
195
|
-
case "redacted_thinking": {
|
|
196
|
-
parts.push(
|
|
197
|
-
new AiResponse.RedactedReasoningPart(
|
|
198
|
-
{ redactedText: content.data },
|
|
199
|
-
constDisableValidation
|
|
200
|
-
)
|
|
201
|
-
)
|
|
202
|
-
break
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
break
|
|
206
|
-
}
|
|
207
|
-
case "content_block_delta": {
|
|
208
|
-
switch (chunk.delta.type) {
|
|
209
|
-
case "text_delta": {
|
|
210
|
-
parts.push(
|
|
211
|
-
new AiResponse.TextPart(
|
|
212
|
-
{ text: chunk.delta.text },
|
|
213
|
-
constDisableValidation
|
|
214
|
-
)
|
|
215
|
-
)
|
|
216
|
-
break
|
|
217
|
-
}
|
|
218
|
-
case "thinking_delta": {
|
|
219
|
-
if (Predicate.isNotUndefined(reasoning)) {
|
|
220
|
-
reasoning.content.push(chunk.delta.thinking)
|
|
221
|
-
}
|
|
222
|
-
break
|
|
223
|
-
}
|
|
224
|
-
case "signature_delta": {
|
|
225
|
-
if (Predicate.isNotUndefined(reasoning)) {
|
|
226
|
-
reasoning = {
|
|
227
|
-
...reasoning,
|
|
228
|
-
signature: chunk.delta.signature
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
break
|
|
232
|
-
}
|
|
233
|
-
case "input_json_delta": {
|
|
234
|
-
const tool = toolCalls[chunk.index]
|
|
235
|
-
if (Predicate.isNotUndefined(tool)) {
|
|
236
|
-
tool.params += chunk.delta.partial_json
|
|
237
|
-
}
|
|
238
|
-
break
|
|
239
|
-
}
|
|
240
|
-
// TODO: add support for citations (?)
|
|
241
|
-
case "citations_delta": {
|
|
242
|
-
break
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
break
|
|
246
|
-
}
|
|
247
|
-
case "content_block_stop": {
|
|
248
|
-
if (Predicate.isNotUndefined(toolCalls[chunk.index])) {
|
|
249
|
-
const tool = toolCalls[chunk.index]
|
|
250
|
-
try {
|
|
251
|
-
// If the tool call has no parameters, the model sends an empty string.
|
|
252
|
-
const inputJson = tool.params === "" ? "{}" : tool.params
|
|
253
|
-
const params = JSON.parse(inputJson)
|
|
254
|
-
parts.push(
|
|
255
|
-
new AiResponse.ToolCallPart({
|
|
256
|
-
id: AiInput.ToolCallId.make(tool.id, constDisableValidation),
|
|
257
|
-
name: tool.name,
|
|
258
|
-
params
|
|
259
|
-
}, constDisableValidation)
|
|
260
|
-
)
|
|
261
|
-
delete toolCalls[chunk.index]
|
|
262
|
-
// eslint-disable-next-line no-empty
|
|
263
|
-
} catch {}
|
|
264
|
-
}
|
|
265
|
-
if (Predicate.isNotUndefined(reasoning)) {
|
|
266
|
-
parts.push(
|
|
267
|
-
new AiResponse.ReasoningPart({
|
|
268
|
-
reasoningText: reasoning.content.join(""),
|
|
269
|
-
signature: reasoning.signature
|
|
270
|
-
}, constDisableValidation)
|
|
271
|
-
)
|
|
272
|
-
reasoning = undefined
|
|
273
|
-
}
|
|
274
|
-
break
|
|
275
|
-
}
|
|
276
|
-
case "error": {
|
|
277
|
-
return Option.some(
|
|
278
|
-
Effect.die(
|
|
279
|
-
new AiError.AiError({
|
|
280
|
-
module: "AnthropicClient",
|
|
281
|
-
method: "stream",
|
|
282
|
-
description: `${chunk.error.type}: ${chunk.error.message}`
|
|
283
|
-
})
|
|
284
|
-
)
|
|
285
|
-
)
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return parts.length === 0
|
|
289
|
-
? Option.none()
|
|
290
|
-
: Option.some(
|
|
291
|
-
Effect.succeed(
|
|
292
|
-
AiResponse.AiResponse.make(
|
|
293
|
-
{ parts },
|
|
294
|
-
constDisableValidation
|
|
295
|
-
)
|
|
296
|
-
)
|
|
297
|
-
)
|
|
213
|
+
),
|
|
214
|
+
options.transformClient ? options.transformClient : identity
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
const client = Generated.make(httpClient, {
|
|
218
|
+
transformClient: (client) =>
|
|
219
|
+
AnthropicConfig.getOrUndefined.pipe(
|
|
220
|
+
Effect.map((config) => config?.transformClient ? config.transformClient(client) : client)
|
|
221
|
+
)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const streamRequest = <A, I, R>(
|
|
225
|
+
request: HttpClientRequest.HttpClientRequest,
|
|
226
|
+
schema: Schema.Schema<A, I, R>
|
|
227
|
+
): Stream.Stream<A, AiError.AiError, R> => {
|
|
228
|
+
const decodeEvents = Schema.decode(Schema.ChunkFromSelf(Schema.parseJson(schema)))
|
|
229
|
+
return httpClient.execute(request).pipe(
|
|
230
|
+
Effect.map((r) => r.stream),
|
|
231
|
+
Stream.unwrapScoped,
|
|
232
|
+
Stream.decodeText(),
|
|
233
|
+
Stream.pipeThroughChannel(Sse.makeChannel()),
|
|
234
|
+
Stream.mapChunksEffect((chunk) => decodeEvents(Chunk.map(chunk, (event) => event.data))),
|
|
235
|
+
Stream.catchTags({
|
|
236
|
+
RequestError: (error) =>
|
|
237
|
+
AiError.HttpRequestError.fromRequestError({
|
|
238
|
+
module: "AnthropicClient",
|
|
239
|
+
method: "streamRequest",
|
|
240
|
+
error
|
|
241
|
+
}),
|
|
242
|
+
ResponseError: (error) =>
|
|
243
|
+
AiError.HttpResponseError.fromResponseError({
|
|
244
|
+
module: "AnthropicClient",
|
|
245
|
+
method: "streamRequest",
|
|
246
|
+
error
|
|
247
|
+
}),
|
|
248
|
+
ParseError: (error) =>
|
|
249
|
+
AiError.MalformedOutput.fromParseError({
|
|
250
|
+
module: "AnthropicClient",
|
|
251
|
+
method: "streamRequest",
|
|
252
|
+
error
|
|
298
253
|
})
|
|
299
|
-
)
|
|
300
254
|
})
|
|
301
|
-
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const createMessage: (options: {
|
|
259
|
+
readonly params?: typeof Generated.BetaMessagesPostParams.Encoded | undefined
|
|
260
|
+
readonly payload: typeof Generated.BetaCreateMessageParams.Encoded
|
|
261
|
+
}) => Effect.Effect<Generated.BetaMessage, AiError.AiError> = Effect.fnUntraced(
|
|
262
|
+
function*(options) {
|
|
263
|
+
return yield* client.betaMessagesPost(options).pipe(
|
|
264
|
+
Effect.catchTags({
|
|
265
|
+
RequestError: (error) =>
|
|
266
|
+
AiError.HttpRequestError.fromRequestError({
|
|
267
|
+
module: "AnthropicClient",
|
|
268
|
+
method: "createMessage",
|
|
269
|
+
error
|
|
270
|
+
}),
|
|
271
|
+
ResponseError: (error) =>
|
|
272
|
+
AiError.HttpResponseError.fromResponseError({
|
|
273
|
+
module: "AnthropicClient",
|
|
274
|
+
method: "createMessage",
|
|
275
|
+
error
|
|
276
|
+
}),
|
|
277
|
+
BetaErrorResponse: (error) =>
|
|
278
|
+
new AiError.HttpResponseError({
|
|
279
|
+
module: "AnthropicClient",
|
|
280
|
+
method: "createMessage",
|
|
281
|
+
cause: error.cause,
|
|
282
|
+
reason: "StatusCode",
|
|
283
|
+
request: {
|
|
284
|
+
hash: error.request.hash,
|
|
285
|
+
headers: error.request.headers,
|
|
286
|
+
method: error.request.method,
|
|
287
|
+
url: error.request.url,
|
|
288
|
+
urlParams: error.request.urlParams
|
|
289
|
+
},
|
|
290
|
+
response: {
|
|
291
|
+
headers: error.response.headers,
|
|
292
|
+
status: error.response.status
|
|
293
|
+
}
|
|
294
|
+
}),
|
|
295
|
+
ParseError: (error) =>
|
|
296
|
+
AiError.MalformedOutput.fromParseError({
|
|
297
|
+
module: "AnthropicClient",
|
|
298
|
+
method: "createMessage",
|
|
299
|
+
error
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
)
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
const createMessageStream = (options: {
|
|
307
|
+
readonly params?: typeof Generated.BetaMessagesPostParams.Encoded | undefined
|
|
308
|
+
readonly payload: Omit<typeof Generated.BetaCreateMessageParams.Encoded, "stream">
|
|
309
|
+
}): Stream.Stream<MessageStreamEvent, AiError.AiError> => {
|
|
310
|
+
const request = HttpClientRequest.post("/v1/messages", {
|
|
311
|
+
headers: Headers.fromInput({
|
|
312
|
+
"anthropic-beta": options.params?.["anthropic-beta"] ?? undefined
|
|
313
|
+
}),
|
|
314
|
+
body: HttpBody.unsafeJson({ ...options.payload, stream: true })
|
|
315
|
+
})
|
|
316
|
+
return streamRequest(request, MessageStreamEvent).pipe(
|
|
317
|
+
Stream.takeUntil((event) => event.type === "message_stop")
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return AnthropicClient.of({
|
|
322
|
+
client,
|
|
323
|
+
streamRequest,
|
|
324
|
+
createMessage,
|
|
325
|
+
createMessageStream
|
|
302
326
|
})
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// =============================================================================
|
|
330
|
+
// Message Stream Schema
|
|
331
|
+
// =============================================================================
|
|
303
332
|
|
|
304
333
|
/**
|
|
305
334
|
* @since 1.0.0
|
|
306
|
-
* @category
|
|
335
|
+
* @category Schemas
|
|
307
336
|
*/
|
|
308
|
-
export
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}): Layer.Layer<AnthropicClient, never, HttpClient.HttpClient> => Layer.effect(AnthropicClient, make(options))
|
|
337
|
+
export class PingEvent extends Schema.Class<PingEvent>(
|
|
338
|
+
"@effect/ai-anthropic/PingEvent"
|
|
339
|
+
)({
|
|
340
|
+
type: Schema.Literal("ping")
|
|
341
|
+
}) {}
|
|
314
342
|
|
|
315
343
|
/**
|
|
316
344
|
* @since 1.0.0
|
|
317
|
-
* @category
|
|
345
|
+
* @category Schemas
|
|
318
346
|
*/
|
|
319
|
-
export
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
347
|
+
export class ErrorEvent extends Schema.Class<ErrorEvent>(
|
|
348
|
+
"@effect/ai-anthropic/ErrorEvent"
|
|
349
|
+
)({
|
|
350
|
+
type: Schema.Literal("error"),
|
|
351
|
+
error: Schema.Struct({
|
|
352
|
+
type: Schema.Literal(
|
|
353
|
+
"invalid_request_error",
|
|
354
|
+
"authentication_error",
|
|
355
|
+
"permission_error",
|
|
356
|
+
"not_found_error",
|
|
357
|
+
"request_too_large",
|
|
358
|
+
"rate_limit_error",
|
|
359
|
+
"api_error",
|
|
360
|
+
"overloaded_error"
|
|
361
|
+
),
|
|
362
|
+
message: Schema.String
|
|
363
|
+
})
|
|
364
|
+
}) {}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* @since 1.0.0
|
|
368
|
+
* @category Schemas
|
|
369
|
+
*/
|
|
370
|
+
export class MessageStartEvent extends Schema.Class<MessageStartEvent>(
|
|
371
|
+
"@effect/ai-anthropic/MessageStartEvent"
|
|
372
|
+
)({
|
|
373
|
+
type: Schema.Literal("message_start"),
|
|
374
|
+
message: Generated.BetaMessage
|
|
375
|
+
}) {}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @since 1.0.0
|
|
379
|
+
* @category Schemas
|
|
380
|
+
*/
|
|
381
|
+
export class ServerToolUsage extends Schema.Class<ServerToolUsage>(
|
|
382
|
+
"@effect/ai-anthropic/ServerToolUsage"
|
|
383
|
+
)({
|
|
384
|
+
/**
|
|
385
|
+
* The number of web search tool requests.
|
|
386
|
+
*/
|
|
387
|
+
web_search_requests: Schema.optionalWith(
|
|
388
|
+
Schema.NullOr(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))),
|
|
389
|
+
{ default: () => 0 }
|
|
331
390
|
)
|
|
332
|
-
}
|
|
391
|
+
}) {}
|
|
333
392
|
|
|
334
393
|
/**
|
|
335
394
|
* @since 1.0.0
|
|
336
|
-
* @category
|
|
395
|
+
* @category Schemas
|
|
337
396
|
*/
|
|
338
|
-
export
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
397
|
+
export class MessageDelta extends Schema.Class<MessageDelta>(
|
|
398
|
+
"@effect/ai-anthropic/MessageDelta"
|
|
399
|
+
)({
|
|
400
|
+
stop_reason: Schema.optionalWith(
|
|
401
|
+
Schema.NullOr(
|
|
402
|
+
Schema.Literal(
|
|
403
|
+
"end_turn",
|
|
404
|
+
"max_tokens",
|
|
405
|
+
"stop_sequence",
|
|
406
|
+
"tool_use",
|
|
407
|
+
"pause_turn",
|
|
408
|
+
"refusal"
|
|
409
|
+
)
|
|
410
|
+
),
|
|
411
|
+
{ default: () => null }
|
|
412
|
+
),
|
|
413
|
+
stop_sequence: Schema.optionalWith(
|
|
414
|
+
Schema.NullOr(Schema.String),
|
|
415
|
+
{ default: () => null }
|
|
416
|
+
)
|
|
417
|
+
}) {}
|
|
356
418
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
419
|
+
/**
|
|
420
|
+
* @since 1.0.0
|
|
421
|
+
* @category Schemas
|
|
422
|
+
*/
|
|
423
|
+
export class MessageDeltaUsage extends Schema.Class<MessageDeltaUsage>(
|
|
424
|
+
"@effect/ai-anthropic/MessageDeltaUsage"
|
|
425
|
+
)({
|
|
426
|
+
/**
|
|
427
|
+
* The cumulative number of input tokens which were used.
|
|
428
|
+
*/
|
|
429
|
+
input_tokens: Schema.optionalWith(
|
|
430
|
+
Schema.NullOr(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))),
|
|
431
|
+
{ default: () => null }
|
|
432
|
+
),
|
|
433
|
+
/**
|
|
434
|
+
* The cumulative number of output tokens which were used.
|
|
435
|
+
*/
|
|
436
|
+
output_tokens: Schema.optionalWith(
|
|
437
|
+
Schema.NullOr(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))),
|
|
438
|
+
{ default: () => null }
|
|
439
|
+
),
|
|
440
|
+
/**
|
|
441
|
+
* The cumulative number of input tokens used to create the cache entry.
|
|
442
|
+
*/
|
|
443
|
+
cache_creation_input_tokens: Schema.optionalWith(
|
|
444
|
+
Schema.NullOr(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))),
|
|
445
|
+
{ default: () => null }
|
|
446
|
+
),
|
|
447
|
+
/**
|
|
448
|
+
* The cumulative number of input tokens read from the cache.
|
|
449
|
+
*/
|
|
450
|
+
cache_read_input_tokens: Schema.optionalWith(
|
|
451
|
+
Schema.NullOr(Schema.Int.pipe(Schema.greaterThanOrEqualTo(0))),
|
|
452
|
+
{ default: () => null }
|
|
453
|
+
),
|
|
454
|
+
/**
|
|
455
|
+
* The number of server tool requests.
|
|
456
|
+
*/
|
|
457
|
+
server_tool_use: Schema.optionalWith(
|
|
458
|
+
Schema.NullOr(ServerToolUsage),
|
|
459
|
+
{ default: () => null }
|
|
460
|
+
)
|
|
461
|
+
}) {}
|
|
371
462
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
463
|
+
/**
|
|
464
|
+
* @since 1.0.0
|
|
465
|
+
* @category Schemas
|
|
466
|
+
*/
|
|
467
|
+
export class MessageDeltaEvent extends Schema.Class<MessageDeltaEvent>(
|
|
468
|
+
"@effect/ai-anthropic/MessageDeltaEvent"
|
|
469
|
+
)({
|
|
470
|
+
type: Schema.Literal("message_delta"),
|
|
471
|
+
delta: MessageDelta,
|
|
472
|
+
/**
|
|
473
|
+
* Billing and rate-limit usage.
|
|
474
|
+
*
|
|
475
|
+
* Anthropic's API bills and rate-limits by token counts, as tokens represent
|
|
476
|
+
* the underlying cost to our systems.
|
|
477
|
+
*
|
|
478
|
+
* Under the hood, the API transforms requests into a format suitable for the
|
|
479
|
+
* model. The model's output then goes through a parsing stage before becoming
|
|
480
|
+
* an API response. As a result, the token counts in `usage` will not match
|
|
481
|
+
* one-to-one with the exact visible content of an API request or response.
|
|
482
|
+
*
|
|
483
|
+
* For example, `output_tokens` will be non-zero, even for an empty string
|
|
484
|
+
* response from Claude.\n\nTotal input tokens in a request is the summation
|
|
485
|
+
* of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`.
|
|
486
|
+
*/
|
|
487
|
+
usage: MessageDeltaUsage
|
|
488
|
+
}) {}
|
|
375
489
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
490
|
+
/**
|
|
491
|
+
* @since 1.0.0
|
|
492
|
+
* @category Schemas
|
|
493
|
+
*/
|
|
494
|
+
export class MessageStopEvent extends Schema.Class<MessageStopEvent>(
|
|
495
|
+
"@effect/ai-anthropic/MessageStopEvent"
|
|
496
|
+
)({
|
|
497
|
+
type: Schema.Literal("message_stop")
|
|
498
|
+
}) {}
|
|
381
499
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
500
|
+
/**
|
|
501
|
+
* @since 1.0.0
|
|
502
|
+
* @category Schemas
|
|
503
|
+
*/
|
|
504
|
+
export class ContentBlockStartEvent extends Schema.Class<ContentBlockStartEvent>(
|
|
505
|
+
"@effect/ai-anthropic/ContentBlockStartEvent"
|
|
506
|
+
)({
|
|
507
|
+
type: Schema.Literal("content_block_start"),
|
|
508
|
+
index: Schema.Int,
|
|
509
|
+
content_block: Generated.BetaContentBlock
|
|
510
|
+
}) {}
|
|
392
511
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
512
|
+
/**
|
|
513
|
+
* @since 1.0.0
|
|
514
|
+
* @category Schemas
|
|
515
|
+
*/
|
|
516
|
+
export class CitationsDelta extends Schema.Class<CitationsDelta>(
|
|
517
|
+
"@effect/ai-anthropic/CitationsDelta"
|
|
518
|
+
)({
|
|
519
|
+
type: Schema.Literal("citations_delta"),
|
|
520
|
+
citation: Schema.Union(
|
|
521
|
+
Generated.BetaResponseCharLocationCitation,
|
|
522
|
+
Generated.BetaResponsePageLocationCitation,
|
|
523
|
+
Generated.BetaResponseContentBlockLocationCitation,
|
|
524
|
+
Generated.BetaResponseWebSearchResultLocationCitation,
|
|
525
|
+
Generated.BetaResponseSearchResultLocationCitation
|
|
526
|
+
)
|
|
527
|
+
}) {}
|
|
399
528
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
529
|
+
/**
|
|
530
|
+
* @since 1.0.0
|
|
531
|
+
* @category Schemas
|
|
532
|
+
*/
|
|
533
|
+
export class InputJsonContentBlockDelta extends Schema.Class<InputJsonContentBlockDelta>(
|
|
534
|
+
"@effect/ai-anthropic/InputJsonContentBlockDelta"
|
|
535
|
+
)({
|
|
536
|
+
type: Schema.Literal("input_json_delta"),
|
|
537
|
+
partial_json: Schema.String
|
|
538
|
+
}) {}
|
|
404
539
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
540
|
+
/**
|
|
541
|
+
* @since 1.0.0
|
|
542
|
+
* @category Schemas
|
|
543
|
+
*/
|
|
544
|
+
export class SignatureContentBlockDelta extends Schema.Class<SignatureContentBlockDelta>(
|
|
545
|
+
"@effect/ai-anthropic/SignatureContentBlockDelta"
|
|
546
|
+
)({
|
|
547
|
+
type: Schema.Literal("signature_delta"),
|
|
548
|
+
signature: Schema.String
|
|
549
|
+
}) {}
|
|
409
550
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
551
|
+
/**
|
|
552
|
+
* @since 1.0.0
|
|
553
|
+
* @category Schemas
|
|
554
|
+
*/
|
|
555
|
+
export class TextContentBlockDelta extends Schema.Class<TextContentBlockDelta>(
|
|
556
|
+
"@effect/ai-anthropic/TextContentBlockDelta"
|
|
557
|
+
)({
|
|
558
|
+
type: Schema.Literal("text_delta"),
|
|
559
|
+
text: Schema.String
|
|
560
|
+
}) {}
|
|
414
561
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
562
|
+
/**
|
|
563
|
+
* @since 1.0.0
|
|
564
|
+
* @category Schemas
|
|
565
|
+
*/
|
|
566
|
+
export class ThinkingContentBlockDelta extends Schema.Class<ThinkingContentBlockDelta>(
|
|
567
|
+
"@effect/ai-anthropic/ThinkingContentBlockDelta"
|
|
568
|
+
)({
|
|
569
|
+
type: Schema.Literal("thinking_delta"),
|
|
570
|
+
thinking: Schema.String
|
|
571
|
+
}) {}
|
|
419
572
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
573
|
+
/**
|
|
574
|
+
* @since 1.0.0
|
|
575
|
+
* @category Schemas
|
|
576
|
+
*/
|
|
577
|
+
export class ContentBlockDeltaEvent extends Schema.Class<ContentBlockDeltaEvent>(
|
|
578
|
+
"@effect/ai-anthropic/ContentBlockDeltaEvent"
|
|
579
|
+
)({
|
|
580
|
+
type: Schema.Literal("content_block_delta"),
|
|
581
|
+
index: Schema.Int,
|
|
582
|
+
delta: Schema.Union(
|
|
583
|
+
CitationsDelta,
|
|
584
|
+
InputJsonContentBlockDelta,
|
|
585
|
+
SignatureContentBlockDelta,
|
|
586
|
+
TextContentBlockDelta,
|
|
587
|
+
ThinkingContentBlockDelta
|
|
588
|
+
)
|
|
589
|
+
}) {}
|
|
424
590
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
591
|
+
/**
|
|
592
|
+
* @since 1.0.0
|
|
593
|
+
* @category Schemas
|
|
594
|
+
*/
|
|
595
|
+
export class ContentBlockStopEvent extends Schema.Class<ContentBlockStopEvent>(
|
|
596
|
+
"@effect/ai-anthropic/ContentBlockStopEvent"
|
|
597
|
+
)({
|
|
598
|
+
type: Schema.Literal("content_block_stop"),
|
|
599
|
+
index: Schema.Int
|
|
600
|
+
}) {}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* @since 1.0.0
|
|
604
|
+
* @category Schemas
|
|
605
|
+
*/
|
|
606
|
+
export const MessageStreamEvent = Schema.Union(
|
|
607
|
+
PingEvent,
|
|
608
|
+
ErrorEvent,
|
|
609
|
+
MessageStartEvent,
|
|
610
|
+
MessageDeltaEvent,
|
|
611
|
+
MessageStopEvent,
|
|
612
|
+
ContentBlockStartEvent,
|
|
613
|
+
ContentBlockDeltaEvent,
|
|
614
|
+
ContentBlockStopEvent
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* @since 1.0.0
|
|
619
|
+
* @category Models
|
|
620
|
+
*/
|
|
621
|
+
export type MessageStreamEvent = typeof MessageStreamEvent.Type
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* @since 1.0.0
|
|
625
|
+
* @category Layers
|
|
626
|
+
*/
|
|
627
|
+
export const layer = (options: {
|
|
628
|
+
/**
|
|
629
|
+
* The API key that will be used to authenticate with Anthropic's API.
|
|
630
|
+
*
|
|
631
|
+
* The key is wrapped in a `Redacted` type to prevent accidental logging or
|
|
632
|
+
* exposure in debugging output, helping maintain security best practices.
|
|
633
|
+
*
|
|
634
|
+
* The key is automatically included in the `x-api-key` header for all API
|
|
635
|
+
* requests made through this client, which is automatically redacted in logs
|
|
636
|
+
* output by Effect loggers.
|
|
637
|
+
*
|
|
638
|
+
* Leave `undefined` if authentication will be handled through other means
|
|
639
|
+
* (e.g., environment-based authentication, proxy authentication, or when
|
|
640
|
+
* using a mock server that doesn't require authentication).
|
|
641
|
+
*/
|
|
642
|
+
readonly apiKey?: Redacted.Redacted | undefined
|
|
643
|
+
/**
|
|
644
|
+
* The base URL endpoint used to communicate with Anthropic's API.
|
|
645
|
+
*
|
|
646
|
+
* This property determines the HTTP destination for all API requests made by
|
|
647
|
+
* this client.
|
|
648
|
+
*
|
|
649
|
+
* Defaults to `"https://api.anthropic.com"`.
|
|
650
|
+
*
|
|
651
|
+
* Override this value when you need to:
|
|
652
|
+
* - Point to a different Anthropic environment (e.g., staging or sandbox
|
|
653
|
+
* servers).
|
|
654
|
+
* - Use a proxy between your application and Anthropic's API for security,
|
|
655
|
+
* caching, or logging.
|
|
656
|
+
* - Employ a mock server for local development or testing.
|
|
657
|
+
*
|
|
658
|
+
* You may leave this property `undefined` to accept the default value.
|
|
659
|
+
*/
|
|
660
|
+
readonly apiUrl?: string | undefined
|
|
661
|
+
/**
|
|
662
|
+
* The Anthropic API version to use for requests.
|
|
663
|
+
*
|
|
664
|
+
* This version string determines which API schema and features are available
|
|
665
|
+
* for your requests. Different versions may have different capabilities,
|
|
666
|
+
* request/response formats, or available models.
|
|
667
|
+
*
|
|
668
|
+
* Defaults to `"2023-06-01"`.
|
|
669
|
+
*
|
|
670
|
+
* You should specify a version that:
|
|
671
|
+
* - Supports the features and models you need
|
|
672
|
+
* - Is stable and well-tested for your use case
|
|
673
|
+
* - Matches your application's integration requirements
|
|
674
|
+
*
|
|
675
|
+
* Consult Anthropic's API documentation for available versions and their
|
|
676
|
+
* differences.
|
|
677
|
+
*/
|
|
678
|
+
readonly anthropicVersion?: string | undefined
|
|
679
|
+
/**
|
|
680
|
+
* A function to transform the underlying HTTP client before it's used for API requests.
|
|
681
|
+
*
|
|
682
|
+
* This transformation function receives the configured HTTP client and returns
|
|
683
|
+
* a modified version. It's applied after all standard client configuration
|
|
684
|
+
* (authentication, base URL, headers) but before any requests are made.
|
|
685
|
+
*
|
|
686
|
+
* Use this for:
|
|
687
|
+
* - Adding custom middleware (logging, metrics, caching)
|
|
688
|
+
* - Modifying request/response processing behavior
|
|
689
|
+
* - Adding custom retry logic or error handling
|
|
690
|
+
* - Integrating with monitoring or debugging tools
|
|
691
|
+
* - Applying organization-specific HTTP client policies
|
|
692
|
+
*
|
|
693
|
+
* The transformation is applied once during client initialization and affects
|
|
694
|
+
* all subsequent API requests made through this client instance.
|
|
695
|
+
*
|
|
696
|
+
* Leave `undefined` if no custom HTTP client behavior is needed.
|
|
697
|
+
*/
|
|
698
|
+
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
699
|
+
}): Layer.Layer<AnthropicClient, never, HttpClient.HttpClient> => Layer.scoped(AnthropicClient, make(options))
|
|
440
700
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
701
|
+
/**
|
|
702
|
+
* @since 1.0.0
|
|
703
|
+
* @category Layers
|
|
704
|
+
*/
|
|
705
|
+
export const layerConfig = (options: {
|
|
706
|
+
/**
|
|
707
|
+
* The API key that will be used to authenticate with Anthropic's API.
|
|
708
|
+
*
|
|
709
|
+
* The key is wrapped in a `Redacted` type to prevent accidental logging or
|
|
710
|
+
* exposure in debugging output, helping maintain security best practices.
|
|
711
|
+
*
|
|
712
|
+
* The key is automatically included in the `x-api-key` header for all API
|
|
713
|
+
* requests made through this client, which is automatically redacted in logs
|
|
714
|
+
* output by Effect loggers.
|
|
715
|
+
*
|
|
716
|
+
* Leave `undefined` if authentication will be handled through other means
|
|
717
|
+
* (e.g., environment-based authentication, proxy authentication, or when
|
|
718
|
+
* using a mock server that doesn't require authentication).
|
|
719
|
+
*/
|
|
720
|
+
readonly apiKey?: Config.Config<Redacted.Redacted | undefined> | undefined
|
|
721
|
+
/**
|
|
722
|
+
* The base URL endpoint used to communicate with Anthropic's API.
|
|
723
|
+
*
|
|
724
|
+
* This property determines the HTTP destination for all API requests made by
|
|
725
|
+
* this client.
|
|
726
|
+
*
|
|
727
|
+
* Defaults to `"https://api.anthropic.com"`.
|
|
728
|
+
*
|
|
729
|
+
* Override this value when you need to:
|
|
730
|
+
* - Point to a different Anthropic environment (e.g., staging or sandbox
|
|
731
|
+
* servers).
|
|
732
|
+
* - Use a proxy between your application and Anthropic's API for security,
|
|
733
|
+
* caching, or logging.
|
|
734
|
+
* - Employ a mock server for local development or testing.
|
|
735
|
+
*
|
|
736
|
+
* You may leave this property `undefined` to accept the default value.
|
|
737
|
+
*/
|
|
738
|
+
readonly apiUrl?: Config.Config<string | undefined> | undefined
|
|
739
|
+
/**
|
|
740
|
+
* The Anthropic API version to use for requests.
|
|
741
|
+
*
|
|
742
|
+
* This version string determines which API schema and features are available
|
|
743
|
+
* for your requests. Different versions may have different capabilities,
|
|
744
|
+
* request/response formats, or available models.
|
|
745
|
+
*
|
|
746
|
+
* Defaults to `"2023-06-01"`.
|
|
747
|
+
*
|
|
748
|
+
* You should specify a version that:
|
|
749
|
+
* - Supports the features and models you need
|
|
750
|
+
* - Is stable and well-tested for your use case
|
|
751
|
+
* - Matches your application's integration requirements
|
|
752
|
+
*
|
|
753
|
+
* Consult Anthropic's API documentation for available versions and their
|
|
754
|
+
* differences.
|
|
755
|
+
*/
|
|
756
|
+
readonly anthropicVersion?: Config.Config<string | undefined> | undefined
|
|
757
|
+
/**
|
|
758
|
+
* A function to transform the underlying HTTP client before it's used for API requests.
|
|
759
|
+
*
|
|
760
|
+
* This transformation function receives the configured HTTP client and returns
|
|
761
|
+
* a modified version. It's applied after all standard client configuration
|
|
762
|
+
* (authentication, base URL, headers) but before any requests are made.
|
|
763
|
+
*
|
|
764
|
+
* Use this for:
|
|
765
|
+
* - Adding custom middleware (logging, metrics, caching)
|
|
766
|
+
* - Modifying request/response processing behavior
|
|
767
|
+
* - Adding custom retry logic or error handling
|
|
768
|
+
* - Integrating with monitoring or debugging tools
|
|
769
|
+
* - Applying organization-specific HTTP client policies
|
|
770
|
+
*
|
|
771
|
+
* The transformation is applied once during client initialization and affects
|
|
772
|
+
* all subsequent API requests made through this client instance.
|
|
773
|
+
*
|
|
774
|
+
* Leave `undefined` if no custom HTTP client behavior is needed.
|
|
775
|
+
*/
|
|
776
|
+
readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined
|
|
777
|
+
}): Layer.Layer<AnthropicClient, ConfigError, HttpClient.HttpClient> => {
|
|
778
|
+
const { transformClient, ...configs } = options
|
|
779
|
+
return Config.all(configs).pipe(
|
|
780
|
+
Effect.flatMap((configs) => make({ ...configs, transformClient })),
|
|
781
|
+
Layer.scoped(AnthropicClient)
|
|
782
|
+
)
|
|
445
783
|
}
|