effect-durable-agent-cloudflare 0.1.0-alpha.20 → 0.1.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anthropic.d.ts +44 -0
- package/dist/anthropic.js +66 -0
- package/dist/anthropic.js.map +1 -0
- package/dist/durable-object.d.ts +1 -1
- package/dist/durable-object.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/openai.d.ts +9 -3
- package/dist/openai.js +20 -48
- package/dist/openai.js.map +1 -1
- package/dist/providers.d.ts +53 -0
- package/dist/providers.js +221 -0
- package/dist/providers.js.map +1 -0
- package/dist/{session-controller-zTTLb7tt.js → session-controller-BGfz1DdS.js} +3 -3
- package/dist/{session-controller-zTTLb7tt.js.map → session-controller-BGfz1DdS.js.map} +1 -1
- package/dist/{session-controller-DCvQY3nj.d.ts → session-controller-DoeFP_Ej.d.ts} +3 -3
- package/dist/session-controller.d.ts +1 -1
- package/dist/session-controller.js +1 -1
- package/dist/transport-BzgK07l4.js +205 -0
- package/dist/transport-BzgK07l4.js.map +1 -0
- package/package.json +20 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AnthropicClient, AnthropicLanguageModel } from "@effect/ai-anthropic";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import * as Prompt from "effect/ai/Prompt";
|
|
4
|
+
//#region src/providers/anthropic.d.ts
|
|
5
|
+
/** Anthropic request defaults for one resolved model (everything but `model`). */
|
|
6
|
+
type EDAAnthropicModelConfig = Omit<typeof AnthropicLanguageModel.Config.Service, "model">;
|
|
7
|
+
/** Shared Anthropic transport and client options. */
|
|
8
|
+
interface EDAAnthropicClientOptions {
|
|
9
|
+
/** Cloudflare AI Gateway binding. With a gateway-stored key (BYOK) no `apiKey` is needed. */
|
|
10
|
+
readonly aiGateway?: AiGateway | undefined;
|
|
11
|
+
readonly apiKey?: string | undefined;
|
|
12
|
+
readonly apiUrl?: string | undefined;
|
|
13
|
+
/** Beta flags sent on every request, e.g. `thinking-binding-controls-2026-08-01`. */
|
|
14
|
+
readonly betas?: ReadonlyArray<string> | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Anthropic client layer over EDA's provider transport. */
|
|
17
|
+
declare const makeEDAAnthropicClientLayer: (options: EDAAnthropicClientOptions) => Layer.Layer<AnthropicClient.AnthropicClient>;
|
|
18
|
+
/** Beta that lets requests choose what happens to thinking bound to an edited conversation. */
|
|
19
|
+
declare const ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
|
|
20
|
+
/** Agent request policy for Claude 5.5-generation models. */
|
|
21
|
+
interface EDAAnthropicAgentSettings {
|
|
22
|
+
/** Thinking depth; Opus 5.5 cannot disable thinking, so effort is the only control. */
|
|
23
|
+
readonly effort: "low" | "medium" | "high";
|
|
24
|
+
/** Output budget including thinking. Defaults to 64,000. */
|
|
25
|
+
readonly maxTokens?: number | undefined;
|
|
26
|
+
/** `summarized` streams readable reasoning summaries. Defaults to `summarized`. */
|
|
27
|
+
readonly thinkingDisplay?: "summarized" | "omitted" | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Explicit preserved-thinking policy (requires {@link ANTHROPIC_THINKING_BINDING_BETA}).
|
|
30
|
+
* `drop_block` degrades instead of failing when replayed thinking no longer matches.
|
|
31
|
+
*/
|
|
32
|
+
readonly prefixMismatchBehavior?: "error" | "drop_block" | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** Model config for EDA agent sessions on Anthropic. */
|
|
35
|
+
declare const anthropicAgentModelConfig: (settings: EDAAnthropicAgentSettings) => EDAAnthropicModelConfig;
|
|
36
|
+
/**
|
|
37
|
+
* Anthropic prompt preparation: EDA cache hints become `cache_control` breakpoints (end of the
|
|
38
|
+
* instruction prefix and end of durable history), and Anthropic compaction summaries become the
|
|
39
|
+
* transport sentinel that is replayed as the signed `compaction` block.
|
|
40
|
+
*/
|
|
41
|
+
declare const prepareEDAAnthropicPrompt: (prompt: Prompt.Prompt) => Prompt.Prompt;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ANTHROPIC_THINKING_BINDING_BETA, EDAAnthropicAgentSettings, EDAAnthropicClientOptions, EDAAnthropicModelConfig, anthropicAgentModelConfig, makeEDAAnthropicClientLayer, prepareEDAAnthropicPrompt };
|
|
44
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { i as prepareNativeCompaction, r as makeEDAProviderHttpClient } from "./transport-BzgK07l4.js";
|
|
2
|
+
import { AnthropicClient } from "@effect/ai-anthropic";
|
|
3
|
+
import { isEDACacheBreakpoint } from "effect-durable-agent/services/prompt-projector";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Redacted from "effect/Redacted";
|
|
6
|
+
import * as Prompt from "effect/ai/Prompt";
|
|
7
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
8
|
+
//#region src/providers/anthropic.ts
|
|
9
|
+
/** Anthropic client layer over EDA's provider transport. */
|
|
10
|
+
const makeEDAAnthropicClientLayer = (options) => {
|
|
11
|
+
const apiKey = optionalNonEmptyString(options.apiKey);
|
|
12
|
+
if (apiKey === void 0 && options.aiGateway === void 0) throw new Error("ANTHROPIC_API_KEY is required unless Anthropic traffic goes through a Cloudflare AI Gateway binding with a stored key.");
|
|
13
|
+
return AnthropicClient.layer({
|
|
14
|
+
...apiKey === void 0 ? {} : { apiKey: Redacted.make(apiKey) },
|
|
15
|
+
...options.apiUrl === void 0 ? {} : { apiUrl: options.apiUrl }
|
|
16
|
+
}).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, makeEDAProviderHttpClient({
|
|
17
|
+
provider: "anthropic",
|
|
18
|
+
aiGateway: options.aiGateway,
|
|
19
|
+
anthropicBetas: options.betas
|
|
20
|
+
}))));
|
|
21
|
+
};
|
|
22
|
+
/** Beta that lets requests choose what happens to thinking bound to an edited conversation. */
|
|
23
|
+
const ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
|
|
24
|
+
/** Model config for EDA agent sessions on Anthropic. */
|
|
25
|
+
const anthropicAgentModelConfig = (settings) => {
|
|
26
|
+
const thinking = {
|
|
27
|
+
type: "adaptive",
|
|
28
|
+
display: settings.thinkingDisplay ?? "summarized",
|
|
29
|
+
...settings.prefixMismatchBehavior === void 0 ? {} : { block_binding: { prefix_mismatch_behavior: settings.prefixMismatchBehavior } }
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
max_tokens: settings.maxTokens ?? 64e3,
|
|
33
|
+
output_config: { effort: settings.effort },
|
|
34
|
+
thinking,
|
|
35
|
+
strictJsonSchema: false
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Anthropic prompt preparation: EDA cache hints become `cache_control` breakpoints (end of the
|
|
40
|
+
* instruction prefix and end of durable history), and Anthropic compaction summaries become the
|
|
41
|
+
* transport sentinel that is replayed as the signed `compaction` block.
|
|
42
|
+
*/
|
|
43
|
+
const prepareEDAAnthropicPrompt = (prompt) => prepareNativeCompaction("anthropic", Prompt.fromMessages(prompt.content.map((message) => isEDACacheBreakpoint(message) ? withMessageOptions(message, { anthropic: {
|
|
44
|
+
...anthropicOptions(message.options),
|
|
45
|
+
cacheControl: { type: "ephemeral" }
|
|
46
|
+
} }) : message)));
|
|
47
|
+
const anthropicOptions = (options) => {
|
|
48
|
+
const current = options.anthropic;
|
|
49
|
+
return isJsonObject(current) ? current : {};
|
|
50
|
+
};
|
|
51
|
+
const isJsonObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
+
const withMessageOptions = (message, options) => ({
|
|
53
|
+
...message,
|
|
54
|
+
options: {
|
|
55
|
+
...message.options,
|
|
56
|
+
...options
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const optionalNonEmptyString = (value) => {
|
|
60
|
+
const trimmed = value?.trim();
|
|
61
|
+
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { ANTHROPIC_THINKING_BINDING_BETA, anthropicAgentModelConfig, makeEDAAnthropicClientLayer, prepareEDAAnthropicPrompt };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","names":[],"sources":["../src/providers/anthropic.ts"],"sourcesContent":["import { AnthropicClient, AnthropicLanguageModel } from \"@effect/ai-anthropic\";\nimport { isEDACacheBreakpoint } from \"effect-durable-agent/services/prompt-projector\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport type * as Schema from \"effect/Schema\";\nimport * as Prompt from \"effect/ai/Prompt\";\nimport * as HttpClient from \"effect/http/HttpClient\";\n\nimport { makeEDAProviderHttpClient, prepareNativeCompaction } from \"./transport\";\n\n/** Anthropic request defaults for one resolved model (everything but `model`). */\nexport type EDAAnthropicModelConfig = Omit<typeof AnthropicLanguageModel.Config.Service, \"model\">;\n\n/** Shared Anthropic transport and client options. */\nexport interface EDAAnthropicClientOptions {\n /** Cloudflare AI Gateway binding. With a gateway-stored key (BYOK) no `apiKey` is needed. */\n readonly aiGateway?: AiGateway | undefined;\n readonly apiKey?: string | undefined;\n readonly apiUrl?: string | undefined;\n /** Beta flags sent on every request, e.g. `thinking-binding-controls-2026-08-01`. */\n readonly betas?: ReadonlyArray<string> | undefined;\n}\n\n/** Anthropic client layer over EDA's provider transport. */\nexport const makeEDAAnthropicClientLayer = (\n options: EDAAnthropicClientOptions,\n): Layer.Layer<AnthropicClient.AnthropicClient> => {\n const apiKey = optionalNonEmptyString(options.apiKey);\n if (apiKey === undefined && options.aiGateway === undefined) {\n throw new Error(\n \"ANTHROPIC_API_KEY is required unless Anthropic traffic goes through a Cloudflare AI Gateway binding with a stored key.\",\n );\n }\n return AnthropicClient.layer({\n ...(apiKey === undefined ? {} : { apiKey: Redacted.make(apiKey) }),\n ...(options.apiUrl === undefined ? {} : { apiUrl: options.apiUrl }),\n }).pipe(\n Layer.provide(\n Layer.succeed(\n HttpClient.HttpClient,\n makeEDAProviderHttpClient({\n provider: \"anthropic\",\n aiGateway: options.aiGateway,\n anthropicBetas: options.betas,\n }),\n ),\n ),\n );\n};\n\n/** Beta that lets requests choose what happens to thinking bound to an edited conversation. */\nexport const ANTHROPIC_THINKING_BINDING_BETA = \"thinking-binding-controls-2026-08-01\";\n\n/** Agent request policy for Claude 5.5-generation models. */\nexport interface EDAAnthropicAgentSettings {\n /** Thinking depth; Opus 5.5 cannot disable thinking, so effort is the only control. */\n readonly effort: \"low\" | \"medium\" | \"high\";\n /** Output budget including thinking. Defaults to 64,000. */\n readonly maxTokens?: number | undefined;\n /** `summarized` streams readable reasoning summaries. Defaults to `summarized`. */\n readonly thinkingDisplay?: \"summarized\" | \"omitted\" | undefined;\n /**\n * Explicit preserved-thinking policy (requires {@link ANTHROPIC_THINKING_BINDING_BETA}).\n * `drop_block` degrades instead of failing when replayed thinking no longer matches.\n */\n readonly prefixMismatchBehavior?: \"error\" | \"drop_block\" | undefined;\n}\n\n/** Model config for EDA agent sessions on Anthropic. */\nexport const anthropicAgentModelConfig = (\n settings: EDAAnthropicAgentSettings,\n): EDAAnthropicModelConfig => {\n const thinking = {\n type: \"adaptive\" as const,\n display: settings.thinkingDisplay ?? \"summarized\",\n ...(settings.prefixMismatchBehavior === undefined\n ? {}\n : { block_binding: { prefix_mismatch_behavior: settings.prefixMismatchBehavior } }),\n };\n const config: EDAAnthropicModelConfig = {\n max_tokens: settings.maxTokens ?? 64_000,\n output_config: { effort: settings.effort },\n thinking,\n // EDA tool schemas are not written for strict mode's constraints.\n strictJsonSchema: false,\n };\n return config;\n};\n\n/**\n * Anthropic prompt preparation: EDA cache hints become `cache_control` breakpoints (end of the\n * instruction prefix and end of durable history), and Anthropic compaction summaries become the\n * transport sentinel that is replayed as the signed `compaction` block.\n */\nexport const prepareEDAAnthropicPrompt = (prompt: Prompt.Prompt): Prompt.Prompt =>\n prepareNativeCompaction(\n \"anthropic\",\n Prompt.fromMessages(\n prompt.content.map((message) =>\n isEDACacheBreakpoint(message)\n ? withMessageOptions(message, {\n anthropic: {\n ...anthropicOptions(message.options),\n cacheControl: { type: \"ephemeral\" },\n },\n })\n : message,\n ),\n ),\n );\n\nconst anthropicOptions = (\n options: Prompt.ProviderOptions,\n): Readonly<Record<string, Schema.Json>> => {\n const current = options.anthropic;\n return isJsonObject(current) ? current : {};\n};\n\nconst isJsonObject = (\n value: Schema.Json | null | undefined,\n): value is Readonly<Record<string, Schema.Json>> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst withMessageOptions = (\n message: Prompt.Message,\n options: Prompt.ProviderOptions,\n): Prompt.Message => ({ ...message, options: { ...message.options, ...options } });\n\nconst optionalNonEmptyString = (value: string | undefined): string | undefined => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n};\n"],"mappings":";;;;;;;;;AAwBA,MAAa,+BACX,YACiD;CACjD,MAAM,SAAS,uBAAuB,QAAQ,MAAM;CACpD,IAAI,WAAW,KAAA,KAAa,QAAQ,cAAc,KAAA,GAChD,MAAM,IAAI,MACR,wHACF;CAEF,OAAO,gBAAgB,MAAM;EAC3B,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,SAAS,KAAK,MAAM,EAAE;EAChE,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;CACnE,CAAC,CAAC,CAAC,KACD,MAAM,QACJ,MAAM,QACJ,WAAW,YACX,0BAA0B;EACxB,UAAU;EACV,WAAW,QAAQ;EACnB,gBAAgB,QAAQ;CAC1B,CAAC,CACH,CACF,CACF;AACF;;AAGA,MAAa,kCAAkC;;AAkB/C,MAAa,6BACX,aAC4B;CAC5B,MAAM,WAAW;EACf,MAAM;EACN,SAAS,SAAS,mBAAmB;EACrC,GAAI,SAAS,2BAA2B,KAAA,IACpC,CAAC,IACD,EAAE,eAAe,EAAE,0BAA0B,SAAS,uBAAuB,EAAE;CACrF;CAQA,OAAO;EANL,YAAY,SAAS,aAAa;EAClC,eAAe,EAAE,QAAQ,SAAS,OAAO;EACzC;EAEA,kBAAkB;CAER;AACd;;;;;;AAOA,MAAa,6BAA6B,WACxC,wBACE,aACA,OAAO,aACL,OAAO,QAAQ,KAAK,YAClB,qBAAqB,OAAO,IACxB,mBAAmB,SAAS,EAC1B,WAAW;CACT,GAAG,iBAAiB,QAAQ,OAAO;CACnC,cAAc,EAAE,MAAM,YAAY;AACpC,EACF,CAAC,IACD,OACN,CACF,CACF;AAEF,MAAM,oBACJ,YAC0C;CAC1C,MAAM,UAAU,QAAQ;CACxB,OAAO,aAAa,OAAO,IAAI,UAAU,CAAC;AAC5C;AAEA,MAAM,gBACJ,UAEA,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,MAAM,sBACJ,SACA,aACoB;CAAE,GAAG;CAAS,SAAS;EAAE,GAAG,QAAQ;EAAS,GAAG;CAAQ;AAAE;AAEhF,MAAM,0BAA0B,UAAkD;CAChF,MAAM,UAAU,OAAO,KAAK;CAC5B,OAAO,YAAY,KAAA,KAAa,QAAQ,WAAW,IAAI,KAAA,IAAY;AACrE"}
|
package/dist/durable-object.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as SessionOutcomeInput, i as SessionGrantRunInput, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput } from "./rpc-spec-C8wknrbN.js";
|
|
2
|
-
import { i as EDASessionControllerOptions, l as EDAWebSocketProjection } from "./session-controller-
|
|
2
|
+
import { i as EDASessionControllerOptions, l as EDAWebSocketProjection } from "./session-controller-DoeFP_Ej.js";
|
|
3
3
|
import * as Schema from "effect/Schema";
|
|
4
4
|
import { CommittedDurableEvent } from "effect-durable-agent/services/session-store";
|
|
5
5
|
import { EDARuntimeConfig } from "effect-durable-agent/services/runtime";
|
package/dist/durable-object.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as SessionOutcomeInput, f as encodeEdaRpcDurableEvent, i as SessionGrantRunInput, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput } from "./rpc-spec-CkWEeWJG.js";
|
|
2
|
-
import { t as EDASessionController } from "./session-controller-
|
|
3
|
-
import { durableEventEnvelope } from "effect-durable-agent/types/events/durable";
|
|
2
|
+
import { t as EDASessionController } from "./session-controller-BGfz1DdS.js";
|
|
4
3
|
import * as Effect from "effect/Effect";
|
|
4
|
+
import { durableEventEnvelope } from "effect-durable-agent/types/events/durable";
|
|
5
5
|
import * as Schema from "effect/Schema";
|
|
6
6
|
import { CommandId, RunRequestId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
|
|
7
7
|
import { EDATraceMetadata, makeEDATraceMetadataFromParent, makeRootEDATraceMetadata, parseEDATraceparent } from "effect-durable-agent/types/tracing";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as DurableObjectSqlStorage, n as DurableObjectSessionStoreOptions, r as DurableObjectSqlCursor, t as DurableObjectSessionStorage } from "./durable-object-storage-BZCOHz9p.js";
|
|
2
2
|
import { a as SessionOutcomeInput, i as SessionGrantRunInput, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput } from "./rpc-spec-C8wknrbN.js";
|
|
3
|
-
import { a as EDASessionEventsInput, c as EDASessionSubmitInput, d as EDAWebSocketProjectionInitial, f as EDAWebSocketProjectionResult, h as makeEDADurableObjectRuntimeLayer, i as EDASessionControllerOptions, l as EDAWebSocketProjection, m as EDASessionDurableObjectStorage, n as EDASessionBlockOnCommandInput, o as EDASessionScopedInput, p as EDADurableObjectRuntimeLayerOptions, r as EDASessionController, s as EDASessionSubmitBatchInput, t as EDAPreparedEventWebSocket, u as EDAWebSocketProjectionId } from "./session-controller-
|
|
3
|
+
import { a as EDASessionEventsInput, c as EDASessionSubmitInput, d as EDAWebSocketProjectionInitial, f as EDAWebSocketProjectionResult, h as makeEDADurableObjectRuntimeLayer, i as EDASessionControllerOptions, l as EDAWebSocketProjection, m as EDASessionDurableObjectStorage, n as EDASessionBlockOnCommandInput, o as EDASessionScopedInput, p as EDADurableObjectRuntimeLayerOptions, r as EDASessionController, s as EDASessionSubmitBatchInput, t as EDAPreparedEventWebSocket, u as EDAWebSocketProjectionId } from "./session-controller-DoeFP_Ej.js";
|
|
4
4
|
import { EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionEventsRpcInput, EDASessionGrantRunRpcInput, EDASessionRpcSurface, EDASessionRunRequestOutcomeRpcInput, EDASessionScopedRpcInput, EDASessionSubmitBatchRpcInput, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
|
|
5
|
-
import { EDAOpenAiModelConfig, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer } from "./openai.js";
|
|
5
|
+
import { EDAOpenAiModelConfig, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDAOpenAiClientLayer } from "./openai.js";
|
|
6
6
|
import { a as encodeEdaRpcDurableEvent, i as encodeEdaRpcCommand, n as decodeEdaRpcCommand, o as encodeEdaRpcSubmittables, r as decodeEdaRpcSubmittables, t as EDARpcSubmittable } from "./rpc-codec-B2aLiNqt.js";
|
|
7
|
-
export { DurableObjectSessionStorage, DurableObjectSessionStoreOptions, DurableObjectSqlCursor, DurableObjectSqlStorage, EDADurableObjectRuntimeLayerOptions, EDAOpenAiModelConfig, EDAPreparedEventWebSocket, EDARpcSubmittable, EDASessionBlockOnCommandInput, EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionController, EDASessionControllerOptions, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionDurableObjectStorage, EDASessionEventsInput, EDASessionEventsRpcInput, EDASessionGrantRunRpcInput, EDASessionRpcSurface, EDASessionRunRequestOutcomeRpcInput, EDASessionScopedInput, EDASessionScopedRpcInput, EDASessionSubmitBatchInput, EDASessionSubmitBatchRpcInput, EDASessionSubmitInput, EDAWebSocketProjection, EDAWebSocketProjectionId, EDAWebSocketProjectionInitial, EDAWebSocketProjectionResult, EDA_WEB_SOCKET_PROJECTION_HEADER, SessionBatchInput, SessionBlockInput, SessionCommandInput, SessionGrantRunInput, SessionOutcomeInput, SessionScopedInput, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, edaSessionRpc, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDADurableObjectRuntimeLayer };
|
|
7
|
+
export { DurableObjectSessionStorage, DurableObjectSessionStoreOptions, DurableObjectSqlCursor, DurableObjectSqlStorage, EDADurableObjectRuntimeLayerOptions, EDAOpenAiModelConfig, EDAPreparedEventWebSocket, EDARpcSubmittable, EDASessionBlockOnCommandInput, EDASessionBlockOnCommandRpcInput, EDASessionCommandRpcInput, EDASessionController, EDASessionControllerOptions, EDASessionDurableObject, EDASessionDurableObjectOptions, EDASessionDurableObjectStorage, EDASessionEventsInput, EDASessionEventsRpcInput, EDASessionGrantRunRpcInput, EDASessionRpcSurface, EDASessionRunRequestOutcomeRpcInput, EDASessionScopedInput, EDASessionScopedRpcInput, EDASessionSubmitBatchInput, EDASessionSubmitBatchRpcInput, EDASessionSubmitInput, EDAWebSocketProjection, EDAWebSocketProjectionId, EDAWebSocketProjectionInitial, EDAWebSocketProjectionResult, EDA_WEB_SOCKET_PROJECTION_HEADER, SessionBatchInput, SessionBlockInput, SessionCommandInput, SessionGrantRunInput, SessionOutcomeInput, SessionScopedInput, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, edaSessionRpc, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDADurableObjectRuntimeLayer, makeEDAOpenAiClientLayer };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as SessionOutcomeInput, c as EDARpcSubmittable, d as encodeEdaRpcCommand, f as encodeEdaRpcDurableEvent, i as SessionGrantRunInput, l as decodeEdaRpcCommand, n as SessionBlockInput, o as SessionScopedInput, p as encodeEdaRpcSubmittables, r as SessionCommandInput, s as edaSessionRpc, t as SessionBatchInput, u as decodeEdaRpcSubmittables } from "./rpc-spec-CkWEeWJG.js";
|
|
2
|
-
import { n as EDAWebSocketProjectionId, r as makeEDADurableObjectRuntimeLayer, t as EDASessionController } from "./session-controller-
|
|
2
|
+
import { n as EDAWebSocketProjectionId, r as makeEDADurableObjectRuntimeLayer, t as EDASessionController } from "./session-controller-BGfz1DdS.js";
|
|
3
3
|
import { EDASessionDurableObject, EDA_WEB_SOCKET_PROJECTION_HEADER, edaRuntimeConfig, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcSessionSnapshot, getEDASessionDurableObjectByName } from "./durable-object.js";
|
|
4
4
|
import "./storage.js";
|
|
5
|
-
import { makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer } from "./openai.js";
|
|
6
|
-
export { EDARpcSubmittable, EDASessionController, EDASessionDurableObject, EDAWebSocketProjectionId, EDA_WEB_SOCKET_PROJECTION_HEADER, SessionBatchInput, SessionBlockInput, SessionCommandInput, SessionGrantRunInput, SessionOutcomeInput, SessionScopedInput, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, edaSessionRpc, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDADurableObjectRuntimeLayer };
|
|
5
|
+
import { makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDAOpenAiClientLayer } from "./openai.js";
|
|
6
|
+
export { EDARpcSubmittable, EDASessionController, EDASessionDurableObject, EDAWebSocketProjectionId, EDA_WEB_SOCKET_PROJECTION_HEADER, SessionBatchInput, SessionBlockInput, SessionCommandInput, SessionGrantRunInput, SessionOutcomeInput, SessionScopedInput, decodeEdaRpcCommand, decodeEdaRpcSubmittables, edaRuntimeConfig, edaSessionRpc, encodeEdaRpcCommand, encodeEdaRpcCommittedDurableEvent, encodeEdaRpcDurableEvent, encodeEdaRpcSessionSnapshot, encodeEdaRpcSubmittables, getEDASessionDurableObjectByName, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDADurableObjectRuntimeLayer, makeEDAOpenAiClientLayer };
|
package/dist/openai.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ModelSelectionPayload } from "effect-durable-agent/types/events";
|
|
2
1
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import {
|
|
2
|
+
import { ModelSelectionPayload } from "effect-durable-agent/types/events";
|
|
3
|
+
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai";
|
|
4
4
|
import { ModelResolver } from "effect-durable-agent/services/model-resolver";
|
|
5
5
|
import * as LanguageModel from "effect/ai/LanguageModel";
|
|
6
6
|
//#region src/providers/openai.d.ts
|
|
@@ -24,6 +24,12 @@ declare const makeEDADurableObjectOpenAiModelLayer: (options: {
|
|
|
24
24
|
readonly config?: EDAOpenAiModelConfig;
|
|
25
25
|
readonly modelId: string;
|
|
26
26
|
}) => Layer.Layer<LanguageModel.LanguageModel>;
|
|
27
|
+
/** OpenAI client layer over EDA's provider transport (Cloudflare AI Gateway or `fetch`). */
|
|
28
|
+
declare const makeEDAOpenAiClientLayer: (options: {
|
|
29
|
+
readonly aiGateway?: AiGateway | undefined;
|
|
30
|
+
readonly apiKey?: string | undefined;
|
|
31
|
+
readonly apiUrl?: string | undefined;
|
|
32
|
+
}) => Layer.Layer<OpenAiClient.OpenAiClient>;
|
|
27
33
|
//#endregion
|
|
28
|
-
export { EDAOpenAiModelConfig, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer };
|
|
34
|
+
export { EDAOpenAiModelConfig, makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDAOpenAiClientLayer };
|
|
29
35
|
//# sourceMappingURL=openai.d.ts.map
|
package/dist/openai.js
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { r as makeEDAProviderHttpClient } from "./transport-BzgK07l4.js";
|
|
2
2
|
import * as Layer from "effect/Layer";
|
|
3
|
-
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai";
|
|
4
|
-
import { ModelResolver } from "effect-durable-agent/services/model-resolver";
|
|
5
3
|
import * as Redacted from "effect/Redacted";
|
|
6
|
-
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
7
|
-
import "effect/http/HttpBody";
|
|
8
4
|
import * as HttpClient from "effect/http/HttpClient";
|
|
9
|
-
import * as
|
|
10
|
-
import
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai";
|
|
7
|
+
import { ModelResolver } from "effect-durable-agent/services/model-resolver";
|
|
11
8
|
//#region src/providers/openai.ts
|
|
12
9
|
/** Resolves each durable selection while sharing the provider transport for the runtime lifetime. */
|
|
13
10
|
const makeEDADurableObjectOpenAiModelResolverLayer = (options) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const transport = options.aiGateway === void 0 ? FetchHttpClient.layer : Layer.succeed(HttpClient.HttpClient, makeAiGatewayHttpClient(options.aiGateway));
|
|
17
|
-
const client = OpenAiClient.layer({
|
|
18
|
-
...apiKey === void 0 ? {} : { apiKey: Redacted.make(apiKey) },
|
|
19
|
-
...options.apiUrl === void 0 ? {} : { apiUrl: options.apiUrl }
|
|
20
|
-
}).pipe(Layer.provide(transport));
|
|
11
|
+
if (optionalNonEmptyString(options.apiKey) === void 0 && options.aiGateway === void 0) throw new Error("OPENAI_API_KEY is required unless the EDA OpenAI model resolver is backed by a Cloudflare AI Gateway binding.");
|
|
12
|
+
const client = makeEDAOpenAiClientLayer(options);
|
|
21
13
|
return Layer.effect(ModelResolver, Effect.gen(function* () {
|
|
22
14
|
const provider = yield* OpenAiClient.OpenAiClient;
|
|
23
15
|
return { resolve: Effect.fn("OpenAiModelResolver.resolve")(function* (selection) {
|
|
@@ -31,50 +23,30 @@ const makeEDADurableObjectOpenAiModelResolverLayer = (options) => {
|
|
|
31
23
|
};
|
|
32
24
|
/** OpenAI-backed Effect AI model layer for a Cloudflare Worker. */
|
|
33
25
|
const makeEDADurableObjectOpenAiModelLayer = (options) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const httpClient = options.aiGateway === void 0 ? FetchHttpClient.layer : Layer.succeed(HttpClient.HttpClient, makeAiGatewayHttpClient(options.aiGateway));
|
|
37
|
-
const client = OpenAiClient.layer({
|
|
38
|
-
...apiKey === void 0 ? {} : { apiKey: Redacted.make(apiKey) },
|
|
39
|
-
...options.apiUrl === void 0 ? {} : { apiUrl: options.apiUrl }
|
|
40
|
-
}).pipe(Layer.provide(httpClient));
|
|
26
|
+
if (optionalNonEmptyString(options.apiKey) === void 0 && options.aiGateway === void 0) throw new Error("OPENAI_API_KEY is required unless the EDA OpenAI model layer is backed by a Cloudflare AI Gateway binding.");
|
|
27
|
+
const client = makeEDAOpenAiClientLayer(options);
|
|
41
28
|
return OpenAiLanguageModel.layer({
|
|
42
29
|
model: options.modelId,
|
|
43
30
|
...options.config === void 0 ? {} : { config: options.config }
|
|
44
31
|
}).pipe(Layer.provide(client));
|
|
45
32
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
request,
|
|
58
|
-
cause,
|
|
59
|
-
description: "Cloudflare AI Gateway request failed"
|
|
60
|
-
}) })
|
|
61
|
-
}));
|
|
62
|
-
const endpointFromUrl = (url) => {
|
|
63
|
-
return `${url.pathname.startsWith("/v1/") ? url.pathname.slice(4) : url.pathname.replace(/^\/+/, "")}${url.search}`;
|
|
64
|
-
};
|
|
65
|
-
const requestBody = (body) => {
|
|
66
|
-
switch (body._tag) {
|
|
67
|
-
case "Empty": return;
|
|
68
|
-
case "Raw": return body.body;
|
|
69
|
-
case "Uint8Array": return JSON.parse(new TextDecoder().decode(body.body));
|
|
70
|
-
default: throw new Error(`Unsupported OpenAI request body for Cloudflare AI Gateway: ${body._tag}`);
|
|
71
|
-
}
|
|
33
|
+
/** OpenAI client layer over EDA's provider transport (Cloudflare AI Gateway or `fetch`). */
|
|
34
|
+
const makeEDAOpenAiClientLayer = (options) => {
|
|
35
|
+
const apiKey = optionalNonEmptyString(options.apiKey);
|
|
36
|
+
if (apiKey === void 0 && options.aiGateway === void 0) throw new Error("OPENAI_API_KEY is required unless the EDA OpenAI client is backed by a Cloudflare AI Gateway binding.");
|
|
37
|
+
return OpenAiClient.layer({
|
|
38
|
+
...apiKey === void 0 ? {} : { apiKey: Redacted.make(apiKey) },
|
|
39
|
+
...options.apiUrl === void 0 ? {} : { apiUrl: options.apiUrl }
|
|
40
|
+
}).pipe(Layer.provide(Layer.succeed(HttpClient.HttpClient, makeEDAProviderHttpClient({
|
|
41
|
+
provider: "openai",
|
|
42
|
+
aiGateway: options.aiGateway
|
|
43
|
+
}))));
|
|
72
44
|
};
|
|
73
45
|
const optionalNonEmptyString = (value) => {
|
|
74
46
|
const trimmed = value?.trim();
|
|
75
47
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
76
48
|
};
|
|
77
49
|
//#endregion
|
|
78
|
-
export { makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer };
|
|
50
|
+
export { makeEDADurableObjectOpenAiModelLayer, makeEDADurableObjectOpenAiModelResolverLayer, makeEDAOpenAiClientLayer };
|
|
79
51
|
|
|
80
52
|
//# sourceMappingURL=openai.js.map
|
package/dist/openai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","names":[],"sources":["../src/providers/openai.ts"],"sourcesContent":["import { OpenAiClient, OpenAiLanguageModel } from \"@effect/ai-openai\";\nimport { ModelResolver } from \"effect-durable-agent/services/model-resolver\";\nimport type { ModelSelectionPayload } from \"effect-durable-agent/types/events\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport type * as LanguageModel from \"effect/ai/LanguageModel\";\nimport * as
|
|
1
|
+
{"version":3,"file":"openai.js","names":[],"sources":["../src/providers/openai.ts"],"sourcesContent":["import { OpenAiClient, OpenAiLanguageModel } from \"@effect/ai-openai\";\nimport { ModelResolver } from \"effect-durable-agent/services/model-resolver\";\nimport type { ModelSelectionPayload } from \"effect-durable-agent/types/events\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Redacted from \"effect/Redacted\";\nimport type * as LanguageModel from \"effect/ai/LanguageModel\";\nimport * as HttpClient from \"effect/http/HttpClient\";\n\nimport { makeEDAProviderHttpClient } from \"./transport\";\n\n/** Provider request defaults accepted by EDA's OpenAI Responses model adapter. */\nexport type EDAOpenAiModelConfig = Omit<typeof OpenAiLanguageModel.Config.Service, \"model\">;\n\n/** Resolves each durable selection while sharing the provider transport for the runtime lifetime. */\nexport const makeEDADurableObjectOpenAiModelResolverLayer = (options: {\n readonly aiGateway?: AiGateway;\n readonly apiKey?: string;\n readonly apiUrl?: string;\n readonly resolve: (selection: ModelSelectionPayload | undefined) => {\n readonly modelId: string;\n readonly config: EDAOpenAiModelConfig;\n };\n}): Layer.Layer<ModelResolver> => {\n const apiKey = optionalNonEmptyString(options.apiKey);\n if (apiKey === undefined && options.aiGateway === undefined) {\n throw new Error(\n \"OPENAI_API_KEY is required unless the EDA OpenAI model resolver is backed by a Cloudflare AI Gateway binding.\",\n );\n }\n const client = makeEDAOpenAiClientLayer(options);\n return Layer.effect(\n ModelResolver,\n Effect.gen(function* () {\n const provider = yield* OpenAiClient.OpenAiClient;\n return {\n resolve: Effect.fn(\"OpenAiModelResolver.resolve\")(function* (selection) {\n const resolved = options.resolve(selection);\n return yield* OpenAiLanguageModel.make({\n model: resolved.modelId,\n config: resolved.config,\n }).pipe(Effect.provideService(OpenAiClient.OpenAiClient, provider));\n }),\n };\n }),\n ).pipe(Layer.provide(client));\n};\n\n/** OpenAI-backed Effect AI model layer for a Cloudflare Worker. */\nexport const makeEDADurableObjectOpenAiModelLayer = (options: {\n readonly aiGateway?: AiGateway;\n readonly apiKey?: string;\n readonly apiUrl?: string;\n readonly config?: EDAOpenAiModelConfig;\n readonly modelId: string;\n}): Layer.Layer<LanguageModel.LanguageModel> => {\n const apiKey = optionalNonEmptyString(options.apiKey);\n if (apiKey === undefined && options.aiGateway === undefined) {\n throw new Error(\n \"OPENAI_API_KEY is required unless the EDA OpenAI model layer is backed by a Cloudflare AI Gateway binding.\",\n );\n }\n\n const client = makeEDAOpenAiClientLayer(options);\n\n return OpenAiLanguageModel.layer({\n model: options.modelId,\n ...(options.config === undefined ? {} : { config: options.config }),\n }).pipe(Layer.provide(client));\n};\n\n/** OpenAI client layer over EDA's provider transport (Cloudflare AI Gateway or `fetch`). */\nexport const makeEDAOpenAiClientLayer = (options: {\n readonly aiGateway?: AiGateway | undefined;\n readonly apiKey?: string | undefined;\n readonly apiUrl?: string | undefined;\n}): Layer.Layer<OpenAiClient.OpenAiClient> => {\n const apiKey = optionalNonEmptyString(options.apiKey);\n if (apiKey === undefined && options.aiGateway === undefined) {\n throw new Error(\n \"OPENAI_API_KEY is required unless the EDA OpenAI client is backed by a Cloudflare AI Gateway binding.\",\n );\n }\n return OpenAiClient.layer({\n ...(apiKey === undefined ? {} : { apiKey: Redacted.make(apiKey) }),\n ...(options.apiUrl === undefined ? {} : { apiUrl: options.apiUrl }),\n }).pipe(\n Layer.provide(\n Layer.succeed(\n HttpClient.HttpClient,\n makeEDAProviderHttpClient({ provider: \"openai\", aiGateway: options.aiGateway }),\n ),\n ),\n );\n};\n\nconst optionalNonEmptyString = (value: string | undefined): string | undefined => {\n const trimmed = value?.trim();\n return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;\n};\n"],"mappings":";;;;;;;;;AAeA,MAAa,gDAAgD,YAQ3B;CAEhC,IADe,uBAAuB,QAAQ,MACrC,MAAM,KAAA,KAAa,QAAQ,cAAc,KAAA,GAChD,MAAM,IAAI,MACR,+GACF;CAEF,MAAM,SAAS,yBAAyB,OAAO;CAC/C,OAAO,MAAM,OACX,eACA,OAAO,IAAI,aAAa;EACtB,MAAM,WAAW,OAAO,aAAa;EACrC,OAAO,EACL,SAAS,OAAO,GAAG,6BAA6B,CAAC,CAAC,WAAW,WAAW;GACtE,MAAM,WAAW,QAAQ,QAAQ,SAAS;GAC1C,OAAO,OAAO,oBAAoB,KAAK;IACrC,OAAO,SAAS;IAChB,QAAQ,SAAS;GACnB,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,aAAa,cAAc,QAAQ,CAAC;EACpE,CAAC,EACH;CACF,CAAC,CACH,CAAC,CAAC,KAAK,MAAM,QAAQ,MAAM,CAAC;AAC9B;;AAGA,MAAa,wCAAwC,YAML;CAE9C,IADe,uBAAuB,QAAQ,MACrC,MAAM,KAAA,KAAa,QAAQ,cAAc,KAAA,GAChD,MAAM,IAAI,MACR,4GACF;CAGF,MAAM,SAAS,yBAAyB,OAAO;CAE/C,OAAO,oBAAoB,MAAM;EAC/B,OAAO,QAAQ;EACf,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;CACnE,CAAC,CAAC,CAAC,KAAK,MAAM,QAAQ,MAAM,CAAC;AAC/B;;AAGA,MAAa,4BAA4B,YAIK;CAC5C,MAAM,SAAS,uBAAuB,QAAQ,MAAM;CACpD,IAAI,WAAW,KAAA,KAAa,QAAQ,cAAc,KAAA,GAChD,MAAM,IAAI,MACR,uGACF;CAEF,OAAO,aAAa,MAAM;EACxB,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,SAAS,KAAK,MAAM,EAAE;EAChE,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;CACnE,CAAC,CAAC,CAAC,KACD,MAAM,QACJ,MAAM,QACJ,WAAW,YACX,0BAA0B;EAAE,UAAU;EAAU,WAAW,QAAQ;CAAU,CAAC,CAChF,CACF,CACF;AACF;AAEA,MAAM,0BAA0B,UAAkD;CAChF,MAAM,UAAU,OAAO,KAAK;CAC5B,OAAO,YAAY,KAAA,KAAa,QAAQ,WAAW,IAAI,KAAA,IAAY;AACrE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EDAOpenAiModelConfig } from "./openai.js";
|
|
2
|
+
import { EDAAnthropicClientOptions, EDAAnthropicModelConfig, prepareEDAAnthropicPrompt } from "./anthropic.js";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import { ModelSelectionPayload } from "effect-durable-agent/types/events";
|
|
5
|
+
import { CompactionExecutor } from "effect-durable-agent/services/compaction";
|
|
6
|
+
import { ModelResolver } from "effect-durable-agent/services/model-resolver";
|
|
7
|
+
//#region src/providers/providers.d.ts
|
|
8
|
+
/** Model request settings the host derives from a durable selection. */
|
|
9
|
+
type EDAResolvedModel = {
|
|
10
|
+
readonly provider: "openai";
|
|
11
|
+
readonly modelId: string;
|
|
12
|
+
readonly config: EDAOpenAiModelConfig;
|
|
13
|
+
} | {
|
|
14
|
+
readonly provider: "anthropic";
|
|
15
|
+
readonly modelId: string;
|
|
16
|
+
readonly config: EDAAnthropicModelConfig;
|
|
17
|
+
};
|
|
18
|
+
/** Clients for every provider a host serves; a session runs on the one its selection names. */
|
|
19
|
+
interface EDAMultiProviderModelResolverOptions {
|
|
20
|
+
readonly openai?: {
|
|
21
|
+
readonly aiGateway?: AiGateway | undefined;
|
|
22
|
+
readonly apiKey?: string | undefined;
|
|
23
|
+
readonly apiUrl?: string | undefined;
|
|
24
|
+
};
|
|
25
|
+
readonly anthropic?: EDAAnthropicClientOptions;
|
|
26
|
+
/** Host policy: validate the recorded selection and choose request settings. Throw to reject. */
|
|
27
|
+
readonly resolve: (selection: ModelSelectionPayload | undefined) => EDAResolvedModel;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolves each durable selection to the provider it names, sharing one client per provider for
|
|
31
|
+
* the runtime lifetime, and prepares prompts in that provider's cache and compaction shape.
|
|
32
|
+
*/
|
|
33
|
+
declare const makeEDAMultiProviderModelResolverLayer: (options: EDAMultiProviderModelResolverOptions) => Layer.Layer<ModelResolver>;
|
|
34
|
+
/** Options for provider-native compaction. */
|
|
35
|
+
interface EDANativeCompactionOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Custom summarization prompt for Anthropic (`compaction.instructions`, up to 16,384 characters).
|
|
38
|
+
* OpenAI compaction takes no prompt.
|
|
39
|
+
*/
|
|
40
|
+
readonly anthropicInstructions?: string | undefined;
|
|
41
|
+
/** Output budget for the Anthropic summary call, thinking included. Defaults to 16,000. */
|
|
42
|
+
readonly anthropicMaxTokens?: number | undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Compacts with the session provider's own endpoint: OpenAI `/responses/compact`, Anthropic
|
|
46
|
+
* on-demand compaction (`compact-2026-09-04`). Each call carries the exact earlier request prompt,
|
|
47
|
+
* so it reads the conversation from the provider cache, and the returned native items replace the
|
|
48
|
+
* summarized history on later requests. Other providers fall back to a prompt-prefix summary.
|
|
49
|
+
*/
|
|
50
|
+
declare const makeEDANativeCompactionExecutorLayer: (options?: EDANativeCompactionOptions) => Layer.Layer<CompactionExecutor>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { type EDAAnthropicModelConfig, EDAMultiProviderModelResolverOptions, EDANativeCompactionOptions, type EDAOpenAiModelConfig, EDAResolvedModel, makeEDAMultiProviderModelResolverLayer, makeEDANativeCompactionExecutorLayer, prepareEDAAnthropicPrompt };
|
|
53
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { a as withBeta, i as prepareNativeCompaction, n as EDAProviderRequestOverride, t as ANTHROPIC_COMPACTION_BETA } from "./transport-BzgK07l4.js";
|
|
2
|
+
import { makeEDAAnthropicClientLayer, prepareEDAAnthropicPrompt } from "./anthropic.js";
|
|
3
|
+
import { makeEDAOpenAiClientLayer } from "./openai.js";
|
|
4
|
+
import { AnthropicClient, AnthropicLanguageModel } from "@effect/ai-anthropic";
|
|
5
|
+
import { nativeCompactionSummaryMessage } from "effect-durable-agent/services/prompt-projector";
|
|
6
|
+
import * as Layer from "effect/Layer";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Exit from "effect/Exit";
|
|
9
|
+
import { CompactionExecutorId } from "effect-durable-agent/domain/context-projection";
|
|
10
|
+
import { CompactionError, CompactionExecutor, CompactionOutput, promptPrefixSummaryCompactionExecutor } from "effect-durable-agent/services/compaction";
|
|
11
|
+
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai";
|
|
12
|
+
import { ModelResolver } from "effect-durable-agent/services/model-resolver";
|
|
13
|
+
import { generateTextOfferingTools } from "effect-durable-agent/services/model-call";
|
|
14
|
+
//#region src/providers/providers.ts
|
|
15
|
+
/**
|
|
16
|
+
* Resolves each durable selection to the provider it names, sharing one client per provider for
|
|
17
|
+
* the runtime lifetime, and prepares prompts in that provider's cache and compaction shape.
|
|
18
|
+
*/
|
|
19
|
+
const makeEDAMultiProviderModelResolverLayer = (options) => {
|
|
20
|
+
const openAiClient = options.openai === void 0 ? void 0 : makeEDAOpenAiClientLayer(options.openai);
|
|
21
|
+
const anthropicClient = options.anthropic === void 0 ? void 0 : makeEDAAnthropicClientLayer(options.anthropic);
|
|
22
|
+
return Layer.effect(ModelResolver, Effect.gen(function* () {
|
|
23
|
+
const openAi = openAiClient === void 0 ? void 0 : yield* OpenAiClient.OpenAiClient.pipe(Effect.provide(openAiClient));
|
|
24
|
+
const anthropic = anthropicClient === void 0 ? void 0 : yield* AnthropicClient.AnthropicClient.pipe(Effect.provide(anthropicClient));
|
|
25
|
+
return {
|
|
26
|
+
resolve: Effect.fn("MultiProviderModelResolver.resolve")(function* (selection) {
|
|
27
|
+
const resolved = options.resolve(selection);
|
|
28
|
+
if (resolved.provider === "anthropic") {
|
|
29
|
+
if (anthropic === void 0) return yield* Effect.die(/* @__PURE__ */ new Error("No Anthropic client is configured."));
|
|
30
|
+
return yield* AnthropicLanguageModel.make({
|
|
31
|
+
model: resolved.modelId,
|
|
32
|
+
config: resolved.config
|
|
33
|
+
}).pipe(Effect.provideService(AnthropicClient.AnthropicClient, anthropic));
|
|
34
|
+
}
|
|
35
|
+
if (openAi === void 0) return yield* Effect.die(/* @__PURE__ */ new Error("No OpenAI client is configured."));
|
|
36
|
+
return yield* OpenAiLanguageModel.make({
|
|
37
|
+
model: resolved.modelId,
|
|
38
|
+
config: resolved.config
|
|
39
|
+
}).pipe(Effect.provideService(OpenAiClient.OpenAiClient, openAi));
|
|
40
|
+
}),
|
|
41
|
+
preparePrompt: (selection, prompt) => selection?.provider === "anthropic" ? prepareEDAAnthropicPrompt(prompt) : selection?.provider === "openai" ? prepareNativeCompaction("openai", prompt) : prompt
|
|
42
|
+
};
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Compacts with the session provider's own endpoint: OpenAI `/responses/compact`, Anthropic
|
|
47
|
+
* on-demand compaction (`compact-2026-09-04`). Each call carries the exact earlier request prompt,
|
|
48
|
+
* so it reads the conversation from the provider cache, and the returned native items replace the
|
|
49
|
+
* summarized history on later requests. Other providers fall back to a prompt-prefix summary.
|
|
50
|
+
*/
|
|
51
|
+
const makeEDANativeCompactionExecutorLayer = (options = {}) => Layer.effect(CompactionExecutor, Effect.gen(function* () {
|
|
52
|
+
const fallback = yield* CompactionExecutor.pipe(Effect.provide(promptPrefixSummaryCompactionExecutor()));
|
|
53
|
+
return {
|
|
54
|
+
id: CompactionExecutorId.make("provider-native"),
|
|
55
|
+
execute: (input) => {
|
|
56
|
+
switch (input.state.modelSelection?.provider) {
|
|
57
|
+
case "anthropic": return anthropicCompaction(input, options);
|
|
58
|
+
case "openai": return openAiCompaction(input);
|
|
59
|
+
default: return fallback.execute(input);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}));
|
|
64
|
+
/** Run the adapter's request with an override and return the raw provider response. */
|
|
65
|
+
const callWithOverride = (input, rewrite) => Effect.gen(function* () {
|
|
66
|
+
let captured;
|
|
67
|
+
const exit = yield* generateTextOfferingTools(input.model, input.prompt, input.toolkit).pipe(Effect.provideService(EDAProviderRequestOverride, {
|
|
68
|
+
rewrite,
|
|
69
|
+
onResponse: (status, body) => {
|
|
70
|
+
captured = {
|
|
71
|
+
status,
|
|
72
|
+
body
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}), Effect.exit);
|
|
76
|
+
if (captured === void 0) return yield* new CompactionError({ message: `compaction request failed before a provider response: ${Exit.isFailure(exit) ? String(exit.cause) : "no response"}` });
|
|
77
|
+
if (captured.status < 200 || captured.status >= 300) return yield* new CompactionError({ message: `compaction request failed with ${captured.status}: ${providerErrorMessage(captured.body)}` });
|
|
78
|
+
return captured.body;
|
|
79
|
+
});
|
|
80
|
+
const anthropicCompaction = (input, options) => Effect.gen(function* () {
|
|
81
|
+
const body = yield* callWithOverride(input, (request) => ({
|
|
82
|
+
...request,
|
|
83
|
+
headers: {
|
|
84
|
+
...withBeta(request.headers, ANTHROPIC_COMPACTION_BETA),
|
|
85
|
+
accept: "text/event-stream"
|
|
86
|
+
},
|
|
87
|
+
body: isRecord(request.body) ? {
|
|
88
|
+
...request.body,
|
|
89
|
+
max_tokens: options.anthropicMaxTokens ?? 16e3,
|
|
90
|
+
stream: true,
|
|
91
|
+
compaction: {
|
|
92
|
+
type: "summarize",
|
|
93
|
+
...options.anthropicInstructions === void 0 ? {} : { instructions: options.anthropicInstructions }
|
|
94
|
+
}
|
|
95
|
+
} : request.body
|
|
96
|
+
})).pipe(Effect.map(anthropicMessageFromStream));
|
|
97
|
+
const usage = anthropicCompactionUsage(body);
|
|
98
|
+
const block = isRecord(body) && Array.isArray(body.content) ? body.content[0] : void 0;
|
|
99
|
+
if (!isRecord(body) || body.stop_reason !== "compaction" || !isRecord(block) || block.type !== "compaction" || typeof block.content !== "string" || block.content.trim().length === 0) return yield* new CompactionError({
|
|
100
|
+
message: `anthropic compaction returned no summary (stop_reason ${isRecord(body) ? String(body.stop_reason) : "unknown"})`,
|
|
101
|
+
...usage === void 0 ? {} : { usage }
|
|
102
|
+
});
|
|
103
|
+
const text = block.content.trim();
|
|
104
|
+
return CompactionOutput.make({
|
|
105
|
+
text,
|
|
106
|
+
promptMessage: nativeCompactionSummaryMessage(`Conversation summary:\n\n${text}`, {
|
|
107
|
+
provider: "anthropic",
|
|
108
|
+
modelId: input.state.modelSelection?.modelId ?? "unknown",
|
|
109
|
+
items: [jsonValue(block)]
|
|
110
|
+
}),
|
|
111
|
+
executorId: CompactionExecutorId.make("anthropic-native"),
|
|
112
|
+
...usage === void 0 ? {} : { usage }
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
const openAiCompaction = (input) => Effect.gen(function* () {
|
|
116
|
+
const body = yield* callWithOverride(input, (request) => ({
|
|
117
|
+
...request,
|
|
118
|
+
url: new URL(request.url.pathname.replace(/\/responses$/u, "/responses/compact"), request.url),
|
|
119
|
+
body: isRecord(request.body) ? Object.fromEntries(Object.entries(request.body).filter(([key]) => [
|
|
120
|
+
"model",
|
|
121
|
+
"input",
|
|
122
|
+
"instructions",
|
|
123
|
+
"tools"
|
|
124
|
+
].includes(key))) : request.body
|
|
125
|
+
}));
|
|
126
|
+
const usage = openAiUsage(isRecord(body) ? body.usage : void 0);
|
|
127
|
+
const items = (isRecord(body) && Array.isArray(body.output) ? body.output : []).filter((item) => !(isRecord(item) && (item.role === "developer" || item.role === "system")));
|
|
128
|
+
if (!items.some((item) => isRecord(item) && item.type === "compaction")) return yield* new CompactionError({
|
|
129
|
+
message: "openai compaction returned no compaction item",
|
|
130
|
+
...usage === void 0 ? {} : { usage }
|
|
131
|
+
});
|
|
132
|
+
const text = `Earlier conversation compacted by OpenAI into an encrypted summary (${items.filter((item) => isRecord(item) && item.role === "user").length} user messages retained verbatim).`;
|
|
133
|
+
return CompactionOutput.make({
|
|
134
|
+
text,
|
|
135
|
+
promptMessage: nativeCompactionSummaryMessage(text, {
|
|
136
|
+
provider: "openai",
|
|
137
|
+
modelId: input.state.modelSelection?.modelId ?? "unknown",
|
|
138
|
+
items: items.map(jsonValue)
|
|
139
|
+
}),
|
|
140
|
+
executorId: CompactionExecutorId.make("openai-native"),
|
|
141
|
+
...usage === void 0 ? {} : { usage }
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* Rebuild a Messages API response from its SSE stream. A compaction block arrives whole in its
|
|
146
|
+
* `content_block_start`; usage (with `iterations`) arrives on `message_delta`.
|
|
147
|
+
*/
|
|
148
|
+
const anthropicMessageFromStream = (body) => {
|
|
149
|
+
if (typeof body !== "string") return body;
|
|
150
|
+
let message = {};
|
|
151
|
+
const content = [];
|
|
152
|
+
for (const line of body.split("\n")) {
|
|
153
|
+
if (!line.startsWith("data: ")) continue;
|
|
154
|
+
const event = JSON.parse(line.slice(6));
|
|
155
|
+
if (!isRecord(event)) continue;
|
|
156
|
+
if (event.type === "message_start" && isRecord(event.message)) message = { ...event.message };
|
|
157
|
+
else if (event.type === "content_block_start" && typeof event.index === "number") content[event.index] = event.content_block;
|
|
158
|
+
else if (event.type === "message_delta") {
|
|
159
|
+
const delta = isRecord(event.delta) ? event.delta : {};
|
|
160
|
+
const usage = isRecord(message.usage) ? message.usage : {};
|
|
161
|
+
message = {
|
|
162
|
+
...message,
|
|
163
|
+
...delta,
|
|
164
|
+
usage: {
|
|
165
|
+
...usage,
|
|
166
|
+
...isRecord(event.usage) ? event.usage : {}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
} else if (event.type === "error") return { error: event.error };
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
...message,
|
|
173
|
+
content: content.filter((block) => block !== void 0)
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
/** Anthropic reports compaction cost only in `usage.iterations`; top-level fields are zero. */
|
|
177
|
+
const anthropicCompactionUsage = (body) => {
|
|
178
|
+
const usage = isRecord(body) ? body.usage : void 0;
|
|
179
|
+
const iterations = isRecord(usage) && Array.isArray(usage.iterations) ? usage.iterations : [];
|
|
180
|
+
if (iterations.length === 0) return void 0;
|
|
181
|
+
let uncached = 0;
|
|
182
|
+
let cacheRead = 0;
|
|
183
|
+
let cacheWrite = 0;
|
|
184
|
+
let output = 0;
|
|
185
|
+
for (const iteration of iterations) {
|
|
186
|
+
if (!isRecord(iteration)) continue;
|
|
187
|
+
uncached += count(iteration.input_tokens);
|
|
188
|
+
cacheRead += count(iteration.cache_read_input_tokens);
|
|
189
|
+
cacheWrite += count(iteration.cache_creation_input_tokens);
|
|
190
|
+
output += count(iteration.output_tokens);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
inputTokens: uncached + cacheRead + cacheWrite,
|
|
194
|
+
cachedInputTokens: cacheRead,
|
|
195
|
+
cacheWriteInputTokens: cacheWrite,
|
|
196
|
+
outputTokens: output
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
const openAiUsage = (usage) => {
|
|
200
|
+
if (!isRecord(usage)) return void 0;
|
|
201
|
+
const details = isRecord(usage.input_tokens_details) ? usage.input_tokens_details : {};
|
|
202
|
+
return {
|
|
203
|
+
inputTokens: count(usage.input_tokens),
|
|
204
|
+
cachedInputTokens: count(details.cached_tokens),
|
|
205
|
+
cacheWriteInputTokens: count(details.cache_write_tokens),
|
|
206
|
+
outputTokens: count(usage.output_tokens)
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
const count = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : 0;
|
|
210
|
+
const providerErrorMessage = (body) => {
|
|
211
|
+
if (isRecord(body) && isRecord(body.error) && typeof body.error.message === "string") return body.error.message;
|
|
212
|
+
return typeof body === "string" ? body.slice(0, 500) : JSON.stringify(body).slice(0, 500);
|
|
213
|
+
};
|
|
214
|
+
const jsonValue = (value) => {
|
|
215
|
+
return JSON.parse(JSON.stringify(value) ?? "null");
|
|
216
|
+
};
|
|
217
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
218
|
+
//#endregion
|
|
219
|
+
export { makeEDAMultiProviderModelResolverLayer, makeEDANativeCompactionExecutorLayer, prepareEDAAnthropicPrompt };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=providers.js.map
|