@effect-agent/ai-typesafe 0.1.0-beta.104 → 0.1.0-beta.107
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/README.md +11 -7
- package/dist/{TypeSafeClient-SjzPX2Gl.mjs → TypeSafeClient-DTNc_B47.mjs} +31 -25
- package/dist/TypeSafeClient-DTNc_B47.mjs.map +1 -0
- package/dist/TypeSafeClient.d.mts +22 -24
- package/dist/TypeSafeClient.mjs +2 -2
- package/dist/TypeSafeDecisionModel.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/TypeSafeClient.ts +77 -79
- package/dist/TypeSafeClient-SjzPX2Gl.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @effect-agent/ai-typesafe
|
|
2
2
|
|
|
3
3
|
Use Jev to evaluate typed questions with Effect. `TypeSafeDecisionModel` supplies the
|
|
4
|
-
provider for [`@effect-agent/ai-decision`](../ai-decision); `TypeSafeClient`
|
|
5
|
-
configuration and also exposes Jev's API directly.
|
|
4
|
+
provider for [`@effect-agent/ai-decision`](../ai-decision); `TypeSafeClient` requires
|
|
5
|
+
configuration and an HttpClient, and also exposes Jev's API directly.
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
8
|
DecisionModel → TypeSafeDecisionModel → TypeSafeClient → Jev
|
|
@@ -16,16 +16,20 @@ import { Layer } from "effect";
|
|
|
16
16
|
import { FetchHttpClient } from "effect/unstable/http";
|
|
17
17
|
|
|
18
18
|
const DecisionLive = TypeSafeDecisionModel.model("jev-latest").pipe(
|
|
19
|
-
Layer.provide(TypeSafeClient.
|
|
19
|
+
Layer.provide(TypeSafeClient.layer),
|
|
20
|
+
Layer.provide(TypeSafeClient.Config.layer),
|
|
21
|
+
Layer.provide(FetchHttpClient.layer),
|
|
20
22
|
);
|
|
21
23
|
```
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
`TypeSafeClient.Config.layer` reads `TYPESAFE_API_KEY` and optional `TYPESAFE_API_URL`.
|
|
26
|
+
Provide your own `TypeSafeClient.Config` layer to use application-owned configuration.
|
|
27
|
+
Provide `DecisionLive` to the Effect that evaluates your decision set.
|
|
28
|
+
The adapter maps shared `probability` questions to Jev's `noul` and retains
|
|
25
29
|
choice and score distributions. Application code chooses how to use the answers.
|
|
26
30
|
|
|
27
|
-
There are no default retries or deadlines. Add those policies with Effect or the
|
|
28
|
-
|
|
31
|
+
There are no default retries or deadlines. Add those policies with Effect or to the supplied
|
|
32
|
+
HttpClient. See the [configuration and error reference](https://effect-agent.com/reference/decision-models#typesafe-client)
|
|
29
33
|
for details, including Jev's [rounded probabilities](https://effect-agent.com/reference/decision-models#probability-validation).
|
|
30
34
|
|
|
31
35
|
## Examples
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { ChoiceAnswer, EvaluateRequest, EvaluateResponse, NoulAnswer, Probability, ScoreAnswer } from "./TypeSafeSchema.mjs";
|
|
3
|
-
import * as
|
|
3
|
+
import * as EffectConfig from "effect/Config";
|
|
4
4
|
import * as Context from "effect/Context";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
|
-
import { flow
|
|
6
|
+
import { flow } from "effect/Function";
|
|
7
7
|
import * as Layer from "effect/Layer";
|
|
8
8
|
import * as Redacted from "effect/Redacted";
|
|
9
9
|
import * as Schema from "effect/Schema";
|
|
@@ -137,27 +137,47 @@ function responseFor(questions) {
|
|
|
137
137
|
* @since 0.1.0
|
|
138
138
|
*/
|
|
139
139
|
var TypeSafeClient_exports = /* @__PURE__ */ __exportAll({
|
|
140
|
+
Config: () => Config,
|
|
140
141
|
TypeSafeClient: () => TypeSafeClient,
|
|
141
142
|
layer: () => layer,
|
|
142
|
-
layerConfig: () => layerConfig,
|
|
143
143
|
make: () => make
|
|
144
144
|
});
|
|
145
145
|
/** @category services
|
|
146
146
|
* @since 0.1.0
|
|
147
147
|
*/
|
|
148
148
|
var TypeSafeClient = class extends Context.Service()("@effect-agent/ai-typesafe/TypeSafeClient") {};
|
|
149
|
+
const defaultApiUrl = "https://api.typesafe.ai/v1";
|
|
150
|
+
/**
|
|
151
|
+
* Configuration captured when the client is acquired. Supply this service from
|
|
152
|
+
* application configuration or use `Config.layer` to load environment values.
|
|
153
|
+
*
|
|
154
|
+
* @category services
|
|
155
|
+
* @since 0.1.0
|
|
156
|
+
*/
|
|
157
|
+
var Config = class Config extends Context.Service()("@effect-agent/ai-typesafe/TypeSafeClient/Config") {
|
|
158
|
+
/**
|
|
159
|
+
* Load `TYPESAFE_API_KEY` and optional `TYPESAFE_API_URL` through Effect Config.
|
|
160
|
+
* Missing credentials fail with ConfigError before any HTTP request.
|
|
161
|
+
*/
|
|
162
|
+
static layer = Layer.effect(Config, EffectConfig.all({
|
|
163
|
+
apiKey: EffectConfig.Redacted("TYPESAFE_API_KEY"),
|
|
164
|
+
apiUrl: EffectConfig.String("TYPESAFE_API_URL").pipe(EffectConfig.withDefault(defaultApiUrl))
|
|
165
|
+
}));
|
|
166
|
+
};
|
|
149
167
|
const encodeRequest = Schema.encodeEffect(Schema.fromJsonString(EvaluateRequest));
|
|
150
168
|
/**
|
|
151
|
-
*
|
|
152
|
-
* Acquiring the service does not send a request.
|
|
169
|
+
* Capture Config and a platform-neutral HttpClient at construction.
|
|
170
|
+
* Acquiring the service does not send a request. Apply HTTP policies to the
|
|
171
|
+
* supplied HttpClient; its request middleware receives authenticated, absolute URLs.
|
|
153
172
|
*
|
|
154
173
|
* @category constructors
|
|
155
174
|
* @since 0.1.0
|
|
156
175
|
*/
|
|
157
|
-
const make = Effect.
|
|
158
|
-
const
|
|
176
|
+
const make = Effect.gen(function* () {
|
|
177
|
+
const config = yield* Config;
|
|
178
|
+
const apiKey = Redacted.value(config.apiKey);
|
|
159
179
|
const redact = (text) => apiKey.length === 0 ? text : text.replaceAll(apiKey, "<redacted>");
|
|
160
|
-
const client = (yield* HttpClient.HttpClient).pipe(HttpClient.
|
|
180
|
+
const client = (yield* HttpClient.HttpClient).pipe(HttpClient.mapRequestInput(flow(HttpClientRequest.prependUrl(config.apiUrl ?? defaultApiUrl), HttpClientRequest.bearerToken(config.apiKey), HttpClientRequest.acceptJson)), HttpClient.filterStatusOk);
|
|
161
181
|
const evaluate = Effect.fnUntraced(function* (options) {
|
|
162
182
|
const body = yield* encodeRequest(options).pipe(Effect.mapError((error) => make$1(new AiError.InvalidRequestError({ description: redact(error.message) }))));
|
|
163
183
|
const schema = responseFor(options.questions);
|
|
@@ -174,22 +194,8 @@ const make = Effect.fnUntraced(function* (options) {
|
|
|
174
194
|
/** @category layers
|
|
175
195
|
* @since 0.1.0
|
|
176
196
|
*/
|
|
177
|
-
const layer =
|
|
178
|
-
/**
|
|
179
|
-
* Configure the client with Effect Config. The API key defaults to
|
|
180
|
-
* `Config.Redacted("TYPESAFE_API_KEY")`.
|
|
181
|
-
*
|
|
182
|
-
* @category layers
|
|
183
|
-
* @since 0.1.0
|
|
184
|
-
*/
|
|
185
|
-
const layerConfig = (options) => Layer.effect(TypeSafeClient, Effect.gen(function* () {
|
|
186
|
-
return yield* make({
|
|
187
|
-
apiKey: yield* options?.apiKey ?? Config.Redacted("TYPESAFE_API_KEY"),
|
|
188
|
-
apiUrl: options?.apiUrl === void 0 ? void 0 : yield* options.apiUrl,
|
|
189
|
-
transformClient: options?.transformClient
|
|
190
|
-
});
|
|
191
|
-
}));
|
|
197
|
+
const layer = Layer.effect(TypeSafeClient, make);
|
|
192
198
|
//#endregion
|
|
193
|
-
export { make as a,
|
|
199
|
+
export { make as a, layer as i, TypeSafeClient as n, choiceProbabilitySum as o, TypeSafeClient_exports as r, Config as t };
|
|
194
200
|
|
|
195
|
-
//# sourceMappingURL=TypeSafeClient-
|
|
201
|
+
//# sourceMappingURL=TypeSafeClient-DTNc_B47.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeSafeClient-DTNc_B47.mjs","names":["make","TypeSafeSchema.Probability","TypeSafeSchema.NoulAnswer","TypeSafeSchema.EvaluateRequest","Errors.make","Errors.mapHttpClientError","Errors.mapSchemaError"],"sources":["../src/internal/errors.ts","../src/internal/schema.ts","../src/TypeSafeClient.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Redacted from \"effect/Redacted\";\nimport type * as Schema from \"effect/Schema\";\nimport * as AiError from \"effect/unstable/ai/AiError\";\nimport * as Headers from \"effect/unstable/http/Headers\";\nimport type * as HttpClientError from \"effect/unstable/http/HttpClientError\";\n\nexport const make = (reason: AiError.AiErrorReason): AiError.AiError =>\n AiError.make({ module: \"TypeSafeClient\", method: \"evaluate\", reason });\n\nexport const mapSchemaError = (\n error: Schema.SchemaError,\n redact: (text: string) => string,\n): AiError.AiError => {\n const reason = AiError.InvalidOutputError.fromSchemaError(error);\n\n return make(\n new AiError.InvalidOutputError({ ...reason, description: redact(reason.description) }),\n );\n};\n\nconst redactRequest = (\n request: typeof AiError.HttpRequestDetails.Type,\n redact: (text: string) => string,\n): typeof AiError.HttpRequestDetails.Type => ({\n ...request,\n url: redact(request.url),\n urlParams: request.urlParams.map(([key, value]) => [key, redact(value)]),\n hash: request.hash === undefined ? undefined : redact(request.hash),\n headers: Record.map(request.headers, (value) =>\n Redacted.isRedacted(value) ? \"<redacted>\" : redact(value),\n ),\n});\n\nexport const mapHttpClientError = Effect.fnUntraced(function* (\n error: HttpClientError.HttpClientError,\n redact: (text: string) => string,\n): Effect.fn.Return<never, AiError.AiError> {\n const reason = error.reason;\n\n switch (reason._tag) {\n case \"TransportError\":\n case \"EncodeError\":\n case \"InvalidUrlError\": {\n const network = AiError.NetworkError.fromRequestError(reason);\n\n return yield* make(\n new AiError.NetworkError({\n ...network,\n request: redactRequest(network.request, redact),\n description: network.description === undefined ? undefined : redact(network.description),\n }),\n );\n }\n case \"DecodeError\":\n case \"EmptyBodyError\":\n return yield* make(\n new AiError.InvalidOutputError({\n description: redact(reason.description ?? \"Could not decode the TypeSafe response body\"),\n }),\n );\n case \"StatusCodeError\": {\n const { request, response } = reason;\n const redactedNames = yield* Headers.CurrentRedactedNames;\n\n const headers = (value: Headers.Headers) =>\n Record.map(Headers.redact(value, redactedNames), (value) =>\n Redacted.isRedacted(value) ? \"<redacted>\" : redact(value),\n );\n\n const text = yield* Effect.option(response.text);\n const body = Option.isSome(text) ? redact(text.value) : undefined;\n\n const http: typeof AiError.HttpContext.Type = {\n request: {\n method: request.method,\n url: redact(request.url),\n urlParams: Array.from(request.urlParams, ([key, value]) => [key, redact(value)]),\n hash: Option.getOrUndefined(Option.map(request.hash, redact)),\n headers: headers(request.headers),\n },\n response: { status: response.status, headers: headers(response.headers) },\n body,\n };\n\n const description = AiError.buildErrorDescription({\n status: response.status,\n method: request.method,\n url: http.request.url,\n message: undefined,\n body,\n });\n\n return yield* make(\n response.status === 422\n ? new AiError.InvalidRequestError({ description, http })\n : AiError.reasonFromHttpStatus({ status: response.status, description, http }),\n );\n }\n }\n});\n","import * as Schema from \"effect/Schema\";\n\nimport * as TypeSafeSchema from \"../TypeSafeSchema.ts\";\n\n// Permit floating-point serialization error without changing provider values.\nconst tolerance = 1e-6;\n\nconst probabilitySum = Schema.makeFilter(\n (probabilities: Readonly<Record<string, number>>) =>\n Math.abs(Object.values(probabilities).reduce((sum, value) => sum + value, 0) - 1) <= tolerance,\n { expected: \"probabilities summing to 1 (within 1e-6)\" },\n);\n\n// Jev Choice responses have been observed with two-decimal probabilities totaling 0.99.\n// Limit compatibility to one percentage point, even for very large option catalogues.\n// Score sums/weighting retain their strict checks; no Score rounding contract is assumed.\nexport const choiceProbabilitySum = Schema.makeFilter(\n (probabilities: Readonly<Record<string, number>>) => {\n const values = Object.values(probabilities);\n const error = Math.abs(values.reduce((sum, value) => sum + value, 0) - 1);\n\n return (\n error <= tolerance ||\n (error <= Math.min(0.01, values.length * 0.005) + tolerance &&\n values.every((value) => Math.abs(value * 100 - Math.round(value * 100)) < 1e-8))\n );\n },\n { expected: \"probabilities summing to 1 within bounded two-decimal Choice rounding\" },\n);\n\nconst distribution = (keys: ReadonlyArray<string>, sumCheck = probabilitySum) =>\n Schema.Record(Schema.Literals(keys), TypeSafeSchema.Probability).check(sumCheck);\n\nconst answerFor = (question: TypeSafeSchema.Question) => {\n switch (question.type) {\n case \"choice\": {\n const keys = Object.keys(question.criteria);\n\n return Schema.Struct({\n ...TypeSafeSchema.ChoiceAnswer.fields,\n choice: Schema.Literals(keys),\n probabilities: distribution(keys, choiceProbabilitySum),\n }).check(\n Schema.makeFilter(\n ({ choice, probabilities }) =>\n Object.values(probabilities).every((value) => value <= probabilities[choice]),\n { expected: \"a highest-probability choice\" },\n ),\n );\n }\n case \"score\": {\n const maxLevel = question.criteria.length - 1;\n\n const levels = question.criteria.map(\n (description, index) => [String(index), description] as const,\n );\n\n return Schema.Struct({\n ...TypeSafeSchema.ScoreAnswer.fields,\n score: Schema.Finite.check(Schema.isBetween({ minimum: 0, maximum: maxLevel })),\n legend: Schema.Struct(\n Object.fromEntries(\n levels.map(([key, description]) => [key, Schema.Literal(description)]),\n ),\n ),\n probabilities: distribution(levels.map(([key]) => key)),\n }).check(\n Schema.makeFilter(\n ({ score, probabilities }) =>\n Math.abs(\n score -\n Object.entries(probabilities).reduce(\n (sum, [level, probability]) => sum + Number(level) * probability,\n 0,\n ),\n ) <=\n tolerance * Math.max(1, maxLevel),\n { expected: \"the probability-weighted score (within 1e-6 per level)\" },\n ),\n );\n }\n case \"noul\":\n return TypeSafeSchema.NoulAnswer;\n }\n};\n\n// The overload describes the dependent type enforced by the literal keys and\n// per-question schemas below. No JSON value is asserted to have that type.\nexport function responseFor<const Q extends TypeSafeSchema.Questions>(\n questions: Q,\n): Schema.Codec<TypeSafeSchema.EvaluateResponse<Q>>;\n\nexport function responseFor(questions: TypeSafeSchema.Questions): Schema.Top {\n return Schema.Struct({\n ...TypeSafeSchema.EvaluateResponse.fields,\n answers: Schema.Struct(\n Object.fromEntries(\n Object.entries(questions).map(([id, question]) => [id, answerFor(question)]),\n ),\n ),\n });\n}\n","/**\n * An Effect HttpClient integration for TypeSafe's System One evaluations.\n *\n * @since 0.1.0\n */\nimport * as EffectConfig from \"effect/Config\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport { flow } from \"effect/Function\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as Schema from \"effect/Schema\";\nimport * as AiError from \"effect/unstable/ai/AiError\";\nimport * as Headers from \"effect/unstable/http/Headers\";\nimport * as HttpClient from \"effect/unstable/http/HttpClient\";\nimport * as HttpClientRequest from \"effect/unstable/http/HttpClientRequest\";\nimport * as HttpClientResponse from \"effect/unstable/http/HttpClientResponse\";\n\nimport * as Errors from \"./internal/errors.ts\";\nimport { responseFor } from \"./internal/schema.ts\";\nimport * as TypeSafeSchema from \"./TypeSafeSchema.ts\";\n\n/** @category services\n * @since 0.1.0\n */\nexport interface Service {\n readonly client: HttpClient.HttpClient;\n\n /**\n * Evaluate mixed questions against one state. Answers are validated against\n * the submitted IDs, types, and criteria before receiving their inferred type.\n * There are no automatic retries or timeouts; compose those with Effect.\n */\n readonly evaluate: <const Q extends TypeSafeSchema.Questions>(\n options: TypeSafeSchema.EvaluateRequest<Q>,\n ) => Effect.Effect<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError>;\n}\n\n/** @category services\n * @since 0.1.0\n */\nexport class TypeSafeClient extends Context.Service<TypeSafeClient, Service>()(\n \"@effect-agent/ai-typesafe/TypeSafeClient\",\n) {}\n\nconst defaultApiUrl = \"https://api.typesafe.ai/v1\";\n\n/**\n * Configuration captured when the client is acquired. Supply this service from\n * application configuration or use `Config.layer` to load environment values.\n *\n * @category services\n * @since 0.1.0\n */\nexport class Config extends Context.Service<\n Config,\n {\n readonly apiKey: Redacted.Redacted<string>;\n /** Base URL, including the API version. Defaults to https://api.typesafe.ai/v1. */\n readonly apiUrl?: string | undefined;\n }\n>()(\"@effect-agent/ai-typesafe/TypeSafeClient/Config\") {\n /**\n * Load `TYPESAFE_API_KEY` and optional `TYPESAFE_API_URL` through Effect Config.\n * Missing credentials fail with ConfigError before any HTTP request.\n */\n static readonly layer: Layer.Layer<Config, EffectConfig.ConfigError> = Layer.effect(\n Config,\n EffectConfig.all({\n apiKey: EffectConfig.Redacted(\"TYPESAFE_API_KEY\"),\n apiUrl: EffectConfig.String(\"TYPESAFE_API_URL\").pipe(EffectConfig.withDefault(defaultApiUrl)),\n }),\n );\n}\n\nconst encodeRequest = Schema.encodeEffect(Schema.fromJsonString(TypeSafeSchema.EvaluateRequest));\n\n/**\n * Capture Config and a platform-neutral HttpClient at construction.\n * Acquiring the service does not send a request. Apply HTTP policies to the\n * supplied HttpClient; its request middleware receives authenticated, absolute URLs.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make: Effect.Effect<Service, never, Config | HttpClient.HttpClient> = Effect.gen(\n function* () {\n const config = yield* Config;\n const apiKey = Redacted.value(config.apiKey);\n\n const redact = (text: string) =>\n apiKey.length === 0 ? text : text.replaceAll(apiKey, \"<redacted>\");\n\n const client = (yield* HttpClient.HttpClient).pipe(\n HttpClient.mapRequestInput(\n flow(\n HttpClientRequest.prependUrl(config.apiUrl ?? defaultApiUrl),\n HttpClientRequest.bearerToken(config.apiKey),\n HttpClientRequest.acceptJson,\n ),\n ),\n HttpClient.filterStatusOk,\n );\n\n const evaluate = Effect.fnUntraced(function* <const Q extends TypeSafeSchema.Questions>(\n options: TypeSafeSchema.EvaluateRequest<Q>,\n ): Effect.fn.Return<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError> {\n const body = yield* encodeRequest(options).pipe(\n Effect.mapError((error) =>\n Errors.make(new AiError.InvalidRequestError({ description: redact(error.message) })),\n ),\n );\n\n const schema = responseFor(options.questions);\n\n return yield* client\n .execute(\n HttpClientRequest.post(\"/systemone\").pipe(\n HttpClientRequest.bodyText(body, \"application/json\"),\n ),\n )\n .pipe(\n Effect.flatMap(HttpClientResponse.schemaBodyJson(schema, { onExcessProperty: \"error\" })),\n Effect.catchTags({\n HttpClientError: (error) => Errors.mapHttpClientError(error, redact),\n SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, redact)),\n }),\n Effect.updateService(Headers.CurrentRedactedNames, (names) => [\n ...names,\n \"authorization\",\n ]),\n );\n });\n\n return TypeSafeClient.of({ client, evaluate });\n },\n);\n\n/** @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<TypeSafeClient, never, Config | HttpClient.HttpClient> =\n Layer.effect(TypeSafeClient, make);\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as EvaluateResponse, g as TypeSafeSchema_d_exports, p as Questions, s as EvaluateRequest } from "./TypeSafeSchema-Dn4_Tptf.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as EffectConfig from "effect/Config";
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
5
|
import * as Layer from "effect/Layer";
|
|
@@ -7,7 +7,7 @@ import * as Redacted from "effect/Redacted";
|
|
|
7
7
|
import * as AiError from "effect/unstable/ai/AiError";
|
|
8
8
|
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
9
9
|
declare namespace TypeSafeClient_d_exports {
|
|
10
|
-
export {
|
|
10
|
+
export { Config, Service, TypeSafeClient, layer, make };
|
|
11
11
|
}
|
|
12
12
|
/** @category services
|
|
13
13
|
* @since 0.1.0
|
|
@@ -26,40 +26,38 @@ declare const TypeSafeClient_base: Context.ServiceClass<TypeSafeClient, "@effect
|
|
|
26
26
|
* @since 0.1.0
|
|
27
27
|
*/
|
|
28
28
|
export declare class TypeSafeClient extends TypeSafeClient_base {}
|
|
29
|
-
|
|
30
|
-
* @since 0.1.0
|
|
31
|
-
*/
|
|
32
|
-
export interface Options {
|
|
29
|
+
declare const Config_base: Context.ServiceClass<Config, "@effect-agent/ai-typesafe/TypeSafeClient/Config", {
|
|
33
30
|
readonly apiKey: Redacted.Redacted<string>;
|
|
34
31
|
/** Base URL, including the API version. Defaults to https://api.typesafe.ai/v1. */
|
|
35
32
|
readonly apiUrl?: string | undefined;
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Configuration captured when the client is acquired. Supply this service from
|
|
36
|
+
* application configuration or use `Config.layer` to load environment values.
|
|
37
|
+
*
|
|
38
|
+
* @category services
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
*/
|
|
41
|
+
export declare class Config extends Config_base {
|
|
42
|
+
/**
|
|
43
|
+
* Load `TYPESAFE_API_KEY` and optional `TYPESAFE_API_URL` through Effect Config.
|
|
44
|
+
* Missing credentials fail with ConfigError before any HTTP request.
|
|
45
|
+
*/
|
|
46
|
+
static readonly layer: Layer.Layer<Config, EffectConfig.ConfigError>;
|
|
38
47
|
}
|
|
39
48
|
/**
|
|
40
|
-
*
|
|
41
|
-
* Acquiring the service does not send a request.
|
|
49
|
+
* Capture Config and a platform-neutral HttpClient at construction.
|
|
50
|
+
* Acquiring the service does not send a request. Apply HTTP policies to the
|
|
51
|
+
* supplied HttpClient; its request middleware receives authenticated, absolute URLs.
|
|
42
52
|
*
|
|
43
53
|
* @category constructors
|
|
44
54
|
* @since 0.1.0
|
|
45
55
|
*/
|
|
46
|
-
export declare const make:
|
|
56
|
+
export declare const make: Effect.Effect<Service, never, Config | HttpClient.HttpClient>;
|
|
47
57
|
/** @category layers
|
|
48
58
|
* @since 0.1.0
|
|
49
59
|
*/
|
|
50
|
-
export declare const layer:
|
|
51
|
-
/**
|
|
52
|
-
* Configure the client with Effect Config. The API key defaults to
|
|
53
|
-
* `Config.Redacted("TYPESAFE_API_KEY")`.
|
|
54
|
-
*
|
|
55
|
-
* @category layers
|
|
56
|
-
* @since 0.1.0
|
|
57
|
-
*/
|
|
58
|
-
export declare const layerConfig: (options?: {
|
|
59
|
-
readonly apiKey?: Config.Config<Redacted.Redacted<string>> | undefined;
|
|
60
|
-
readonly apiUrl?: Config.Config<string> | undefined;
|
|
61
|
-
readonly transformClient?: Options["transformClient"];
|
|
62
|
-
}) => Layer.Layer<TypeSafeClient, Config.ConfigError, HttpClient.HttpClient>;
|
|
60
|
+
export declare const layer: Layer.Layer<TypeSafeClient, never, Config | HttpClient.HttpClient>;
|
|
63
61
|
//#endregion
|
|
64
62
|
export { TypeSafeClient_d_exports as t };
|
|
65
63
|
//# sourceMappingURL=TypeSafeClient.d.mts.map
|
package/dist/TypeSafeClient.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as make, i as
|
|
1
|
+
import { a as make, i as layer, n as TypeSafeClient, t as Config } from "./TypeSafeClient-DTNc_B47.mjs";
|
|
2
2
|
import "./TypeSafeSchema.mjs";
|
|
3
|
-
export { TypeSafeClient, layer,
|
|
3
|
+
export { Config, TypeSafeClient, layer, make };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { n as TypeSafeClient, o as choiceProbabilitySum } from "./TypeSafeClient-DTNc_B47.mjs";
|
|
3
3
|
import { Probability } from "./TypeSafeSchema.mjs";
|
|
4
4
|
import { DecisionModel } from "@effect-agent/ai-decision";
|
|
5
5
|
import { Effect, Layer, Schema } from "effect";
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as TypeSafeClient_exports } from "./TypeSafeClient-DTNc_B47.mjs";
|
|
2
2
|
import { t as TypeSafeSchema_exports } from "./TypeSafeSchema.mjs";
|
|
3
3
|
import { t as TypeSafeDecisionModel_exports } from "./TypeSafeDecisionModel.mjs";
|
|
4
4
|
export { TypeSafeClient_exports as TypeSafeClient, TypeSafeDecisionModel_exports as TypeSafeDecisionModel, TypeSafeSchema_exports as TypeSafeSchema };
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@effect-agent/ai-typesafe","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@effect-agent/ai-typesafe","version":"0.1.0-beta.107","dependencies":{"@effect-agent/ai-decision":"0.1.0-beta.107"},"devDependencies":{"@effect/vitest":"4.0.0-rc.115","effect":"4.0.0-rc.115","typescript":"7.0.2","vite-plus":"0.3.2"},"peerDependencies":{"effect":"^4.0.0-rc.115"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./type-safe-client":{"types":"./dist/TypeSafeClient.d.mts","default":"./dist/TypeSafeClient.mjs"},"./type-safe-schema":{"types":"./dist/TypeSafeSchema.d.mts","default":"./dist/TypeSafeSchema.mjs"},"./type-safe-decision-model":{"types":"./dist/TypeSafeDecisionModel.d.mts","default":"./dist/TypeSafeDecisionModel.mjs"}},"description":"TypeSafe AI evaluation with Effect HttpClient and request-derived answer types.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/ai-typesafe"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test"}}
|
package/src/TypeSafeClient.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @since 0.1.0
|
|
5
5
|
*/
|
|
6
|
-
import * as
|
|
6
|
+
import * as EffectConfig from "effect/Config";
|
|
7
7
|
import * as Context from "effect/Context";
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
|
-
import { flow
|
|
9
|
+
import { flow } from "effect/Function";
|
|
10
10
|
import * as Layer from "effect/Layer";
|
|
11
11
|
import * as Redacted from "effect/Redacted";
|
|
12
12
|
import * as Schema from "effect/Schema";
|
|
@@ -43,103 +43,101 @@ export class TypeSafeClient extends Context.Service<TypeSafeClient, Service>()(
|
|
|
43
43
|
"@effect-agent/ai-typesafe/TypeSafeClient",
|
|
44
44
|
) {}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
const defaultApiUrl = "https://api.typesafe.ai/v1";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Configuration captured when the client is acquired. Supply this service from
|
|
50
|
+
* application configuration or use `Config.layer` to load environment values.
|
|
51
|
+
*
|
|
52
|
+
* @category services
|
|
47
53
|
* @since 0.1.0
|
|
48
54
|
*/
|
|
49
|
-
export
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
export class Config extends Context.Service<
|
|
56
|
+
Config,
|
|
57
|
+
{
|
|
58
|
+
readonly apiKey: Redacted.Redacted<string>;
|
|
59
|
+
/** Base URL, including the API version. Defaults to https://api.typesafe.ai/v1. */
|
|
60
|
+
readonly apiUrl?: string | undefined;
|
|
61
|
+
}
|
|
62
|
+
>()("@effect-agent/ai-typesafe/TypeSafeClient/Config") {
|
|
63
|
+
/**
|
|
64
|
+
* Load `TYPESAFE_API_KEY` and optional `TYPESAFE_API_URL` through Effect Config.
|
|
65
|
+
* Missing credentials fail with ConfigError before any HTTP request.
|
|
66
|
+
*/
|
|
67
|
+
static readonly layer: Layer.Layer<Config, EffectConfig.ConfigError> = Layer.effect(
|
|
68
|
+
Config,
|
|
69
|
+
EffectConfig.all({
|
|
70
|
+
apiKey: EffectConfig.Redacted("TYPESAFE_API_KEY"),
|
|
71
|
+
apiUrl: EffectConfig.String("TYPESAFE_API_URL").pipe(EffectConfig.withDefault(defaultApiUrl)),
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
const encodeRequest = Schema.encodeEffect(Schema.fromJsonString(TypeSafeSchema.EvaluateRequest));
|
|
58
77
|
|
|
59
78
|
/**
|
|
60
|
-
*
|
|
61
|
-
* Acquiring the service does not send a request.
|
|
79
|
+
* Capture Config and a platform-neutral HttpClient at construction.
|
|
80
|
+
* Acquiring the service does not send a request. Apply HTTP policies to the
|
|
81
|
+
* supplied HttpClient; its request middleware receives authenticated, absolute URLs.
|
|
62
82
|
*
|
|
63
83
|
* @category constructors
|
|
64
84
|
* @since 0.1.0
|
|
65
85
|
*/
|
|
66
|
-
export const make = Effect.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
export const make: Effect.Effect<Service, never, Config | HttpClient.HttpClient> = Effect.gen(
|
|
87
|
+
function* () {
|
|
88
|
+
const config = yield* Config;
|
|
89
|
+
const apiKey = Redacted.value(config.apiKey);
|
|
70
90
|
|
|
71
|
-
|
|
72
|
-
|
|
91
|
+
const redact = (text: string) =>
|
|
92
|
+
apiKey.length === 0 ? text : text.replaceAll(apiKey, "<redacted>");
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
),
|
|
82
|
-
HttpClient.filterStatusOk,
|
|
83
|
-
options.transformClient ?? identity,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const evaluate = Effect.fnUntraced(function* <const Q extends TypeSafeSchema.Questions>(
|
|
87
|
-
options: TypeSafeSchema.EvaluateRequest<Q>,
|
|
88
|
-
): Effect.fn.Return<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError> {
|
|
89
|
-
const body = yield* encodeRequest(options).pipe(
|
|
90
|
-
Effect.mapError((error) =>
|
|
91
|
-
Errors.make(new AiError.InvalidRequestError({ description: redact(error.message) })),
|
|
94
|
+
const client = (yield* HttpClient.HttpClient).pipe(
|
|
95
|
+
HttpClient.mapRequestInput(
|
|
96
|
+
flow(
|
|
97
|
+
HttpClientRequest.prependUrl(config.apiUrl ?? defaultApiUrl),
|
|
98
|
+
HttpClientRequest.bearerToken(config.apiKey),
|
|
99
|
+
HttpClientRequest.acceptJson,
|
|
100
|
+
),
|
|
92
101
|
),
|
|
102
|
+
HttpClient.filterStatusOk,
|
|
93
103
|
);
|
|
94
104
|
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
const evaluate = Effect.fnUntraced(function* <const Q extends TypeSafeSchema.Questions>(
|
|
106
|
+
options: TypeSafeSchema.EvaluateRequest<Q>,
|
|
107
|
+
): Effect.fn.Return<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError> {
|
|
108
|
+
const body = yield* encodeRequest(options).pipe(
|
|
109
|
+
Effect.mapError((error) =>
|
|
110
|
+
Errors.make(new AiError.InvalidRequestError({ description: redact(error.message) })),
|
|
101
111
|
),
|
|
102
|
-
)
|
|
103
|
-
.pipe(
|
|
104
|
-
Effect.flatMap(HttpClientResponse.schemaBodyJson(schema, { onExcessProperty: "error" })),
|
|
105
|
-
Effect.catchTags({
|
|
106
|
-
HttpClientError: (error) => Errors.mapHttpClientError(error, redact),
|
|
107
|
-
SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, redact)),
|
|
108
|
-
}),
|
|
109
|
-
Effect.updateService(Headers.CurrentRedactedNames, (names) => [...names, "authorization"]),
|
|
110
112
|
);
|
|
111
|
-
});
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
});
|
|
114
|
+
const schema = responseFor(options.questions);
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
122
|
-
|
|
116
|
+
return yield* client
|
|
117
|
+
.execute(
|
|
118
|
+
HttpClientRequest.post("/systemone").pipe(
|
|
119
|
+
HttpClientRequest.bodyText(body, "application/json"),
|
|
120
|
+
),
|
|
121
|
+
)
|
|
122
|
+
.pipe(
|
|
123
|
+
Effect.flatMap(HttpClientResponse.schemaBodyJson(schema, { onExcessProperty: "error" })),
|
|
124
|
+
Effect.catchTags({
|
|
125
|
+
HttpClientError: (error) => Errors.mapHttpClientError(error, redact),
|
|
126
|
+
SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, redact)),
|
|
127
|
+
}),
|
|
128
|
+
Effect.updateService(Headers.CurrentRedactedNames, (names) => [
|
|
129
|
+
...names,
|
|
130
|
+
"authorization",
|
|
131
|
+
]),
|
|
132
|
+
);
|
|
133
|
+
});
|
|
123
134
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
return TypeSafeClient.of({ client, evaluate });
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
/** @category layers
|
|
129
140
|
* @since 0.1.0
|
|
130
141
|
*/
|
|
131
|
-
export const
|
|
132
|
-
|
|
133
|
-
readonly apiUrl?: Config.Config<string> | undefined;
|
|
134
|
-
readonly transformClient?: Options["transformClient"];
|
|
135
|
-
}): Layer.Layer<TypeSafeClient, Config.ConfigError, HttpClient.HttpClient> =>
|
|
136
|
-
Layer.effect(
|
|
137
|
-
TypeSafeClient,
|
|
138
|
-
Effect.gen(function* () {
|
|
139
|
-
return yield* make({
|
|
140
|
-
apiKey: yield* options?.apiKey ?? Config.Redacted("TYPESAFE_API_KEY"),
|
|
141
|
-
apiUrl: options?.apiUrl === undefined ? undefined : yield* options.apiUrl,
|
|
142
|
-
transformClient: options?.transformClient,
|
|
143
|
-
});
|
|
144
|
-
}),
|
|
145
|
-
);
|
|
142
|
+
export const layer: Layer.Layer<TypeSafeClient, never, Config | HttpClient.HttpClient> =
|
|
143
|
+
Layer.effect(TypeSafeClient, make);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TypeSafeClient-SjzPX2Gl.mjs","names":["make","TypeSafeSchema.Probability","TypeSafeSchema.NoulAnswer","TypeSafeSchema.EvaluateRequest","Errors.make","Errors.mapHttpClientError","Errors.mapSchemaError"],"sources":["../src/internal/errors.ts","../src/internal/schema.ts","../src/TypeSafeClient.ts"],"sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as Option from \"effect/Option\";\nimport * as Record from \"effect/Record\";\nimport * as Redacted from \"effect/Redacted\";\nimport type * as Schema from \"effect/Schema\";\nimport * as AiError from \"effect/unstable/ai/AiError\";\nimport * as Headers from \"effect/unstable/http/Headers\";\nimport type * as HttpClientError from \"effect/unstable/http/HttpClientError\";\n\nexport const make = (reason: AiError.AiErrorReason): AiError.AiError =>\n AiError.make({ module: \"TypeSafeClient\", method: \"evaluate\", reason });\n\nexport const mapSchemaError = (\n error: Schema.SchemaError,\n redact: (text: string) => string,\n): AiError.AiError => {\n const reason = AiError.InvalidOutputError.fromSchemaError(error);\n\n return make(\n new AiError.InvalidOutputError({ ...reason, description: redact(reason.description) }),\n );\n};\n\nconst redactRequest = (\n request: typeof AiError.HttpRequestDetails.Type,\n redact: (text: string) => string,\n): typeof AiError.HttpRequestDetails.Type => ({\n ...request,\n url: redact(request.url),\n urlParams: request.urlParams.map(([key, value]) => [key, redact(value)]),\n hash: request.hash === undefined ? undefined : redact(request.hash),\n headers: Record.map(request.headers, (value) =>\n Redacted.isRedacted(value) ? \"<redacted>\" : redact(value),\n ),\n});\n\nexport const mapHttpClientError = Effect.fnUntraced(function* (\n error: HttpClientError.HttpClientError,\n redact: (text: string) => string,\n): Effect.fn.Return<never, AiError.AiError> {\n const reason = error.reason;\n\n switch (reason._tag) {\n case \"TransportError\":\n case \"EncodeError\":\n case \"InvalidUrlError\": {\n const network = AiError.NetworkError.fromRequestError(reason);\n\n return yield* make(\n new AiError.NetworkError({\n ...network,\n request: redactRequest(network.request, redact),\n description: network.description === undefined ? undefined : redact(network.description),\n }),\n );\n }\n case \"DecodeError\":\n case \"EmptyBodyError\":\n return yield* make(\n new AiError.InvalidOutputError({\n description: redact(reason.description ?? \"Could not decode the TypeSafe response body\"),\n }),\n );\n case \"StatusCodeError\": {\n const { request, response } = reason;\n const redactedNames = yield* Headers.CurrentRedactedNames;\n\n const headers = (value: Headers.Headers) =>\n Record.map(Headers.redact(value, redactedNames), (value) =>\n Redacted.isRedacted(value) ? \"<redacted>\" : redact(value),\n );\n\n const text = yield* Effect.option(response.text);\n const body = Option.isSome(text) ? redact(text.value) : undefined;\n\n const http: typeof AiError.HttpContext.Type = {\n request: {\n method: request.method,\n url: redact(request.url),\n urlParams: Array.from(request.urlParams, ([key, value]) => [key, redact(value)]),\n hash: Option.getOrUndefined(Option.map(request.hash, redact)),\n headers: headers(request.headers),\n },\n response: { status: response.status, headers: headers(response.headers) },\n body,\n };\n\n const description = AiError.buildErrorDescription({\n status: response.status,\n method: request.method,\n url: http.request.url,\n message: undefined,\n body,\n });\n\n return yield* make(\n response.status === 422\n ? new AiError.InvalidRequestError({ description, http })\n : AiError.reasonFromHttpStatus({ status: response.status, description, http }),\n );\n }\n }\n});\n","import * as Schema from \"effect/Schema\";\n\nimport * as TypeSafeSchema from \"../TypeSafeSchema.ts\";\n\n// Permit floating-point serialization error without changing provider values.\nconst tolerance = 1e-6;\n\nconst probabilitySum = Schema.makeFilter(\n (probabilities: Readonly<Record<string, number>>) =>\n Math.abs(Object.values(probabilities).reduce((sum, value) => sum + value, 0) - 1) <= tolerance,\n { expected: \"probabilities summing to 1 (within 1e-6)\" },\n);\n\n// Jev Choice responses have been observed with two-decimal probabilities totaling 0.99.\n// Limit compatibility to one percentage point, even for very large option catalogues.\n// Score sums/weighting retain their strict checks; no Score rounding contract is assumed.\nexport const choiceProbabilitySum = Schema.makeFilter(\n (probabilities: Readonly<Record<string, number>>) => {\n const values = Object.values(probabilities);\n const error = Math.abs(values.reduce((sum, value) => sum + value, 0) - 1);\n\n return (\n error <= tolerance ||\n (error <= Math.min(0.01, values.length * 0.005) + tolerance &&\n values.every((value) => Math.abs(value * 100 - Math.round(value * 100)) < 1e-8))\n );\n },\n { expected: \"probabilities summing to 1 within bounded two-decimal Choice rounding\" },\n);\n\nconst distribution = (keys: ReadonlyArray<string>, sumCheck = probabilitySum) =>\n Schema.Record(Schema.Literals(keys), TypeSafeSchema.Probability).check(sumCheck);\n\nconst answerFor = (question: TypeSafeSchema.Question) => {\n switch (question.type) {\n case \"choice\": {\n const keys = Object.keys(question.criteria);\n\n return Schema.Struct({\n ...TypeSafeSchema.ChoiceAnswer.fields,\n choice: Schema.Literals(keys),\n probabilities: distribution(keys, choiceProbabilitySum),\n }).check(\n Schema.makeFilter(\n ({ choice, probabilities }) =>\n Object.values(probabilities).every((value) => value <= probabilities[choice]),\n { expected: \"a highest-probability choice\" },\n ),\n );\n }\n case \"score\": {\n const maxLevel = question.criteria.length - 1;\n\n const levels = question.criteria.map(\n (description, index) => [String(index), description] as const,\n );\n\n return Schema.Struct({\n ...TypeSafeSchema.ScoreAnswer.fields,\n score: Schema.Finite.check(Schema.isBetween({ minimum: 0, maximum: maxLevel })),\n legend: Schema.Struct(\n Object.fromEntries(\n levels.map(([key, description]) => [key, Schema.Literal(description)]),\n ),\n ),\n probabilities: distribution(levels.map(([key]) => key)),\n }).check(\n Schema.makeFilter(\n ({ score, probabilities }) =>\n Math.abs(\n score -\n Object.entries(probabilities).reduce(\n (sum, [level, probability]) => sum + Number(level) * probability,\n 0,\n ),\n ) <=\n tolerance * Math.max(1, maxLevel),\n { expected: \"the probability-weighted score (within 1e-6 per level)\" },\n ),\n );\n }\n case \"noul\":\n return TypeSafeSchema.NoulAnswer;\n }\n};\n\n// The overload describes the dependent type enforced by the literal keys and\n// per-question schemas below. No JSON value is asserted to have that type.\nexport function responseFor<const Q extends TypeSafeSchema.Questions>(\n questions: Q,\n): Schema.Codec<TypeSafeSchema.EvaluateResponse<Q>>;\n\nexport function responseFor(questions: TypeSafeSchema.Questions): Schema.Top {\n return Schema.Struct({\n ...TypeSafeSchema.EvaluateResponse.fields,\n answers: Schema.Struct(\n Object.fromEntries(\n Object.entries(questions).map(([id, question]) => [id, answerFor(question)]),\n ),\n ),\n });\n}\n","/**\n * An Effect HttpClient integration for TypeSafe's System One evaluations.\n *\n * @since 0.1.0\n */\nimport * as Config from \"effect/Config\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport { flow, identity } from \"effect/Function\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport * as Schema from \"effect/Schema\";\nimport * as AiError from \"effect/unstable/ai/AiError\";\nimport * as Headers from \"effect/unstable/http/Headers\";\nimport * as HttpClient from \"effect/unstable/http/HttpClient\";\nimport * as HttpClientRequest from \"effect/unstable/http/HttpClientRequest\";\nimport * as HttpClientResponse from \"effect/unstable/http/HttpClientResponse\";\n\nimport * as Errors from \"./internal/errors.ts\";\nimport { responseFor } from \"./internal/schema.ts\";\nimport * as TypeSafeSchema from \"./TypeSafeSchema.ts\";\n\n/** @category services\n * @since 0.1.0\n */\nexport interface Service {\n readonly client: HttpClient.HttpClient;\n\n /**\n * Evaluate mixed questions against one state. Answers are validated against\n * the submitted IDs, types, and criteria before receiving their inferred type.\n * There are no automatic retries or timeouts; compose those with Effect.\n */\n readonly evaluate: <const Q extends TypeSafeSchema.Questions>(\n options: TypeSafeSchema.EvaluateRequest<Q>,\n ) => Effect.Effect<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError>;\n}\n\n/** @category services\n * @since 0.1.0\n */\nexport class TypeSafeClient extends Context.Service<TypeSafeClient, Service>()(\n \"@effect-agent/ai-typesafe/TypeSafeClient\",\n) {}\n\n/** @category options\n * @since 0.1.0\n */\nexport interface Options {\n readonly apiKey: Redacted.Redacted<string>;\n /** Base URL, including the API version. Defaults to https://api.typesafe.ai/v1. */\n readonly apiUrl?: string | undefined;\n /** Applied after authentication and status filtering, for explicit HTTP policies. */\n readonly transformClient?: ((client: HttpClient.HttpClient) => HttpClient.HttpClient) | undefined;\n}\n\nconst encodeRequest = Schema.encodeEffect(Schema.fromJsonString(TypeSafeSchema.EvaluateRequest));\n\n/**\n * Construct the client using a supplied, platform-neutral HttpClient.\n * Acquiring the service does not send a request.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = Effect.fnUntraced(function* (\n options: Options,\n): Effect.fn.Return<Service, never, HttpClient.HttpClient> {\n const apiKey = Redacted.value(options.apiKey);\n\n const redact = (text: string) =>\n apiKey.length === 0 ? text : text.replaceAll(apiKey, \"<redacted>\");\n\n const client = (yield* HttpClient.HttpClient).pipe(\n HttpClient.mapRequest(\n flow(\n HttpClientRequest.prependUrl(options.apiUrl ?? \"https://api.typesafe.ai/v1\"),\n HttpClientRequest.bearerToken(options.apiKey),\n HttpClientRequest.acceptJson,\n ),\n ),\n HttpClient.filterStatusOk,\n options.transformClient ?? identity,\n );\n\n const evaluate = Effect.fnUntraced(function* <const Q extends TypeSafeSchema.Questions>(\n options: TypeSafeSchema.EvaluateRequest<Q>,\n ): Effect.fn.Return<TypeSafeSchema.EvaluateResponse<Q>, AiError.AiError> {\n const body = yield* encodeRequest(options).pipe(\n Effect.mapError((error) =>\n Errors.make(new AiError.InvalidRequestError({ description: redact(error.message) })),\n ),\n );\n\n const schema = responseFor(options.questions);\n\n return yield* client\n .execute(\n HttpClientRequest.post(\"/systemone\").pipe(\n HttpClientRequest.bodyText(body, \"application/json\"),\n ),\n )\n .pipe(\n Effect.flatMap(HttpClientResponse.schemaBodyJson(schema, { onExcessProperty: \"error\" })),\n Effect.catchTags({\n HttpClientError: (error) => Errors.mapHttpClientError(error, redact),\n SchemaError: (error) => Effect.fail(Errors.mapSchemaError(error, redact)),\n }),\n Effect.updateService(Headers.CurrentRedactedNames, (names) => [...names, \"authorization\"]),\n );\n });\n\n return TypeSafeClient.of({ client, evaluate });\n});\n\n/** @category layers\n * @since 0.1.0\n */\nexport const layer = (\n options: Options,\n): Layer.Layer<TypeSafeClient, never, HttpClient.HttpClient> =>\n Layer.effect(TypeSafeClient, make(options));\n\n/**\n * Configure the client with Effect Config. The API key defaults to\n * `Config.Redacted(\"TYPESAFE_API_KEY\")`.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerConfig = (options?: {\n readonly apiKey?: Config.Config<Redacted.Redacted<string>> | undefined;\n readonly apiUrl?: Config.Config<string> | undefined;\n readonly transformClient?: Options[\"transformClient\"];\n}): Layer.Layer<TypeSafeClient, Config.ConfigError, HttpClient.HttpClient> =>\n Layer.effect(\n TypeSafeClient,\n Effect.gen(function* () {\n return yield* make({\n apiKey: yield* options?.apiKey ?? Config.Redacted(\"TYPESAFE_API_KEY\"),\n apiUrl: options?.apiUrl === undefined ? undefined : yield* options.apiUrl,\n transformClient: options?.transformClient,\n });\n }),\n );\n"],"mappings":"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"}
|