@effect-agent/ai-typesafe 0.1.0-beta.101 → 0.1.0-beta.103
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 +27 -114
- package/dist/{TypeSafeClient-OS5hTVMz.mjs → TypeSafeClient-SjzPX2Gl.mjs} +10 -4
- package/dist/TypeSafeClient-SjzPX2Gl.mjs.map +1 -0
- package/dist/TypeSafeClient.d.mts +1 -1
- package/dist/TypeSafeClient.mjs +1 -1
- package/dist/TypeSafeDecisionModel.d.mts +25 -0
- package/dist/TypeSafeDecisionModel.mjs +68 -0
- package/dist/TypeSafeDecisionModel.mjs.map +1 -0
- package/dist/TypeSafeSchema-Dn4_Tptf.d.mts +305 -0
- package/dist/TypeSafeSchema.d.mts +2 -305
- package/dist/TypeSafeSchema.mjs +7 -26
- package/dist/TypeSafeSchema.mjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +3 -2
- package/package.json +1 -1
- package/src/TypeSafeDecisionModel.ts +77 -0
- package/src/TypeSafeSchema.ts +7 -21
- package/src/index.ts +1 -0
- package/src/internal/schema.ts +26 -10
- package/dist/TypeSafeClient-OS5hTVMz.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,126 +1,39 @@
|
|
|
1
1
|
# @effect-agent/ai-typesafe
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Use Jev to evaluate typed questions with Effect. `TypeSafeDecisionModel` supplies the
|
|
4
|
+
provider for [`@effect-agent/ai-decision`](../ai-decision); `TypeSafeClient` owns HTTP
|
|
5
|
+
configuration and also exposes Jev's API directly.
|
|
6
6
|
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
import { Config, Effect, Layer } from "effect";
|
|
10
|
-
import { FetchHttpClient } from "effect/unstable/http";
|
|
11
|
-
|
|
12
|
-
const evaluation = Effect.gen(function* () {
|
|
13
|
-
const client = yield* TypeSafeClient.TypeSafeClient;
|
|
14
|
-
const result = yield* client.evaluate({
|
|
15
|
-
model: "jev-latest",
|
|
16
|
-
state: { message: "I was charged twice. Please refund the duplicate." },
|
|
17
|
-
questions: {
|
|
18
|
-
department: {
|
|
19
|
-
type: "choice",
|
|
20
|
-
instructions: "Which team should handle this ticket?",
|
|
21
|
-
criteria: { billing: "Payments and refunds", technical: "Bugs and outages" },
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return result.answers.department.choice; // "billing" | "technical"
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const ClientLive = TypeSafeClient.layerConfig({
|
|
30
|
-
apiKey: Config.Redacted("TYPESAFE_API_KEY"),
|
|
31
|
-
}).pipe(Layer.provide(FetchHttpClient.layer));
|
|
32
|
-
|
|
33
|
-
const program = evaluation.pipe(Effect.provide(ClientLive));
|
|
7
|
+
```text
|
|
8
|
+
DecisionModel → TypeSafeDecisionModel → TypeSafeClient → Jev
|
|
34
9
|
```
|
|
35
10
|
|
|
36
|
-
|
|
37
|
-
[mixed-question example](examples/evaluate.ts) also shows bounded retries and an
|
|
38
|
-
overall timeout. Acquiring the client does not send requests.
|
|
39
|
-
|
|
40
|
-
## Questions and answers
|
|
41
|
-
|
|
42
|
-
`evaluate` sends `POST https://api.typesafe.ai/v1/systemone` with bearer authentication
|
|
43
|
-
and the required `{ model, state, questions }` body. State and instructions accept
|
|
44
|
-
strings, JSON objects, and JSON arrays. Nested values must be JSON-compatible.
|
|
45
|
-
|
|
46
|
-
| Question | Criteria | Answer |
|
|
47
|
-
| -------- | ------------------------------------------------------------------------ | ----------------------------------------------------------- |
|
|
48
|
-
| `choice` | Nonempty map of option names to a string or `null` | `choice`, `probabilities`, `confidence` |
|
|
49
|
-
| `score` | At least two ordered string descriptions | Fractional `score`, `legend`, `probabilities`, `confidence` |
|
|
50
|
-
| `noul` | Optional object with optional string descriptions for `true` and `false` | `noul` in [0, 1] |
|
|
51
|
-
|
|
52
|
-
Every answer includes its `type`. `model` and `usage.input_tokens` /
|
|
53
|
-
`usage.output_tokens` are retained. A returned model may resolve the requested alias
|
|
54
|
-
to a concrete version. Required fields are never filled in from examples or defaults.
|
|
55
|
-
The supported wire shapes follow the [API reference](https://docs.typesafe.ai/api),
|
|
56
|
-
including string-valued score legends.
|
|
57
|
-
|
|
58
|
-
Use `satisfies TypeSafeSchema.Questions` to retain question keys and choice literals
|
|
59
|
-
when defining questions separately. Runtime-built maps retain broader types:
|
|
60
|
-
unknown answer IDs and probability keys may be absent, and mixed answers must be
|
|
61
|
-
narrowed by `type`. Optional criteria remain optional in the probability map.
|
|
62
|
-
Open string, numeric, and template-pattern indexes allow absent entries;
|
|
63
|
-
explicitly required keys keep their required types.
|
|
11
|
+
## Connect a decision model
|
|
64
12
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
and must match their probability-weighted value. Distribution sums allow `1e-6`
|
|
70
|
-
rounding error, and score comparisons allow `1e-6` times the highest level index.
|
|
71
|
-
Values are preserved rather than normalized. Unexpected response fields are rejected.
|
|
72
|
-
|
|
73
|
-
Confidence summarizes a distribution; it is not a correctness guarantee. Noul has
|
|
74
|
-
no separate confidence. Choose application thresholds using evaluated examples for
|
|
75
|
-
your domain. See TypeSafe's [confidence guide](https://docs.typesafe.ai/confidence).
|
|
76
|
-
|
|
77
|
-
## Errors, cancellation, and HTTP policies
|
|
78
|
-
|
|
79
|
-
Evaluation failures use native `AiError` reasons:
|
|
80
|
-
|
|
81
|
-
| Failure | Reason |
|
|
82
|
-
| ------------------------------------------------------------ | ------------------------------------ |
|
|
83
|
-
| Invalid local request or HTTP 422 | `InvalidRequestError` |
|
|
84
|
-
| HTTP 401 | `AuthenticationError` (`InvalidKey`) |
|
|
85
|
-
| HTTP 429 | `RateLimitError` |
|
|
86
|
-
| HTTP 529 | `InternalProviderError` |
|
|
87
|
-
| Transport failure | `NetworkError` |
|
|
88
|
-
| Malformed JSON or a response that disagrees with the request | `InvalidOutputError` |
|
|
89
|
-
|
|
90
|
-
`layerConfig` can also fail with `ConfigError`. Defects and interruption remain
|
|
91
|
-
defects and interruption. Cancellation reaches the supplied HttpClient, including
|
|
92
|
-
while reading the response body.
|
|
93
|
-
|
|
94
|
-
HTTP status failures retain the status, request details, response headers, and raw
|
|
95
|
-
provider error text without assuming an error-body protocol. Sensitive headers and
|
|
96
|
-
the configured API key are redacted from diagnostics. Provider error text may contain
|
|
97
|
-
submitted content. The integration adds no body logging; HTTP tracing is controlled
|
|
98
|
-
by Effect HttpClient and the application.
|
|
99
|
-
|
|
100
|
-
There are no default retries or deadlines. Compose `Effect.retry` with a bounded
|
|
101
|
-
schedule and `Effect.timeout`, or supply `transformClient` to `make`, `layer`, or
|
|
102
|
-
`layerConfig`. The transformer receives the client after authentication and status
|
|
103
|
-
filtering. `apiUrl` overrides the versioned base URL for a proxy or substitute.
|
|
13
|
+
```ts
|
|
14
|
+
import { TypeSafeClient, TypeSafeDecisionModel } from "@effect-agent/ai-typesafe";
|
|
15
|
+
import { Layer } from "effect";
|
|
16
|
+
import { FetchHttpClient } from "effect/unstable/http";
|
|
104
17
|
|
|
105
|
-
|
|
18
|
+
const DecisionLive = TypeSafeDecisionModel.model("jev-latest").pipe(
|
|
19
|
+
Layer.provide(TypeSafeClient.layerConfig().pipe(Layer.provide(FetchHttpClient.layer))),
|
|
20
|
+
);
|
|
21
|
+
```
|
|
106
22
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
failures in the Effect error channel. Supply TypeSafeClient when executing the tool
|
|
111
|
-
or providing it to an agent's language model.
|
|
23
|
+
Set `TYPESAFE_API_KEY`, then provide `DecisionLive` to the Effect that evaluates your
|
|
24
|
+
decision set. The adapter maps shared `probability` questions to Jev's `noul` and retains
|
|
25
|
+
choice and score distributions. Application code chooses how to use the answers.
|
|
112
26
|
|
|
113
|
-
|
|
114
|
-
|
|
27
|
+
There are no default retries or deadlines. Add those policies with Effect or the client's
|
|
28
|
+
`transformClient` option. See the [configuration and error reference](https://effect-agent.com/reference/decision-models#typesafe-client)
|
|
29
|
+
for details, including Jev's [rounded probabilities](https://effect-agent.com/reference/decision-models#probability-validation).
|
|
115
30
|
|
|
116
|
-
##
|
|
31
|
+
## Examples
|
|
117
32
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
33
|
+
- [Decision set and state transition](examples/decision.ts): all three query types with provider setup.
|
|
34
|
+
- [Direct evaluation](examples/evaluate.ts): native choice, score, and noul answers, bounded retries, and a timeout.
|
|
35
|
+
- [Native Effect AI tool](examples/tool.ts): expose a fixed assessment through `Tool` and `Toolkit`.
|
|
121
36
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
package metadata, service identity, import paths, and release documentation while
|
|
126
|
-
retaining the HTTP contracts and tests.
|
|
37
|
+
Each example exports an Effect to run with your application's runtime. Start with the
|
|
38
|
+
[decision guide](https://effect-agent.com/guide/tools#decision-transitions), or use the
|
|
39
|
+
[reference](https://effect-agent.com/reference/decision-models) for options, results, and errors.
|
|
@@ -90,7 +90,13 @@ const mapHttpClientError = Effect.fnUntraced(function* (error, redact) {
|
|
|
90
90
|
//#endregion
|
|
91
91
|
//#region src/internal/schema.ts
|
|
92
92
|
const tolerance = 1e-6;
|
|
93
|
-
const
|
|
93
|
+
const probabilitySum = Schema.makeFilter((probabilities) => Math.abs(Object.values(probabilities).reduce((sum, value) => sum + value, 0) - 1) <= tolerance, { expected: "probabilities summing to 1 (within 1e-6)" });
|
|
94
|
+
const choiceProbabilitySum = Schema.makeFilter((probabilities) => {
|
|
95
|
+
const values = Object.values(probabilities);
|
|
96
|
+
const error = Math.abs(values.reduce((sum, value) => sum + value, 0) - 1);
|
|
97
|
+
return error <= tolerance || error <= Math.min(.01, values.length * .005) + tolerance && values.every((value) => Math.abs(value * 100 - Math.round(value * 100)) < 1e-8);
|
|
98
|
+
}, { expected: "probabilities summing to 1 within bounded two-decimal Choice rounding" });
|
|
99
|
+
const distribution = (keys, sumCheck = probabilitySum) => Schema.Record(Schema.Literals(keys), Probability).check(sumCheck);
|
|
94
100
|
const answerFor = (question) => {
|
|
95
101
|
switch (question.type) {
|
|
96
102
|
case "choice": {
|
|
@@ -98,7 +104,7 @@ const answerFor = (question) => {
|
|
|
98
104
|
return Schema.Struct({
|
|
99
105
|
...ChoiceAnswer.fields,
|
|
100
106
|
choice: Schema.Literals(keys),
|
|
101
|
-
probabilities: distribution(keys)
|
|
107
|
+
probabilities: distribution(keys, choiceProbabilitySum)
|
|
102
108
|
}).check(Schema.makeFilter(({ choice, probabilities }) => Object.values(probabilities).every((value) => value <= probabilities[choice]), { expected: "a highest-probability choice" }));
|
|
103
109
|
}
|
|
104
110
|
case "score": {
|
|
@@ -184,6 +190,6 @@ const layerConfig = (options) => Layer.effect(TypeSafeClient, Effect.gen(functio
|
|
|
184
190
|
});
|
|
185
191
|
}));
|
|
186
192
|
//#endregion
|
|
187
|
-
export { make as a, layerConfig as i, TypeSafeClient_exports as n, layer as r, TypeSafeClient as t };
|
|
193
|
+
export { make as a, layerConfig as i, TypeSafeClient_exports as n, choiceProbabilitySum as o, layer as r, TypeSafeClient as t };
|
|
188
194
|
|
|
189
|
-
//# sourceMappingURL=TypeSafeClient-
|
|
195
|
+
//# sourceMappingURL=TypeSafeClient-SjzPX2Gl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as EvaluateResponse, g as TypeSafeSchema_d_exports, p as Questions, s as EvaluateRequest } from "./TypeSafeSchema-Dn4_Tptf.mjs";
|
|
2
2
|
import * as Config from "effect/Config";
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
package/dist/TypeSafeClient.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as make, i as layerConfig, r as layer, t as TypeSafeClient } from "./TypeSafeClient-
|
|
1
|
+
import { a as make, i as layerConfig, r as layer, t as TypeSafeClient } from "./TypeSafeClient-SjzPX2Gl.mjs";
|
|
2
2
|
import "./TypeSafeSchema.mjs";
|
|
3
3
|
export { TypeSafeClient, layer, layerConfig, make };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { TypeSafeClient } from "./TypeSafeClient.mjs";
|
|
2
|
+
import { DecisionModel } from "@effect-agent/ai-decision";
|
|
3
|
+
import { Layer, Schema } from "effect";
|
|
4
|
+
declare namespace TypeSafeDecisionModel_d_exports {
|
|
5
|
+
export { ProviderMetadata, model };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* TypeSafe's distribution statistics, under result.providerMetadata.typesafe.
|
|
9
|
+
* Noul questions have no confidence entry.
|
|
10
|
+
*
|
|
11
|
+
* @category schemas
|
|
12
|
+
* @since 0.1.0
|
|
13
|
+
*/
|
|
14
|
+
export declare const ProviderMetadata: Schema.Struct<{
|
|
15
|
+
readonly confidence: Schema.$Record<Schema.String, Schema.Finite>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Supply a TypeSafe model as a provider-neutral decision model. The client retains HTTP policy;
|
|
19
|
+
* this adapter translates probability questions to noul and preserves returned evidence/usage.
|
|
20
|
+
* Capture TypeSafeClient at Layer construction. This Layer does not supply LanguageModel.
|
|
21
|
+
*/
|
|
22
|
+
export declare const model: (model: string) => Layer.Layer<DecisionModel.DecisionModel, never, TypeSafeClient>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { TypeSafeDecisionModel_d_exports as t };
|
|
25
|
+
//# sourceMappingURL=TypeSafeDecisionModel.d.mts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { o as choiceProbabilitySum, t as TypeSafeClient } from "./TypeSafeClient-SjzPX2Gl.mjs";
|
|
3
|
+
import { Probability } from "./TypeSafeSchema.mjs";
|
|
4
|
+
import { DecisionModel } from "@effect-agent/ai-decision";
|
|
5
|
+
import { Effect, Layer, Schema } from "effect";
|
|
6
|
+
//#region src/TypeSafeDecisionModel.ts
|
|
7
|
+
var TypeSafeDecisionModel_exports = /* @__PURE__ */ __exportAll({
|
|
8
|
+
ProviderMetadata: () => ProviderMetadata,
|
|
9
|
+
model: () => model
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* TypeSafe's distribution statistics, under result.providerMetadata.typesafe.
|
|
13
|
+
* Noul questions have no confidence entry.
|
|
14
|
+
*
|
|
15
|
+
* @category schemas
|
|
16
|
+
* @since 0.1.0
|
|
17
|
+
*/
|
|
18
|
+
const ProviderMetadata = Schema.Struct({ confidence: Schema.Record(Schema.String, Probability) });
|
|
19
|
+
/**
|
|
20
|
+
* Supply a TypeSafe model as a provider-neutral decision model. The client retains HTTP policy;
|
|
21
|
+
* this adapter translates probability questions to noul and preserves returned evidence/usage.
|
|
22
|
+
* Capture TypeSafeClient at Layer construction. This Layer does not supply LanguageModel.
|
|
23
|
+
*/
|
|
24
|
+
const model = (model) => Layer.effect(DecisionModel.DecisionModel, Effect.gen(function* () {
|
|
25
|
+
const client = yield* TypeSafeClient;
|
|
26
|
+
return yield* DecisionModel.make({
|
|
27
|
+
choiceProbabilitySum,
|
|
28
|
+
evaluate: Effect.fnUntraced(function* (request) {
|
|
29
|
+
const questions = Object.fromEntries(Object.entries(request.questions).map(([id, question]) => [id, question.type === "probability" ? {
|
|
30
|
+
...question,
|
|
31
|
+
type: "noul"
|
|
32
|
+
} : question]));
|
|
33
|
+
const response = yield* client.evaluate({
|
|
34
|
+
model,
|
|
35
|
+
state: request.state,
|
|
36
|
+
questions
|
|
37
|
+
});
|
|
38
|
+
const answers = [];
|
|
39
|
+
const confidence = [];
|
|
40
|
+
for (const [id, answer] of Object.entries(response.answers)) {
|
|
41
|
+
if (answer === void 0) continue;
|
|
42
|
+
if (answer.type === "noul") answers.push([id, {
|
|
43
|
+
type: "probability",
|
|
44
|
+
probability: answer.noul
|
|
45
|
+
}]);
|
|
46
|
+
else {
|
|
47
|
+
const { confidence: statistic, ...evidence } = answer;
|
|
48
|
+
answers.push([id, evidence]);
|
|
49
|
+
confidence.push([id, statistic]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
provider: "typesafe",
|
|
54
|
+
model: response.model,
|
|
55
|
+
answers: Object.fromEntries(answers),
|
|
56
|
+
usage: {
|
|
57
|
+
inputTokens: response.usage.input_tokens,
|
|
58
|
+
outputTokens: response.usage.output_tokens
|
|
59
|
+
},
|
|
60
|
+
providerMetadata: { typesafe: { confidence: Object.fromEntries(confidence) } }
|
|
61
|
+
};
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
}));
|
|
65
|
+
//#endregion
|
|
66
|
+
export { ProviderMetadata, model, TypeSafeDecisionModel_exports as t };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=TypeSafeDecisionModel.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypeSafeDecisionModel.mjs","names":["TypeSafeSchema.Probability"],"sources":["../src/TypeSafeDecisionModel.ts"],"sourcesContent":["import { DecisionModel, type DecisionSchema } from \"@effect-agent/ai-decision\";\nimport { Effect, Layer, Schema } from \"effect\";\n\nimport { choiceProbabilitySum } from \"./internal/schema.ts\";\nimport { TypeSafeClient } from \"./TypeSafeClient.ts\";\nimport * as TypeSafeSchema from \"./TypeSafeSchema.ts\";\n\n/**\n * TypeSafe's distribution statistics, under result.providerMetadata.typesafe.\n * Noul questions have no confidence entry.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const ProviderMetadata = Schema.Struct({\n confidence: Schema.Record(Schema.String, TypeSafeSchema.Probability),\n});\n\n/**\n * Supply a TypeSafe model as a provider-neutral decision model. The client retains HTTP policy;\n * this adapter translates probability questions to noul and preserves returned evidence/usage.\n * Capture TypeSafeClient at Layer construction. This Layer does not supply LanguageModel.\n */\nexport const model = (\n model: string,\n): Layer.Layer<DecisionModel.DecisionModel, never, TypeSafeClient> =>\n Layer.effect(\n DecisionModel.DecisionModel,\n Effect.gen(function* () {\n const client = yield* TypeSafeClient;\n\n return yield* DecisionModel.make({\n choiceProbabilitySum,\n evaluate: Effect.fnUntraced(function* (request) {\n const questions: TypeSafeSchema.Questions = Object.fromEntries(\n Object.entries(request.questions).map(([id, question]) => [\n id,\n question.type === \"probability\" ? { ...question, type: \"noul\" } : question,\n ]),\n );\n\n const response = yield* client.evaluate({ model, state: request.state, questions });\n\n const answers: Array<readonly [string, DecisionSchema.Answer]> = [];\n\n const confidence: Array<readonly [string, number]> = [];\n\n for (const [id, answer] of Object.entries(response.answers)) {\n if (answer === undefined) continue;\n if (answer.type === \"noul\") {\n answers.push([id, { type: \"probability\", probability: answer.noul }]);\n } else {\n const { confidence: statistic, ...evidence } = answer;\n\n answers.push([id, evidence]);\n confidence.push([id, statistic]);\n }\n }\n\n return {\n provider: \"typesafe\",\n model: response.model,\n answers: Object.fromEntries(answers),\n usage: {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n },\n providerMetadata: {\n typesafe: {\n confidence: Object.fromEntries(confidence),\n },\n },\n };\n }),\n });\n }),\n );\n"],"mappings":";;;;;;;;;;;;;;;;;AAcA,MAAa,mBAAmB,OAAO,OAAO,EAC5C,YAAY,OAAO,OAAO,OAAO,QAAQA,WAA0B,EACrE,CAAC;;;;;;AAOD,MAAa,SACX,UAEA,MAAM,OACJ,cAAc,eACd,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CAEtB,OAAO,OAAO,cAAc,KAAK;EAC/B;EACA,UAAU,OAAO,WAAW,WAAW,SAAS;GAC9C,MAAM,YAAsC,OAAO,YACjD,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,cAAc,CACxD,IACA,SAAS,SAAS,gBAAgB;IAAE,GAAG;IAAU,MAAM;GAAO,IAAI,QACpE,CAAC,CACH;GAEA,MAAM,WAAW,OAAO,OAAO,SAAS;IAAE;IAAO,OAAO,QAAQ;IAAO;GAAU,CAAC;GAElF,MAAM,UAA2D,CAAC;GAElE,MAAM,aAA+C,CAAC;GAEtD,KAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,SAAS,OAAO,GAAG;IAC3D,IAAI,WAAW,KAAA,GAAW;IAC1B,IAAI,OAAO,SAAS,QAClB,QAAQ,KAAK,CAAC,IAAI;KAAE,MAAM;KAAe,aAAa,OAAO;IAAK,CAAC,CAAC;SAC/D;KACL,MAAM,EAAE,YAAY,WAAW,GAAG,aAAa;KAE/C,QAAQ,KAAK,CAAC,IAAI,QAAQ,CAAC;KAC3B,WAAW,KAAK,CAAC,IAAI,SAAS,CAAC;IACjC;GACF;GAEA,OAAO;IACL,UAAU;IACV,OAAO,SAAS;IAChB,SAAS,OAAO,YAAY,OAAO;IACnC,OAAO;KACL,aAAa,SAAS,MAAM;KAC5B,cAAc,SAAS,MAAM;IAC/B;IACA,kBAAkB,EAChB,UAAU,EACR,YAAY,OAAO,YAAY,UAAU,EAC3C,EACF;GACF;EACF,CAAC;CACH,CAAC;AACH,CAAC,CACH"}
|