@to11ai/sdk 1.0.0 → 2.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.cjs CHANGED
@@ -39,16 +39,19 @@ var __export = (target, all) => {
39
39
  // src/client.ts
40
40
  var exports_client = {};
41
41
  __export(exports_client, {
42
- gatewayPromptHeaders: () => import_gateway.gatewayPromptHeaders,
43
- gatewayAuthHeaders: () => import_gateway.gatewayAuthHeaders,
42
+ gatewayPromptHeaders: () => import_gateway2.gatewayPromptHeaders,
43
+ gatewayAuthHeaders: () => import_gateway2.gatewayAuthHeaders,
44
44
  envVarNameForKey: () => import_store2.envVarNameForKey,
45
45
  createClient: () => createClient,
46
+ UnknownRoleError: () => import_errors.UnknownRoleError,
47
+ Turn: () => import_context2.Turn,
46
48
  To11aiValidationError: () => import_errors.To11aiValidationError,
47
49
  To11aiRateLimitError: () => import_errors.To11aiRateLimitError,
48
50
  To11aiNetworkError: () => import_errors.To11aiNetworkError,
49
51
  To11aiError: () => import_errors.To11aiError,
50
52
  To11aiAuthError: () => import_errors.To11aiAuthError,
51
53
  To11aiApiError: () => import_errors.To11aiApiError,
54
+ Session: () => import_context2.Session,
52
55
  RuleVersionInvalidSnapshotError: () => import_errors.RuleVersionInvalidSnapshotError,
53
56
  RuleNotFoundError: () => import_errors.RuleNotFoundError,
54
57
  RoutingRulesResource: () => import_resource6.RoutingRulesResource,
@@ -64,29 +67,50 @@ __export(exports_client, {
64
67
  EnvNotFoundError: () => import_errors.EnvNotFoundError,
65
68
  EnvNotEnabledForProviderError: () => import_errors.EnvNotEnabledForProviderError,
66
69
  ENV_SLUG_REGEX: () => import_types2.ENV_SLUG_REGEX,
70
+ Conversation: () => import_context2.Conversation,
67
71
  BehaviorStore: () => import_store2.BehaviorStore,
68
72
  AmbiguousEnvLabelsError: () => import_errors.AmbiguousEnvLabelsError
69
73
  });
70
74
  module.exports = __toCommonJS(exports_client);
71
75
  var import_store = require("./behaviors/store");
76
+ var import_config = require("./config");
77
+ var import_context = require("./context");
78
+ var import_gateway = require("./gateway");
72
79
  var import_resource = require("./projectEnvironments/resource");
73
80
  var import_resource2 = require("./prompts/resource");
74
81
  var import_types = require("./prompts/types");
75
82
  var import_resource3 = require("./routingRules/resource");
76
83
  var import_transport = require("./transport");
77
84
  var import_store2 = require("./behaviors/store");
85
+ var import_context2 = require("./context");
78
86
  var import_errors = require("./errors");
79
- var import_gateway = require("./gateway");
87
+ var import_gateway2 = require("./gateway");
80
88
  var import_resource4 = require("./projectEnvironments/resource");
81
89
  var import_resource5 = require("./prompts/resource");
82
90
  var import_types2 = require("./prompts/types");
83
91
  var import_resource6 = require("./routingRules/resource");
84
- function createClient(options) {
92
+ function createClient(options = {}) {
85
93
  const isDomBrowser = typeof globalThis === "object" && typeof globalThis.document !== "undefined";
86
94
  const workerLikeGlobal = globalThis;
87
95
  const isBunMainThread = workerLikeGlobal.Bun?.isMainThread === true;
88
96
  const isWorkerBrowser = typeof globalThis === "object" && (typeof workerLikeGlobal.importScripts === "function" || !isBunMainThread && typeof workerLikeGlobal.postMessage === "function" && typeof workerLikeGlobal.onmessage !== "undefined");
89
- if ((isDomBrowser || isWorkerBrowser) && options.apiKey !== undefined) {
97
+ const isBrowser = isDomBrowser || isWorkerBrowser;
98
+ const processEnv = !isBrowser && typeof process !== "undefined" && typeof process.env === "object" ? process.env : undefined;
99
+ const pick = (opt, envKey) => {
100
+ const fromOpt = opt?.trim();
101
+ if (fromOpt)
102
+ return fromOpt;
103
+ const fromEnv = processEnv?.[envKey]?.trim();
104
+ return fromEnv ? fromEnv : undefined;
105
+ };
106
+ const baseUrl = pick(options.baseUrl, "TO11_API_URL") ?? import_config.DEFAULT_API_URL;
107
+ const gatewayUrl = (pick(options.gatewayUrl, "TO11_GATEWAY_URL") ?? import_config.DEFAULT_GATEWAY_URL).replace(/\/+$/, "").replace(/\/v1$/, "");
108
+ const getAccessToken = options.getAccessToken;
109
+ const apiKey = getAccessToken !== undefined ? options.apiKey : pick(options.apiKey, "TO11_API_KEY");
110
+ const projectId = pick(options.projectId, "TO11_PROJECT_ID");
111
+ const env = options.env;
112
+ const providerApiKey = options.providerApiKey?.trim() || undefined;
113
+ if (isBrowser && options.apiKey !== undefined) {
90
114
  throw new Error("[to11ai/sdk] Do not use `apiKey` in browser contexts — use `getAccessToken` instead.");
91
115
  }
92
116
  if (options.apiKey !== undefined && options.apiKey.trim() === "") {
@@ -95,39 +119,82 @@ function createClient(options) {
95
119
  if (options.projectId !== undefined && options.projectId.trim() === "") {
96
120
  throw new Error("[to11ai/sdk] `projectId` must not be an empty string — omit it or pass a valid project id.");
97
121
  }
98
- if (options.env !== undefined && !import_types.ENV_SLUG_REGEX.test(options.env)) {
99
- throw new Error(`[to11ai/sdk] \`env\` must match ${import_types.ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(options.env)}`);
122
+ if (env !== undefined && !import_types.ENV_SLUG_REGEX.test(env)) {
123
+ throw new Error(`[to11ai/sdk] \`env\` must match ${import_types.ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
100
124
  }
101
- const hasApiKey = options.apiKey !== undefined;
102
- const hasGetAccessToken = options.getAccessToken !== undefined;
103
- const getAccessToken = options.getAccessToken;
125
+ const hasApiKey = apiKey !== undefined;
126
+ const hasGetAccessToken = getAccessToken !== undefined;
104
127
  if (hasApiKey === hasGetAccessToken) {
105
- throw new Error("[to11ai/sdk] Provide exactly one of `apiKey` (server) or `getAccessToken` (browser).");
128
+ throw new Error("[to11ai/sdk] Provide exactly one of `apiKey` (or `TO11_API_KEY`) or `getAccessToken`.");
106
129
  }
107
- const auth = options.apiKey !== undefined ? { apiKey: options.apiKey } : { getAccessToken };
108
- const isBrowser = isDomBrowser || isWorkerBrowser;
109
- const processEnv = !isBrowser && typeof process !== "undefined" && typeof process.env === "object" ? process.env : undefined;
130
+ const auth = hasApiKey ? { apiKey } : { getAccessToken };
110
131
  const behaviorStore = new import_store.BehaviorStore({
111
132
  initOverrides: options.behaviorOverrides,
112
133
  env: processEnv
113
134
  });
114
135
  const transport = new import_transport.Transport({
115
- baseUrl: options.baseUrl,
136
+ baseUrl,
116
137
  auth,
117
138
  timeoutMs: options.timeoutMs,
118
139
  maxRetries: options.maxRetries,
119
140
  behaviorStore
120
141
  });
121
142
  const prompts = new import_resource2.PromptResource(transport, options.cache, {
122
- projectId: options.projectId,
123
- env: options.env
143
+ projectId,
144
+ env,
145
+ format: options.format,
146
+ onUnknownRole: options.onUnknownRole
124
147
  });
125
148
  const projectEnvironments = new import_resource.ProjectEnvironmentResource(transport);
126
149
  const routingRules = new import_resource3.RoutingRulesResource(transport);
150
+ const gatewayAuthContext = () => {
151
+ if (apiKey === undefined) {
152
+ throw new Error("[to11ai/sdk] session()/turn()/openaiOptions() need an `apiKey` (or `TO11_API_KEY`) — gateway calls require a server-side key. In the browser use `getAccessToken` for control-plane calls only.");
153
+ }
154
+ if (projectId === undefined) {
155
+ throw new Error("[to11ai/sdk] session()/turn() need a `projectId` (or `TO11_PROJECT_ID`).");
156
+ }
157
+ return env !== undefined ? { apiKey, projectId, env } : { apiKey, projectId };
158
+ };
159
+ let defaultSession;
160
+ const clientDefaultSession = () => {
161
+ if (defaultSession === undefined) {
162
+ defaultSession = new import_context.Session(gatewayAuthContext());
163
+ }
164
+ return defaultSession;
165
+ };
166
+ const gatewayClientOptions = (defaultBaseURL, overrides) => {
167
+ if (apiKey === undefined) {
168
+ throw new Error("[to11ai/sdk] openaiOptions()/anthropicOptions() need an `apiKey` (or `TO11_API_KEY`) — gateway calls require a server-side key. In the browser use `getAccessToken` for control-plane calls only.");
169
+ }
170
+ if (projectId === undefined) {
171
+ throw new Error("[to11ai/sdk] openaiOptions()/anthropicOptions() need a `projectId` (or `TO11_PROJECT_ID`) — it authenticates the gateway call via `x-to11-project-id`.");
172
+ }
173
+ const authHeaders = import_gateway.gatewayAuthHeaders(env !== undefined ? { apiKey, projectId, env } : { apiKey, projectId });
174
+ const {
175
+ apiKey: overrideApiKey,
176
+ baseURL: overrideBaseURL,
177
+ defaultHeaders: overrideHeaders,
178
+ ...passthrough
179
+ } = overrides ?? {};
180
+ return {
181
+ ...passthrough,
182
+ baseURL: overrideBaseURL ?? defaultBaseURL,
183
+ apiKey: overrideApiKey ?? providerApiKey ?? apiKey,
184
+ defaultHeaders: { ...authHeaders, ...overrideHeaders }
185
+ };
186
+ };
127
187
  return {
128
188
  prompts,
129
189
  projectEnvironments,
130
190
  routingRules,
131
- resolveBehavior: (key, codedDefault) => behaviorStore.resolve(key, codedDefault)
191
+ resolveBehavior: (key, codedDefault) => behaviorStore.resolve(key, codedDefault),
192
+ apiKey,
193
+ gatewayUrl,
194
+ session: (id) => new import_context.Session(gatewayAuthContext(), id),
195
+ conversation: (id) => clientDefaultSession().conversation(id),
196
+ turn: () => clientDefaultSession().turn(),
197
+ openaiOptions: (overrides) => gatewayClientOptions(`${gatewayUrl}/v1`, overrides),
198
+ anthropicOptions: (overrides) => gatewayClientOptions(gatewayUrl, overrides)
132
199
  };
133
200
  }
package/dist/client.d.ts CHANGED
@@ -1,69 +1,115 @@
1
+ import { type Conversation, Session, type Turn } from "./context";
1
2
  import { ProjectEnvironmentResource } from "./projectEnvironments/resource";
2
3
  import type { CacheConfig } from "./prompts/cache";
3
4
  import { PromptResource } from "./prompts/resource";
5
+ import { type RenderFormat, type UnknownRoleMode } from "./prompts/types";
4
6
  import { RoutingRulesResource } from "./routingRules/resource";
5
7
  export { BehaviorStore, type BehaviorStoreOptions, envVarNameForKey, type SdkBehaviorEnvelope, } from "./behaviors/store";
8
+ export type { TurnAuthContext } from "./context";
9
+ export { Conversation, Session, Turn } from "./context";
6
10
  export type { AmbiguousEnvLabelsReason, EnvNotFoundReason, NoActiveReleaseReason, NoApplicableRouteReason, PromptNotFoundReason, PromptPolicyViolationReason, } from "./errors";
7
- export { AmbiguousEnvLabelsError, EnvNotEnabledForProviderError, EnvNotFoundError, NoActiveReleaseError, NoApplicableRouteError, PromptLabelNotRegisteredError, PromptNotFoundError, PromptPolicyViolationError, RuleNotFoundError, RuleVersionInvalidSnapshotError, To11aiApiError, To11aiAuthError, To11aiError, To11aiNetworkError, To11aiRateLimitError, To11aiValidationError, } from "./errors";
8
- export type { GatewayAuthOptions } from "./gateway";
11
+ export { AmbiguousEnvLabelsError, EnvNotEnabledForProviderError, EnvNotFoundError, NoActiveReleaseError, NoApplicableRouteError, PromptLabelNotRegisteredError, PromptNotFoundError, PromptPolicyViolationError, RuleNotFoundError, RuleVersionInvalidSnapshotError, To11aiApiError, To11aiAuthError, To11aiError, To11aiNetworkError, To11aiRateLimitError, To11aiValidationError, UnknownRoleError, } from "./errors";
12
+ export type { ConvertMessagesOptions, GatewayAuthOptions } from "./gateway";
9
13
  export { gatewayAuthHeaders, gatewayPromptHeaders } from "./gateway";
10
14
  export type { ArchiveProjectEnvironmentInput, ArchiveProjectEnvironmentResult, CreateProjectEnvironmentInput, CreateProjectEnvironmentResult, GetProjectEnvironmentInput, GetProjectEnvironmentResult, ListProjectEnvironmentsInput, ListProjectEnvironmentsResult, LivePointerCounts, ProjectEnvironment, RestoreProjectEnvironmentInput, RestoreProjectEnvironmentResult, UpdateProjectEnvironmentInput, UpdateProjectEnvironmentResult, } from "./projectEnvironments/resource";
11
15
  export { ProjectEnvironmentResource } from "./projectEnvironments/resource";
12
16
  export type { CacheConfig } from "./prompts/cache";
13
17
  export type { PromptResourceConfig } from "./prompts/resource";
14
18
  export { PromptResource } from "./prompts/resource";
15
- export type { BlockRenderRecord, DeveloperRole, FetchedPrompt, FetchPromptOptions, RenderedChatMessage, RenderedPrompt, ResolvedPrompt, ResolvedPromptEnvelope, } from "./prompts/types";
19
+ export type { AnthropicRenderedPrompt, OpenAiRenderedPrompt, PromptConfig, PromptMetadata, RenderResult, } from "./prompts/shape";
20
+ export type { BlockRenderRecord, FetchedPrompt, FetchPromptOptions, RenderedChatMessage, RenderedPrompt, RenderFormat, RenderOptions, ResolvedPrompt, ResolvedPromptEnvelope, UnknownRoleMode, } from "./prompts/types";
16
21
  export { ENV_SLUG_REGEX } from "./prompts/types";
17
22
  export type { CreateRuleVersionInput, CreateRuleVersionResult, GetRuleVersionInput, GetRuleVersionResult, ListRuleReleasesInput, ListRuleReleasesResult, ListRuleVersionsInput, ListRuleVersionsResult, RollbackRuleReleaseInput, RollbackRuleReleaseResult, RuleModelBinding, RuleProviderRef, RuleRelease, RuleReleaseActorType, RuleReleaseApprovalStatus, RuleReleaseChangeKind, RuleReleaseStrategy, RuleReleaseWeight, RuleSnapshot, RuleStrategy, RuleVersion, SetRuleReleaseInput, SetRuleReleaseResult, } from "./routingRules/resource";
18
23
  export { RoutingRuleReleaseResource, RoutingRulesResource, RoutingRuleVersionResource, } from "./routingRules/resource";
19
24
  export type { Transport } from "./transport";
20
- interface ServerAuthOptions {
21
- /** API key for server-side use. Must not be used in browser contexts. */
22
- apiKey: string;
23
- getAccessToken?: never;
24
- }
25
- interface BrowserAuthOptions {
25
+ export interface ClientOptions {
26
+ /**
27
+ * Control-plane base URL. Precedence: this option → `TO11_API_URL` env →
28
+ * `https://api.to11.ai`.
29
+ */
30
+ baseUrl?: string;
31
+ /**
32
+ * Data-plane gateway URL (the app's provider-client `baseURL`). Precedence:
33
+ * this option → `TO11_GATEWAY_URL` env → `https://gw.to11.ai`.
34
+ */
35
+ gatewayUrl?: string;
36
+ /**
37
+ * API key for server-side use. Precedence: this option → `TO11_API_KEY` env.
38
+ * Rejected in browser contexts — use `getAccessToken` there.
39
+ */
40
+ apiKey?: string;
26
41
  /** Token callback for browser / edge contexts — avoids static secrets. */
27
- getAccessToken: () => Promise<string>;
28
- apiKey?: never;
29
- }
30
- type AuthOptions = ServerAuthOptions | BrowserAuthOptions;
31
- export type ClientOptions = AuthOptions & {
32
- baseUrl: string;
42
+ getAccessToken?: () => Promise<string>;
43
+ /**
44
+ * Provider API key (BYOK) carried by `openaiOptions()` / `anthropicOptions()`
45
+ * as the provider client's `apiKey`, so a BYOK call is a single
46
+ * `new OpenAI(to11.openaiOptions())`. When omitted, those helpers fall back to
47
+ * the to11 `apiKey` as a placeholder (the managed / server-side-credential
48
+ * path). Option only — no env fallback. Whether the gateway actually uses this
49
+ * key depends on the provider's passthrough mode; otherwise the project's
50
+ * stored credential wins.
51
+ */
52
+ providerApiKey?: string;
33
53
  /**
34
- * Project the client is bound to (TO11-980 / S9). Required for the
35
- * env-aware `prompts.fetch(slug, …)` surface, which builds the
36
- * project-scoped resolve path from it. Validated non-empty at
37
- * construction. The deprecated `prompts.resolve()` keeps its per-call
38
- * `projectId` and ignores this.
54
+ * Project the client is bound to. Precedence: this option → `TO11_PROJECT_ID`
55
+ * env. Required for `prompts.render()` and the gateway context helpers.
39
56
  */
40
57
  projectId?: string;
41
58
  /**
42
- * Default serving environment for `prompts.fetch(slug)` (TO11-980 / S9,
43
- * Style-A). When set, every `fetch()` call inherits it unless overridden
44
- * per call. Validated eagerly against the project-environments registry
45
- * rule (lowercase-kebab, `^[a-z0-9-]{1,63}$`): empty / whitespace-only /
46
- * uppercase / 64+-char values throw at construction with a loud
47
- * `[to11ai/sdk]` message before any request hits the wire.
59
+ * Default serving environment for `prompts.render(slug)`, inherited by every
60
+ * render unless overridden per call. Validated eagerly against the
61
+ * project-environments slug rule (`^[a-z0-9-]{1,63}$`).
48
62
  */
49
63
  env?: string;
50
- /** LRU cache configuration for resolve(). Defaults: ttlSeconds=300, maxEntries=100 */
64
+ /**
65
+ * Default provider shape for `prompts.render()` output (`"openai"` |
66
+ * `"anthropic"`). Omit for the neutral result. Per-call override allowed.
67
+ */
68
+ format?: RenderFormat;
69
+ /**
70
+ * Default policy for a message with an unrecognized role while shaping
71
+ * `render({ format })` output: `"drop"` (default, silent), `"warn"` (drop +
72
+ * `console.warn`), or `"error"` (throw `UnknownRoleError`). Per-call override
73
+ * via `render(slug, { onUnknownRole })`.
74
+ */
75
+ onUnknownRole?: UnknownRoleMode;
76
+ /** LRU cache configuration for render(). Defaults: ttlSeconds=300, maxEntries=100 */
51
77
  cache?: CacheConfig;
52
78
  /** Request timeout in milliseconds. Default: 30_000 */
53
79
  timeoutMs?: number;
54
80
  /** Max retry attempts for network errors / 5xx. Default: 3 */
55
81
  maxRetries?: number;
56
82
  /**
57
- * Purely local overrides for server-evaluated SDK-behavior flags (TO11-2100),
58
- * keyed by namespaced flag key (e.g. `{ "sdk.retry-v2": true }`). These take
59
- * precedence over server-delivered values and the SDK's coded defaults. For
60
- * the same flag key, an init option here wins over a `TO11_SDK_BEHAVIOR_*`
61
- * environment variable. Published-SDK only — no LaunchDarkly involved.
83
+ * Purely local overrides for server-evaluated SDK-behavior flags (TO11-2100).
84
+ * An init option here wins over a `TO11_SDK_BEHAVIOR_*` env var. No LaunchDarkly.
62
85
  */
63
86
  behaviorOverrides?: Record<string, unknown>;
87
+ }
88
+ /**
89
+ * Overrides accepted by `openaiOptions()` / `anthropicOptions()`. The three
90
+ * known fields are merged (`apiKey` / `baseURL` override; `defaultHeaders`
91
+ * shallow-merges over the tenant-auth headers, caller wins); any other keys —
92
+ * `timeout`, `maxRetries`, `fetch`, … — pass through untouched to the provider
93
+ * client, so `new OpenAI(to11.openaiOptions({ apiKey, timeout }))` needs no
94
+ * outer spread.
95
+ */
96
+ export interface ProviderClientOverrides {
97
+ apiKey?: string;
98
+ baseURL?: string;
99
+ defaultHeaders?: Record<string, string>;
100
+ }
101
+ /**
102
+ * The spread-ready result of `openaiOptions()` / `anthropicOptions()`: the three
103
+ * managed fields plus whatever passthrough keys the caller supplied (their types
104
+ * preserved), so it drops straight into `new OpenAI(...)` / `new Anthropic(...)`.
105
+ */
106
+ export type ProviderClientOptions<T extends ProviderClientOverrides = ProviderClientOverrides> = Omit<T, "apiKey" | "baseURL" | "defaultHeaders"> & {
107
+ baseURL: string;
108
+ apiKey: string;
109
+ defaultHeaders: Record<string, string>;
64
110
  };
65
- export interface To11aiClient {
66
- readonly prompts: PromptResource;
111
+ export interface To11aiClient<F extends RenderFormat | undefined = undefined> {
112
+ readonly prompts: PromptResource<F>;
67
113
  readonly projectEnvironments: ProjectEnvironmentResource;
68
114
  readonly routingRules: RoutingRulesResource;
69
115
  /**
@@ -76,12 +122,67 @@ export interface To11aiClient {
76
122
  * delivered on the envelope.
77
123
  */
78
124
  readonly resolveBehavior: <T>(key: string, codedDefault: T) => T;
125
+ /** Resolved API key (server mode); `undefined` in browser (`getAccessToken`) mode. */
126
+ readonly apiKey: string | undefined;
127
+ /** Resolved data-plane gateway URL (option → `TO11_GATEWAY_URL` → default). */
128
+ readonly gatewayUrl: string;
129
+ /** A new session (unit of work). Pass an id to group telemetry by your own id. */
130
+ session(id?: string): Session;
131
+ /**
132
+ * A conversation in the client's default session (for side / parallel agents).
133
+ *
134
+ * @example Two agents under one session
135
+ * const research = to11.conversation(); // a separate thread from to11.turn()'s default
136
+ * const res = await openai.chat.completions.create(
137
+ * { ...researchPrompt.config, messages },
138
+ * { headers: research.turn().headers(researchPrompt) },
139
+ * );
140
+ */
141
+ conversation(id?: string): Conversation;
142
+ /** A turn in the client's default session + default conversation. */
143
+ turn(): Turn;
144
+ /**
145
+ * Spread-ready options for `new OpenAI(...)` targeting the gateway:
146
+ * `{ baseURL, apiKey, defaultHeaders }` (baseURL carries `/v1`). `defaultHeaders`
147
+ * holds the static tenant auth, so the client authenticates on its own; add
148
+ * `turn().headers(prompt)` per call for trace + prompt provenance. Pass
149
+ * `overrides` to change `apiKey`/`baseURL`, merge extra `defaultHeaders`, or
150
+ * forward any other provider-SDK option (`timeout`, …).
151
+ *
152
+ * @example
153
+ * const openai = new OpenAI(to11.openaiOptions());
154
+ * @example BYOK + a provider-SDK option, no outer spread
155
+ * const openai = new OpenAI(to11.openaiOptions({ apiKey: MY_KEY, timeout: 60_000 }));
156
+ */
157
+ openaiOptions<T extends ProviderClientOverrides = ProviderClientOverrides>(overrides?: T): ProviderClientOptions<T>;
158
+ /**
159
+ * Spread-ready options for `new Anthropic(...)` targeting the gateway root
160
+ * (the Anthropic SDK appends `/v1/messages` itself). Same shape and merge
161
+ * rules as {@link To11aiClient.openaiOptions}.
162
+ */
163
+ anthropicOptions<T extends ProviderClientOverrides = ProviderClientOverrides>(overrides?: T): ProviderClientOptions<T>;
79
164
  }
80
165
  /**
81
- * Create a to11ai SDK client.
166
+ * Create a to11ai SDK client. Resolution precedence differs per option:
167
+ * - URLs (`baseUrl` / `gatewayUrl`) — option → env var → built-in default.
168
+ * - `apiKey` / `projectId` — option → env var (no default).
169
+ * - `env` / `format` — option only.
170
+ * Auth mode:
171
+ * - `apiKey` (or `TO11_API_KEY`) → server-side; rejected in browser contexts.
172
+ * - `getAccessToken` → browser-safe; token fetched per request.
173
+ *
174
+ * @example Minimal setup (single call)
175
+ * import { createClient } from "@to11ai/sdk";
176
+ * import OpenAI from "openai";
82
177
  *
83
- * Auth mode is inferred from options:
84
- * - `apiKey` → server-side; rejected in browser contexts.
85
- * - `getAccessToken` → browser-safe; token fetched per request.
178
+ * const to11 = createClient({ env: "prod", format: "openai" });
179
+ * const openai = new OpenAI(to11.openaiOptions());
180
+ * const prompt = await to11.prompts.render("weather-concierge", { variables: { city: "NYC" } });
181
+ * const res = await openai.chat.completions.create(
182
+ * { ...prompt.config, messages: prompt.messages },
183
+ * { headers: to11.turn().headers(prompt) },
184
+ * );
86
185
  */
87
- export declare function createClient(options: ClientOptions): To11aiClient;
186
+ export declare function createClient<const F extends RenderFormat | undefined = undefined>(options?: Omit<ClientOptions, "format"> & {
187
+ format?: F;
188
+ }): To11aiClient<F>;
package/dist/client.js CHANGED
@@ -1,14 +1,22 @@
1
1
  // src/client.ts
2
2
  import { BehaviorStore } from "./behaviors/store";
3
+ import { DEFAULT_API_URL, DEFAULT_GATEWAY_URL } from "./config";
4
+ import {
5
+ Session
6
+ } from "./context";
7
+ import { gatewayAuthHeaders } from "./gateway";
3
8
  import { ProjectEnvironmentResource } from "./projectEnvironments/resource";
4
9
  import { PromptResource } from "./prompts/resource";
5
- import { ENV_SLUG_REGEX } from "./prompts/types";
10
+ import {
11
+ ENV_SLUG_REGEX
12
+ } from "./prompts/types";
6
13
  import { RoutingRulesResource } from "./routingRules/resource";
7
14
  import { Transport } from "./transport";
8
15
  import {
9
16
  BehaviorStore as BehaviorStore2,
10
17
  envVarNameForKey
11
18
  } from "./behaviors/store";
19
+ import { Conversation, Session as Session2, Turn } from "./context";
12
20
  import {
13
21
  AmbiguousEnvLabelsError,
14
22
  EnvNotEnabledForProviderError,
@@ -25,9 +33,10 @@ import {
25
33
  To11aiError,
26
34
  To11aiNetworkError,
27
35
  To11aiRateLimitError,
28
- To11aiValidationError
36
+ To11aiValidationError,
37
+ UnknownRoleError
29
38
  } from "./errors";
30
- import { gatewayAuthHeaders, gatewayPromptHeaders } from "./gateway";
39
+ import { gatewayAuthHeaders as gatewayAuthHeaders2, gatewayPromptHeaders } from "./gateway";
31
40
  import { ProjectEnvironmentResource as ProjectEnvironmentResource2 } from "./projectEnvironments/resource";
32
41
  import { PromptResource as PromptResource2 } from "./prompts/resource";
33
42
  import { ENV_SLUG_REGEX as ENV_SLUG_REGEX2 } from "./prompts/types";
@@ -36,12 +45,28 @@ import {
36
45
  RoutingRulesResource as RoutingRulesResource2,
37
46
  RoutingRuleVersionResource
38
47
  } from "./routingRules/resource";
39
- function createClient(options) {
48
+ function createClient(options = {}) {
40
49
  const isDomBrowser = typeof globalThis === "object" && typeof globalThis.document !== "undefined";
41
50
  const workerLikeGlobal = globalThis;
42
51
  const isBunMainThread = workerLikeGlobal.Bun?.isMainThread === true;
43
52
  const isWorkerBrowser = typeof globalThis === "object" && (typeof workerLikeGlobal.importScripts === "function" || !isBunMainThread && typeof workerLikeGlobal.postMessage === "function" && typeof workerLikeGlobal.onmessage !== "undefined");
44
- if ((isDomBrowser || isWorkerBrowser) && options.apiKey !== undefined) {
53
+ const isBrowser = isDomBrowser || isWorkerBrowser;
54
+ const processEnv = !isBrowser && typeof process !== "undefined" && typeof process.env === "object" ? process.env : undefined;
55
+ const pick = (opt, envKey) => {
56
+ const fromOpt = opt?.trim();
57
+ if (fromOpt)
58
+ return fromOpt;
59
+ const fromEnv = processEnv?.[envKey]?.trim();
60
+ return fromEnv ? fromEnv : undefined;
61
+ };
62
+ const baseUrl = pick(options.baseUrl, "TO11_API_URL") ?? DEFAULT_API_URL;
63
+ const gatewayUrl = (pick(options.gatewayUrl, "TO11_GATEWAY_URL") ?? DEFAULT_GATEWAY_URL).replace(/\/+$/, "").replace(/\/v1$/, "");
64
+ const getAccessToken = options.getAccessToken;
65
+ const apiKey = getAccessToken !== undefined ? options.apiKey : pick(options.apiKey, "TO11_API_KEY");
66
+ const projectId = pick(options.projectId, "TO11_PROJECT_ID");
67
+ const env = options.env;
68
+ const providerApiKey = options.providerApiKey?.trim() || undefined;
69
+ if (isBrowser && options.apiKey !== undefined) {
45
70
  throw new Error("[to11ai/sdk] Do not use `apiKey` in browser contexts — use `getAccessToken` instead.");
46
71
  }
47
72
  if (options.apiKey !== undefined && options.apiKey.trim() === "") {
@@ -50,53 +75,99 @@ function createClient(options) {
50
75
  if (options.projectId !== undefined && options.projectId.trim() === "") {
51
76
  throw new Error("[to11ai/sdk] `projectId` must not be an empty string — omit it or pass a valid project id.");
52
77
  }
53
- if (options.env !== undefined && !ENV_SLUG_REGEX.test(options.env)) {
54
- throw new Error(`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(options.env)}`);
78
+ if (env !== undefined && !ENV_SLUG_REGEX.test(env)) {
79
+ throw new Error(`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`);
55
80
  }
56
- const hasApiKey = options.apiKey !== undefined;
57
- const hasGetAccessToken = options.getAccessToken !== undefined;
58
- const getAccessToken = options.getAccessToken;
81
+ const hasApiKey = apiKey !== undefined;
82
+ const hasGetAccessToken = getAccessToken !== undefined;
59
83
  if (hasApiKey === hasGetAccessToken) {
60
- throw new Error("[to11ai/sdk] Provide exactly one of `apiKey` (server) or `getAccessToken` (browser).");
84
+ throw new Error("[to11ai/sdk] Provide exactly one of `apiKey` (or `TO11_API_KEY`) or `getAccessToken`.");
61
85
  }
62
- const auth = options.apiKey !== undefined ? { apiKey: options.apiKey } : { getAccessToken };
63
- const isBrowser = isDomBrowser || isWorkerBrowser;
64
- const processEnv = !isBrowser && typeof process !== "undefined" && typeof process.env === "object" ? process.env : undefined;
86
+ const auth = hasApiKey ? { apiKey } : { getAccessToken };
65
87
  const behaviorStore = new BehaviorStore({
66
88
  initOverrides: options.behaviorOverrides,
67
89
  env: processEnv
68
90
  });
69
91
  const transport = new Transport({
70
- baseUrl: options.baseUrl,
92
+ baseUrl,
71
93
  auth,
72
94
  timeoutMs: options.timeoutMs,
73
95
  maxRetries: options.maxRetries,
74
96
  behaviorStore
75
97
  });
76
98
  const prompts = new PromptResource(transport, options.cache, {
77
- projectId: options.projectId,
78
- env: options.env
99
+ projectId,
100
+ env,
101
+ format: options.format,
102
+ onUnknownRole: options.onUnknownRole
79
103
  });
80
104
  const projectEnvironments = new ProjectEnvironmentResource(transport);
81
105
  const routingRules = new RoutingRulesResource(transport);
106
+ const gatewayAuthContext = () => {
107
+ if (apiKey === undefined) {
108
+ throw new Error("[to11ai/sdk] session()/turn()/openaiOptions() need an `apiKey` (or `TO11_API_KEY`) — gateway calls require a server-side key. In the browser use `getAccessToken` for control-plane calls only.");
109
+ }
110
+ if (projectId === undefined) {
111
+ throw new Error("[to11ai/sdk] session()/turn() need a `projectId` (or `TO11_PROJECT_ID`).");
112
+ }
113
+ return env !== undefined ? { apiKey, projectId, env } : { apiKey, projectId };
114
+ };
115
+ let defaultSession;
116
+ const clientDefaultSession = () => {
117
+ if (defaultSession === undefined) {
118
+ defaultSession = new Session(gatewayAuthContext());
119
+ }
120
+ return defaultSession;
121
+ };
122
+ const gatewayClientOptions = (defaultBaseURL, overrides) => {
123
+ if (apiKey === undefined) {
124
+ throw new Error("[to11ai/sdk] openaiOptions()/anthropicOptions() need an `apiKey` (or `TO11_API_KEY`) — gateway calls require a server-side key. In the browser use `getAccessToken` for control-plane calls only.");
125
+ }
126
+ if (projectId === undefined) {
127
+ throw new Error("[to11ai/sdk] openaiOptions()/anthropicOptions() need a `projectId` (or `TO11_PROJECT_ID`) — it authenticates the gateway call via `x-to11-project-id`.");
128
+ }
129
+ const authHeaders = gatewayAuthHeaders(env !== undefined ? { apiKey, projectId, env } : { apiKey, projectId });
130
+ const {
131
+ apiKey: overrideApiKey,
132
+ baseURL: overrideBaseURL,
133
+ defaultHeaders: overrideHeaders,
134
+ ...passthrough
135
+ } = overrides ?? {};
136
+ return {
137
+ ...passthrough,
138
+ baseURL: overrideBaseURL ?? defaultBaseURL,
139
+ apiKey: overrideApiKey ?? providerApiKey ?? apiKey,
140
+ defaultHeaders: { ...authHeaders, ...overrideHeaders }
141
+ };
142
+ };
82
143
  return {
83
144
  prompts,
84
145
  projectEnvironments,
85
146
  routingRules,
86
- resolveBehavior: (key, codedDefault) => behaviorStore.resolve(key, codedDefault)
147
+ resolveBehavior: (key, codedDefault) => behaviorStore.resolve(key, codedDefault),
148
+ apiKey,
149
+ gatewayUrl,
150
+ session: (id) => new Session(gatewayAuthContext(), id),
151
+ conversation: (id) => clientDefaultSession().conversation(id),
152
+ turn: () => clientDefaultSession().turn(),
153
+ openaiOptions: (overrides) => gatewayClientOptions(`${gatewayUrl}/v1`, overrides),
154
+ anthropicOptions: (overrides) => gatewayClientOptions(gatewayUrl, overrides)
87
155
  };
88
156
  }
89
157
  export {
90
158
  gatewayPromptHeaders,
91
- gatewayAuthHeaders,
159
+ gatewayAuthHeaders2 as gatewayAuthHeaders,
92
160
  envVarNameForKey,
93
161
  createClient,
162
+ UnknownRoleError,
163
+ Turn,
94
164
  To11aiValidationError,
95
165
  To11aiRateLimitError,
96
166
  To11aiNetworkError,
97
167
  To11aiError,
98
168
  To11aiAuthError,
99
169
  To11aiApiError,
170
+ Session2 as Session,
100
171
  RuleVersionInvalidSnapshotError,
101
172
  RuleNotFoundError,
102
173
  RoutingRulesResource2 as RoutingRulesResource,
@@ -112,6 +183,7 @@ export {
112
183
  EnvNotFoundError,
113
184
  EnvNotEnabledForProviderError,
114
185
  ENV_SLUG_REGEX2 as ENV_SLUG_REGEX,
186
+ Conversation,
115
187
  BehaviorStore2 as BehaviorStore,
116
188
  AmbiguousEnvLabelsError
117
189
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Internal default endpoints. Deliberately NOT re-exported from the package
3
+ * root: `createClient` resolves the URLs (option → env → default) and exposes
4
+ * the resolved data-plane URL as `to11.gatewayUrl`, so app code never imports a
5
+ * bare URL constant. Keeping these out of the public surface avoids a JS-only
6
+ * exported symbol that would need a Python-parity record.
7
+ */
8
+ export declare const DEFAULT_API_URL = "https://api.to11.ai";
9
+ export declare const DEFAULT_GATEWAY_URL = "https://gw.to11.ai";