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