@to11ai/sdk 1.1.0 → 2.0.0-rc.10
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 +99 -258
- package/dist/client.cjs +91 -45
- package/dist/client.d.ts +149 -61
- package/dist/client.js +95 -55
- package/dist/config.d.ts +9 -0
- package/dist/context.d.ts +124 -0
- package/dist/errors.cjs +36 -24
- package/dist/errors.d.ts +35 -46
- package/dist/errors.js +36 -24
- package/dist/gateway.cjs +85 -31
- package/dist/gateway.d.ts +102 -27
- package/dist/gateway.js +85 -31
- package/dist/generated/index.d.ts +1 -1
- package/dist/generated/types.gen.d.ts +2802 -502
- package/dist/generated/zod.gen.d.ts +1018 -243
- package/dist/prompts/resource.cjs +80 -113
- package/dist/prompts/resource.d.ts +60 -39
- package/dist/prompts/resource.js +84 -113
- package/dist/prompts/shape.d.ts +56 -0
- package/dist/prompts/types.d.ts +76 -61
- package/dist/transport.d.ts +2 -6
- package/package.json +5 -11
- package/src/client.ts +332 -157
- package/src/config.ts +13 -0
- package/src/context.ts +196 -0
- package/src/errors.ts +65 -79
- package/src/gateway.ts +212 -67
- package/src/generated/index.ts +1 -1
- package/src/generated/types.gen.ts +2977 -611
- package/src/generated/zod.gen.ts +1029 -338
- package/src/prompts/resource.ts +211 -226
- package/src/prompts/shape.ts +152 -0
- package/src/prompts/types.ts +77 -65
- package/src/transport.ts +53 -40
- package/dist/prompts/cache.d.ts +0 -59
- package/dist/routingRules/resource.cjs +0 -138
- package/dist/routingRules/resource.js +0 -98
- package/src/prompts/cache.ts +0 -157
package/dist/transport.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { BehaviorStore } from "./behaviors/store";
|
|
2
|
-
export
|
|
2
|
+
export interface AuthConfig {
|
|
3
3
|
readonly apiKey: string;
|
|
4
|
-
|
|
5
|
-
} | {
|
|
6
|
-
readonly getAccessToken: () => Promise<string>;
|
|
7
|
-
readonly apiKey?: never;
|
|
8
|
-
};
|
|
4
|
+
}
|
|
9
5
|
export interface TransportConfig {
|
|
10
6
|
readonly baseUrl: string;
|
|
11
7
|
readonly auth: AuthConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@to11ai/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-rc.10",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -44,14 +44,6 @@
|
|
|
44
44
|
"require": "./dist/projectEnvironments/resource.cjs",
|
|
45
45
|
"default": "./dist/projectEnvironments/resource.js"
|
|
46
46
|
},
|
|
47
|
-
"./routingRules": {
|
|
48
|
-
"types": "./dist/routingRules/resource.d.ts",
|
|
49
|
-
"bun": "./src/routingRules/resource.ts",
|
|
50
|
-
"deno": "./src/routingRules/resource.ts",
|
|
51
|
-
"import": "./dist/routingRules/resource.js",
|
|
52
|
-
"require": "./dist/routingRules/resource.cjs",
|
|
53
|
-
"default": "./dist/routingRules/resource.js"
|
|
54
|
-
},
|
|
55
47
|
"./errors": {
|
|
56
48
|
"types": "./dist/errors.d.ts",
|
|
57
49
|
"bun": "./src/errors.ts",
|
|
@@ -75,8 +67,8 @@
|
|
|
75
67
|
"scripts": {
|
|
76
68
|
"build": "bun run build:clean && bun run build:esm && bun run build:cjs && bun run build:types",
|
|
77
69
|
"build:clean": "rm -rf dist",
|
|
78
|
-
"build:esm": "bun build src/client.ts src/prompts/resource.ts src/projectEnvironments/resource.ts src/
|
|
79
|
-
"build:cjs": "bun build src/client.ts src/prompts/resource.ts src/projectEnvironments/resource.ts src/
|
|
70
|
+
"build:esm": "bun build src/client.ts src/prompts/resource.ts src/projectEnvironments/resource.ts src/errors.ts src/gateway.ts --outdir dist --target node --format esm --external '*'",
|
|
71
|
+
"build:cjs": "bun build src/client.ts src/prompts/resource.ts src/projectEnvironments/resource.ts src/errors.ts src/gateway.ts --outdir dist --target node --format cjs --external '*' --entry-naming '[dir]/[name].cjs'",
|
|
80
72
|
"build:types": "tsc -p tsconfig.build.json",
|
|
81
73
|
"prepack": "bun run build",
|
|
82
74
|
"codegen": "openapi-ts",
|
|
@@ -90,10 +82,12 @@
|
|
|
90
82
|
"format": "biome format --write ."
|
|
91
83
|
},
|
|
92
84
|
"devDependencies": {
|
|
85
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
93
86
|
"@biomejs/biome": "2.4.16",
|
|
94
87
|
"@hey-api/openapi-ts": "0.98.2",
|
|
95
88
|
"@opentelemetry/api": "^1.9.1",
|
|
96
89
|
"@types/bun": "^1.3.14",
|
|
90
|
+
"openai": "^4.67.0",
|
|
97
91
|
"typescript": "^6.0.3"
|
|
98
92
|
},
|
|
99
93
|
"dependencies": {
|
package/src/client.ts
CHANGED
|
@@ -1,47 +1,46 @@
|
|
|
1
1
|
import { BehaviorStore } from "./behaviors/store";
|
|
2
|
+
import { DEFAULT_API_URL, DEFAULT_GATEWAY_URL } from "./config";
|
|
3
|
+
import {
|
|
4
|
+
type Conversation,
|
|
5
|
+
Session,
|
|
6
|
+
type Turn,
|
|
7
|
+
type TurnAuthContext,
|
|
8
|
+
} from "./context";
|
|
9
|
+
import { gatewayAuthHeaders } from "./gateway";
|
|
2
10
|
import { ProjectEnvironmentResource } from "./projectEnvironments/resource";
|
|
3
|
-
import type { CacheConfig } from "./prompts/cache";
|
|
4
11
|
import { PromptResource } from "./prompts/resource";
|
|
5
|
-
import {
|
|
6
|
-
|
|
12
|
+
import {
|
|
13
|
+
ENV_SLUG_REGEX,
|
|
14
|
+
type RenderFormat,
|
|
15
|
+
type UnknownRoleMode,
|
|
16
|
+
} from "./prompts/types";
|
|
7
17
|
import { Transport } from "./transport";
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
BehaviorStore,
|
|
12
|
-
type BehaviorStoreOptions,
|
|
13
|
-
envVarNameForKey,
|
|
14
|
-
type SdkBehaviorEnvelope,
|
|
15
|
-
} from "./behaviors/store";
|
|
19
|
+
export type { TurnAuthContext } from "./context";
|
|
20
|
+
export { Conversation, Session, Turn } from "./context";
|
|
16
21
|
// Re-export all error types for convenience
|
|
17
22
|
export type {
|
|
18
|
-
AmbiguousEnvLabelsReason,
|
|
19
|
-
EnvNotFoundReason,
|
|
20
23
|
NoActiveReleaseReason,
|
|
21
|
-
NoApplicableRouteReason,
|
|
22
24
|
PromptNotFoundReason,
|
|
23
25
|
PromptPolicyViolationReason,
|
|
24
26
|
} from "./errors";
|
|
25
27
|
export {
|
|
26
28
|
// TO11-980 (S9) prompt-resolution typed errors.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
EnvNotFoundError,
|
|
29
|
+
LabelNotFoundError,
|
|
30
|
+
MissingLabelError,
|
|
30
31
|
NoActiveReleaseError,
|
|
31
|
-
NoApplicableRouteError,
|
|
32
32
|
PromptLabelNotRegisteredError,
|
|
33
33
|
PromptNotFoundError,
|
|
34
34
|
PromptPolicyViolationError,
|
|
35
|
-
RuleNotFoundError,
|
|
36
|
-
RuleVersionInvalidSnapshotError,
|
|
37
35
|
To11aiApiError,
|
|
38
36
|
To11aiAuthError,
|
|
39
37
|
To11aiError,
|
|
40
38
|
To11aiNetworkError,
|
|
41
39
|
To11aiRateLimitError,
|
|
42
40
|
To11aiValidationError,
|
|
41
|
+
UnknownRoleError,
|
|
43
42
|
} from "./errors";
|
|
44
|
-
export type { GatewayAuthOptions } from "./gateway";
|
|
43
|
+
export type { ConvertMessagesOptions, GatewayAuthOptions } from "./gateway";
|
|
45
44
|
export { gatewayAuthHeaders, gatewayPromptHeaders } from "./gateway";
|
|
46
45
|
export type {
|
|
47
46
|
ArchiveProjectEnvironmentInput,
|
|
@@ -60,134 +59,204 @@ export type {
|
|
|
60
59
|
UpdateProjectEnvironmentResult,
|
|
61
60
|
} from "./projectEnvironments/resource";
|
|
62
61
|
export { ProjectEnvironmentResource } from "./projectEnvironments/resource";
|
|
63
|
-
export type { CacheConfig } from "./prompts/cache";
|
|
64
62
|
export type { PromptResourceConfig } from "./prompts/resource";
|
|
65
63
|
export { PromptResource } from "./prompts/resource";
|
|
66
|
-
|
|
64
|
+
export type {
|
|
65
|
+
AnthropicRenderedPrompt,
|
|
66
|
+
OpenAiRenderedPrompt,
|
|
67
|
+
PromptConfig,
|
|
68
|
+
PromptMetadata,
|
|
69
|
+
RenderResult,
|
|
70
|
+
} from "./prompts/shape";
|
|
71
|
+
// TO11-980 (S9): env-aware render() surface types at the package entrypoint (AC9).
|
|
67
72
|
export type {
|
|
68
73
|
BlockRenderRecord,
|
|
69
|
-
DeveloperRole,
|
|
70
|
-
FetchedPrompt,
|
|
71
|
-
FetchPromptOptions,
|
|
72
74
|
RenderedChatMessage,
|
|
73
75
|
RenderedPrompt,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
RenderFormat,
|
|
77
|
+
RenderOptions,
|
|
78
|
+
UnknownRoleMode,
|
|
76
79
|
} from "./prompts/types";
|
|
77
80
|
export { ENV_SLUG_REGEX } from "./prompts/types";
|
|
78
|
-
export type {
|
|
79
|
-
CreateRuleVersionInput,
|
|
80
|
-
CreateRuleVersionResult,
|
|
81
|
-
GetRuleVersionInput,
|
|
82
|
-
GetRuleVersionResult,
|
|
83
|
-
ListRuleReleasesInput,
|
|
84
|
-
ListRuleReleasesResult,
|
|
85
|
-
ListRuleVersionsInput,
|
|
86
|
-
ListRuleVersionsResult,
|
|
87
|
-
RollbackRuleReleaseInput,
|
|
88
|
-
RollbackRuleReleaseResult,
|
|
89
|
-
RuleModelBinding,
|
|
90
|
-
RuleProviderRef,
|
|
91
|
-
RuleRelease,
|
|
92
|
-
RuleReleaseActorType,
|
|
93
|
-
RuleReleaseApprovalStatus,
|
|
94
|
-
RuleReleaseChangeKind,
|
|
95
|
-
RuleReleaseStrategy,
|
|
96
|
-
RuleReleaseWeight,
|
|
97
|
-
RuleSnapshot,
|
|
98
|
-
RuleStrategy,
|
|
99
|
-
RuleVersion,
|
|
100
|
-
SetRuleReleaseInput,
|
|
101
|
-
SetRuleReleaseResult,
|
|
102
|
-
} from "./routingRules/resource";
|
|
103
|
-
export {
|
|
104
|
-
RoutingRuleReleaseResource,
|
|
105
|
-
RoutingRulesResource,
|
|
106
|
-
RoutingRuleVersionResource,
|
|
107
|
-
} from "./routingRules/resource";
|
|
108
|
-
export type { Transport } from "./transport";
|
|
109
|
-
|
|
110
|
-
// ─── Auth option shapes ────────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
interface ServerAuthOptions {
|
|
113
|
-
/** API key for server-side use. Must not be used in browser contexts. */
|
|
114
|
-
apiKey: string;
|
|
115
|
-
getAccessToken?: never;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
interface BrowserAuthOptions {
|
|
119
|
-
/** Token callback for browser / edge contexts — avoids static secrets. */
|
|
120
|
-
getAccessToken: () => Promise<string>;
|
|
121
|
-
apiKey?: never;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
type AuthOptions = ServerAuthOptions | BrowserAuthOptions;
|
|
125
81
|
|
|
126
82
|
// ─── Client options ────────────────────────────────────────────────────────
|
|
127
83
|
|
|
128
|
-
export
|
|
129
|
-
|
|
84
|
+
export interface ClientOptions {
|
|
85
|
+
/**
|
|
86
|
+
* Control-plane base URL. Precedence: this option → `TO11_API_URL` env →
|
|
87
|
+
* `https://api.to11.ai`.
|
|
88
|
+
*/
|
|
89
|
+
baseUrl?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Data-plane gateway URL (the app's provider-client `baseURL`). Precedence:
|
|
92
|
+
* this option → `TO11_GATEWAY_URL` env → `https://gw.to11.ai`.
|
|
93
|
+
*/
|
|
94
|
+
gatewayUrl?: string;
|
|
95
|
+
/**
|
|
96
|
+
* API key for server-side use (server, CLI, backend job). Precedence: this
|
|
97
|
+
* option → `TO11_API_KEY` env. Required. Rejected in browser contexts — a
|
|
98
|
+
* to11 API key carries gateway access and must never ship in client code.
|
|
99
|
+
*/
|
|
100
|
+
apiKey?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Provider API key (BYOK) carried by `openaiOptions()` / `anthropicOptions()`
|
|
103
|
+
* as the provider client's `apiKey`, so a BYOK call is a single
|
|
104
|
+
* `new OpenAI(to11.openaiOptions())`. When omitted, those helpers fall back to
|
|
105
|
+
* the to11 `apiKey` as a placeholder (the managed / server-side-credential
|
|
106
|
+
* path). Option only — no env fallback. Whether the gateway actually uses this
|
|
107
|
+
* key depends on the provider's passthrough mode; otherwise the project's
|
|
108
|
+
* stored credential wins.
|
|
109
|
+
*/
|
|
110
|
+
providerApiKey?: string;
|
|
130
111
|
/**
|
|
131
|
-
* Project the client is bound to
|
|
132
|
-
* env
|
|
133
|
-
* project-scoped resolve path from it. Validated non-empty at
|
|
134
|
-
* construction. The deprecated `prompts.resolve()` keeps its per-call
|
|
135
|
-
* `projectId` and ignores this.
|
|
112
|
+
* Project the client is bound to. Precedence: this option → `TO11_PROJECT_ID`
|
|
113
|
+
* env. Required for `prompts.render()` and the gateway context helpers.
|
|
136
114
|
*/
|
|
137
115
|
projectId?: string;
|
|
138
116
|
/**
|
|
139
|
-
* Default serving environment for `prompts.
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* uppercase / 64+-char values throw at construction with a loud
|
|
144
|
-
* `[to11ai/sdk]` message before any request hits the wire.
|
|
117
|
+
* Default serving environment for `prompts.render(slug)`, inherited by every
|
|
118
|
+
* render unless overridden per call. Precedence: this option → `TO11_ENV`
|
|
119
|
+
* env. Validated eagerly against the project-environments slug rule
|
|
120
|
+
* (`^[a-z0-9-]{1,63}$`).
|
|
145
121
|
*/
|
|
146
122
|
env?: string;
|
|
147
|
-
/**
|
|
148
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Default provider shape for `prompts.render()` output (`"openai"` |
|
|
125
|
+
* `"anthropic"`). Omit for the neutral result. Per-call override allowed.
|
|
126
|
+
*/
|
|
127
|
+
format?: RenderFormat;
|
|
128
|
+
/**
|
|
129
|
+
* Default policy for a message with an unrecognized role while shaping
|
|
130
|
+
* `render({ format })` output: `"drop"` (default, silent), `"warn"` (drop +
|
|
131
|
+
* `console.warn`), or `"error"` (throw `UnknownRoleError`). Per-call override
|
|
132
|
+
* via `render(slug, { onUnknownRole })`.
|
|
133
|
+
*/
|
|
134
|
+
onUnknownRole?: UnknownRoleMode;
|
|
149
135
|
/** Request timeout in milliseconds. Default: 30_000 */
|
|
150
136
|
timeoutMs?: number;
|
|
151
137
|
/** Max retry attempts for network errors / 5xx. Default: 3 */
|
|
152
138
|
maxRetries?: number;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Provider-client options (openaiOptions / anthropicOptions) ─────────────
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Overrides accepted by `openaiOptions()` / `anthropicOptions()`. The three
|
|
145
|
+
* known fields are merged (`apiKey` / `baseURL` override; `defaultHeaders`
|
|
146
|
+
* shallow-merges over the tenant-auth headers, caller wins); any other keys —
|
|
147
|
+
* `timeout`, `maxRetries`, `fetch`, … — pass through untouched to the provider
|
|
148
|
+
* client, so `new OpenAI(to11.openaiOptions({ apiKey, timeout }))` needs no
|
|
149
|
+
* outer spread.
|
|
150
|
+
*/
|
|
151
|
+
export interface ProviderClientOverrides {
|
|
152
|
+
apiKey?: string;
|
|
153
|
+
baseURL?: string;
|
|
154
|
+
defaultHeaders?: Record<string, string>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The spread-ready result of `openaiOptions()` / `anthropicOptions()`: the three
|
|
159
|
+
* managed fields plus whatever passthrough keys the caller supplied (their types
|
|
160
|
+
* preserved), so it drops straight into `new OpenAI(...)` / `new Anthropic(...)`.
|
|
161
|
+
*/
|
|
162
|
+
export type ProviderClientOptions<
|
|
163
|
+
T extends ProviderClientOverrides = ProviderClientOverrides,
|
|
164
|
+
> = Omit<T, "apiKey" | "baseURL" | "defaultHeaders"> & {
|
|
165
|
+
baseURL: string;
|
|
166
|
+
apiKey: string;
|
|
167
|
+
defaultHeaders: Record<string, string>;
|
|
161
168
|
};
|
|
162
169
|
|
|
163
170
|
// ─── Client interface ──────────────────────────────────────────────────────
|
|
164
171
|
|
|
165
|
-
export interface To11aiClient {
|
|
166
|
-
readonly prompts: PromptResource
|
|
172
|
+
export interface To11aiClient<F extends RenderFormat | undefined = undefined> {
|
|
173
|
+
readonly prompts: PromptResource<F>;
|
|
167
174
|
readonly projectEnvironments: ProjectEnvironmentResource;
|
|
168
|
-
|
|
175
|
+
/** Resolved API key (option → `TO11_API_KEY`). */
|
|
176
|
+
readonly apiKey: string;
|
|
177
|
+
/** Resolved control-plane base URL (option → `TO11_API_URL` → default). */
|
|
178
|
+
readonly baseUrl: string;
|
|
179
|
+
/** Resolved data-plane gateway URL (option → `TO11_GATEWAY_URL` → default). */
|
|
180
|
+
readonly gatewayUrl: string;
|
|
181
|
+
/**
|
|
182
|
+
* Resolved project id (option → `TO11_PROJECT_ID`); `undefined` when none is
|
|
183
|
+
* configured. Read-only, for your own logging / manual headers — `prompts.*`
|
|
184
|
+
* already default to it, so you don't need to pass it back into calls.
|
|
185
|
+
*/
|
|
186
|
+
readonly projectId: string | undefined;
|
|
169
187
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* var) → server-delivered value (captured from responses the client has
|
|
173
|
-
* already made) → the `codedDefault` passed here. A value whose runtime type
|
|
174
|
-
* disagrees with `codedDefault` falls through to the next tier. The SDK
|
|
175
|
-
* carries no LaunchDarkly dependency; this only reads what the server
|
|
176
|
-
* delivered on the envelope.
|
|
188
|
+
* Resolved default serving environment (option → `TO11_ENV`); `undefined`
|
|
189
|
+
* when none is configured. `prompts.render()` already defaults to it.
|
|
177
190
|
*/
|
|
178
|
-
readonly
|
|
191
|
+
readonly env: string | undefined;
|
|
192
|
+
/** A new session (unit of work). Pass an id to group telemetry by your own id. */
|
|
193
|
+
session(id?: string): Session;
|
|
194
|
+
/**
|
|
195
|
+
* A conversation in the client's default session (for side / parallel agents).
|
|
196
|
+
*
|
|
197
|
+
* @example Two agents under one session
|
|
198
|
+
* const research = to11.conversation(); // a separate thread from to11.turn()'s default
|
|
199
|
+
* const res = await openai.chat.completions.create(
|
|
200
|
+
* { ...researchPrompt.config, messages },
|
|
201
|
+
* { headers: research.turn().headers(researchPrompt) },
|
|
202
|
+
* );
|
|
203
|
+
*/
|
|
204
|
+
conversation(id?: string): Conversation;
|
|
205
|
+
/** A turn in the client's default session + default conversation. */
|
|
206
|
+
turn(): Turn;
|
|
207
|
+
/**
|
|
208
|
+
* Spread-ready options for `new OpenAI(...)` targeting the gateway:
|
|
209
|
+
* `{ baseURL, apiKey, defaultHeaders }` (baseURL carries `/v1`). `defaultHeaders`
|
|
210
|
+
* holds the static tenant auth, so the client authenticates on its own; add
|
|
211
|
+
* `turn().headers(prompt)` per call for trace + prompt provenance. Pass
|
|
212
|
+
* `overrides` to change `apiKey`/`baseURL`, merge extra `defaultHeaders`, or
|
|
213
|
+
* forward any other provider-SDK option (`timeout`, …).
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* const openai = new OpenAI(to11.openaiOptions());
|
|
217
|
+
* @example BYOK + a provider-SDK option, no outer spread
|
|
218
|
+
* const openai = new OpenAI(to11.openaiOptions({ apiKey: MY_KEY, timeout: 60_000 }));
|
|
219
|
+
*/
|
|
220
|
+
openaiOptions<T extends ProviderClientOverrides = ProviderClientOverrides>(
|
|
221
|
+
overrides?: T,
|
|
222
|
+
): ProviderClientOptions<T>;
|
|
223
|
+
/**
|
|
224
|
+
* Spread-ready options for `new Anthropic(...)` targeting the gateway root
|
|
225
|
+
* (the Anthropic SDK appends `/v1/messages` itself). Same shape and merge
|
|
226
|
+
* rules as {@link To11aiClient.openaiOptions}.
|
|
227
|
+
*/
|
|
228
|
+
anthropicOptions<T extends ProviderClientOverrides = ProviderClientOverrides>(
|
|
229
|
+
overrides?: T,
|
|
230
|
+
): ProviderClientOptions<T>;
|
|
179
231
|
}
|
|
180
232
|
|
|
181
233
|
// ─── Factory ───────────────────────────────────────────────────────────────
|
|
182
234
|
|
|
183
235
|
/**
|
|
184
|
-
* Create a to11ai SDK client.
|
|
236
|
+
* Create a to11ai SDK client. Resolution precedence differs per option:
|
|
237
|
+
* - URLs (`baseUrl` / `gatewayUrl`) — option → env var → built-in default.
|
|
238
|
+
* - `apiKey` / `projectId` — option → env var (no default).
|
|
239
|
+
* - `env` / `format` — option only.
|
|
240
|
+
* Authenticate with `apiKey` (or `TO11_API_KEY`) — required, and server-side
|
|
241
|
+
* only (server, CLI, backend job); constructing with `apiKey` in a browser throws.
|
|
242
|
+
*
|
|
243
|
+
* @example Minimal setup (single call)
|
|
244
|
+
* import { createClient } from "@to11ai/sdk";
|
|
245
|
+
* import OpenAI from "openai";
|
|
185
246
|
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
247
|
+
* const to11 = createClient({ env: "prod", format: "openai" });
|
|
248
|
+
* const openai = new OpenAI(to11.openaiOptions());
|
|
249
|
+
* const prompt = await to11.prompts.render("weather-concierge", { variables: { city: "NYC" } });
|
|
250
|
+
* const res = await openai.chat.completions.create(
|
|
251
|
+
* { ...prompt.config, messages: prompt.messages },
|
|
252
|
+
* { headers: to11.turn().headers(prompt) },
|
|
253
|
+
* );
|
|
189
254
|
*/
|
|
190
|
-
export function createClient
|
|
255
|
+
export function createClient<
|
|
256
|
+
const F extends RenderFormat | undefined = undefined,
|
|
257
|
+
>(
|
|
258
|
+
options: Omit<ClientOptions, "format"> & { format?: F } = {},
|
|
259
|
+
): To11aiClient<F> {
|
|
191
260
|
const isDomBrowser =
|
|
192
261
|
typeof globalThis === "object" &&
|
|
193
262
|
typeof (globalThis as { document?: unknown }).document !== "undefined";
|
|
@@ -206,86 +275,192 @@ export function createClient(options: ClientOptions): To11aiClient {
|
|
|
206
275
|
(!isBunMainThread &&
|
|
207
276
|
typeof workerLikeGlobal.postMessage === "function" &&
|
|
208
277
|
typeof workerLikeGlobal.onmessage !== "undefined"));
|
|
278
|
+
const isBrowser = isDomBrowser || isWorkerBrowser;
|
|
209
279
|
|
|
210
|
-
|
|
280
|
+
// Env vars are read ONLY in a non-browser context, so the published browser
|
|
281
|
+
// bundle never touches `process.env`; explicit options apply everywhere.
|
|
282
|
+
const processEnv =
|
|
283
|
+
!isBrowser &&
|
|
284
|
+
typeof process !== "undefined" &&
|
|
285
|
+
typeof process.env === "object"
|
|
286
|
+
? process.env
|
|
287
|
+
: undefined;
|
|
288
|
+
|
|
289
|
+
// Resolve each value: explicit option → env var → default. `pick` trims and
|
|
290
|
+
// treats empty as absent, so an empty option or env value falls through.
|
|
291
|
+
const pick = (
|
|
292
|
+
opt: string | undefined,
|
|
293
|
+
envKey: string,
|
|
294
|
+
): string | undefined => {
|
|
295
|
+
const fromOpt = opt?.trim();
|
|
296
|
+
if (fromOpt) return fromOpt;
|
|
297
|
+
const fromEnv = processEnv?.[envKey]?.trim();
|
|
298
|
+
return fromEnv ? fromEnv : undefined;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const baseUrl = pick(options.baseUrl, "TO11_API_URL") ?? DEFAULT_API_URL;
|
|
302
|
+
// The gateway root (host, no version path). Normalize away a trailing slash
|
|
303
|
+
// and a trailing `/v1` so both the root form (`https://gw.to11.ai`) and the
|
|
304
|
+
// older `/v1` form resolve identically — the provider helpers add the path
|
|
305
|
+
// each SDK expects.
|
|
306
|
+
const gatewayUrl = (
|
|
307
|
+
pick(options.gatewayUrl, "TO11_GATEWAY_URL") ?? DEFAULT_GATEWAY_URL
|
|
308
|
+
)
|
|
309
|
+
.replace(/\/+$/, "")
|
|
310
|
+
.replace(/\/v1$/, "");
|
|
311
|
+
const apiKey = pick(options.apiKey, "TO11_API_KEY");
|
|
312
|
+
const projectId = pick(options.projectId, "TO11_PROJECT_ID");
|
|
313
|
+
// Default serving env: explicit option → `TO11_ENV` env var — the same
|
|
314
|
+
// `pick(option, "TO11_*")` resolution `apiKey`/`projectId` use (empty option
|
|
315
|
+
// or empty env var trims to absent). An explicit empty option is rejected by
|
|
316
|
+
// the dedicated guard below (mirroring `apiKey`/`projectId`); a non-empty but
|
|
317
|
+
// malformed value fails the `ENV_SLUG_REGEX` check.
|
|
318
|
+
const env = pick(options.env, "TO11_ENV");
|
|
319
|
+
// Provider (BYOK) key — option only, no env fallback (which provider's env
|
|
320
|
+
// var is ambiguous). Empty trims to absent so it falls back to the placeholder.
|
|
321
|
+
const providerApiKey = options.providerApiKey?.trim() || undefined;
|
|
322
|
+
|
|
323
|
+
// A browser must never carry a static API key. `processEnv` is already
|
|
324
|
+
// undefined in the browser, so only the explicit option can reach here.
|
|
325
|
+
if (isBrowser && options.apiKey !== undefined) {
|
|
211
326
|
throw new Error(
|
|
212
|
-
"[to11ai/sdk] Do not use `apiKey` in browser
|
|
327
|
+
"[to11ai/sdk] Do not use `apiKey` in a browser — a to11 API key carries gateway access and must stay server-side (server, CLI, or backend job).",
|
|
213
328
|
);
|
|
214
329
|
}
|
|
215
330
|
|
|
331
|
+
// Explicit empty credentials are a misconfiguration — reject loudly.
|
|
216
332
|
if (options.apiKey !== undefined && options.apiKey.trim() === "") {
|
|
217
333
|
throw new Error("[to11ai/sdk] `apiKey` must not be an empty string.");
|
|
218
334
|
}
|
|
219
|
-
|
|
220
|
-
// R0: validate `projectId` eagerly when supplied (loud throw). An empty /
|
|
221
|
-
// whitespace-only value is a misconfiguration; reject before any request.
|
|
222
335
|
if (options.projectId !== undefined && options.projectId.trim() === "") {
|
|
223
336
|
throw new Error(
|
|
224
337
|
"[to11ai/sdk] `projectId` must not be an empty string — omit it or pass a valid project id.",
|
|
225
338
|
);
|
|
226
339
|
}
|
|
227
|
-
|
|
228
|
-
// R1: validate the init-time `env` against the project-environments
|
|
229
|
-
// registry rule (stricter than gatewayAuthHeaders' empty-only check) so a
|
|
230
|
-
// malformed env fails locally rather than round-tripping to ENV_NOT_FOUND.
|
|
231
|
-
if (options.env !== undefined && !ENV_SLUG_REGEX.test(options.env)) {
|
|
340
|
+
if (options.env !== undefined && options.env.trim() === "") {
|
|
232
341
|
throw new Error(
|
|
233
|
-
|
|
342
|
+
"[to11ai/sdk] `env` must not be an empty string — omit it or pass a valid env slug.",
|
|
234
343
|
);
|
|
235
344
|
}
|
|
236
345
|
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
346
|
+
// Validate the init-time `env` against the project-environments slug rule so
|
|
347
|
+
// a malformed env fails locally rather than round-tripping to ENV_NOT_FOUND.
|
|
348
|
+
if (env !== undefined && !ENV_SLUG_REGEX.test(env)) {
|
|
349
|
+
throw new Error(
|
|
350
|
+
`[to11ai/sdk] \`env\` must match ${ENV_SLUG_REGEX} (lowercase-kebab, 1-63 chars). Received: ${JSON.stringify(env)}`,
|
|
351
|
+
);
|
|
352
|
+
}
|
|
242
353
|
|
|
243
|
-
|
|
354
|
+
// `apiKey` is the only auth source and is required.
|
|
355
|
+
if (apiKey === undefined) {
|
|
244
356
|
throw new Error(
|
|
245
|
-
"[to11ai/sdk]
|
|
357
|
+
"[to11ai/sdk] An `apiKey` (or `TO11_API_KEY`) is required.",
|
|
246
358
|
);
|
|
247
359
|
}
|
|
248
360
|
|
|
249
|
-
const auth =
|
|
250
|
-
options.apiKey !== undefined
|
|
251
|
-
? ({ apiKey: options.apiKey } as const)
|
|
252
|
-
: ({ getAccessToken: getAccessToken as () => Promise<string> } as const);
|
|
361
|
+
const auth = { apiKey } as const;
|
|
253
362
|
|
|
254
|
-
// SDK-behavior store (TO11-2100)
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
const
|
|
258
|
-
const processEnv =
|
|
259
|
-
!isBrowser &&
|
|
260
|
-
typeof process !== "undefined" &&
|
|
261
|
-
typeof process.env === "object"
|
|
262
|
-
? process.env
|
|
263
|
-
: undefined;
|
|
264
|
-
const behaviorStore = new BehaviorStore({
|
|
265
|
-
initOverrides: options.behaviorOverrides,
|
|
266
|
-
env: processEnv,
|
|
267
|
-
});
|
|
363
|
+
// The SDK-behavior store (TO11-2100) still captures any server-delivered
|
|
364
|
+
// flags off responses, but the public `resolveBehavior` accessor is hidden
|
|
365
|
+
// for the 2.0 surface — kept internal so it can be re-exposed step by step.
|
|
366
|
+
const behaviorStore = new BehaviorStore({ env: processEnv });
|
|
268
367
|
|
|
269
368
|
const transport = new Transport({
|
|
270
|
-
baseUrl
|
|
369
|
+
baseUrl,
|
|
271
370
|
auth,
|
|
272
371
|
timeoutMs: options.timeoutMs,
|
|
273
372
|
maxRetries: options.maxRetries,
|
|
274
373
|
behaviorStore,
|
|
275
374
|
});
|
|
276
375
|
|
|
277
|
-
const prompts = new PromptResource(transport,
|
|
278
|
-
projectId
|
|
279
|
-
env
|
|
376
|
+
const prompts = new PromptResource<F>(transport, {
|
|
377
|
+
projectId,
|
|
378
|
+
env,
|
|
379
|
+
format: options.format,
|
|
380
|
+
onUnknownRole: options.onUnknownRole,
|
|
280
381
|
});
|
|
281
382
|
const projectEnvironments = new ProjectEnvironmentResource(transport);
|
|
282
|
-
|
|
383
|
+
|
|
384
|
+
// ── Gateway observability context (session → conversation → turn) ──
|
|
385
|
+
// These build gateway auth headers, so they require a projectId; fail loudly
|
|
386
|
+
// rather than emit a broken header bag.
|
|
387
|
+
const gatewayAuthContext = (): TurnAuthContext => {
|
|
388
|
+
if (projectId === undefined) {
|
|
389
|
+
throw new Error(
|
|
390
|
+
"[to11ai/sdk] session()/turn() need a `projectId` (or `TO11_PROJECT_ID`).",
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return env !== undefined
|
|
394
|
+
? { apiKey, projectId, env }
|
|
395
|
+
: { apiKey, projectId };
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
let defaultSession: Session | undefined;
|
|
399
|
+
const clientDefaultSession = (): Session => {
|
|
400
|
+
if (defaultSession === undefined) {
|
|
401
|
+
defaultSession = new Session(gatewayAuthContext());
|
|
402
|
+
}
|
|
403
|
+
return defaultSession;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// OpenAI's SDK convention puts `/v1` in `baseURL`; the Anthropic SDK appends
|
|
407
|
+
// `/v1/messages` itself, so it takes the gateway root. Both point at the same
|
|
408
|
+
// gateway; only the base differs per provider convention. The result is a
|
|
409
|
+
// spread-ready provider-client options object: managed fields (baseURL/apiKey/
|
|
410
|
+
// defaultHeaders) are computed+merged, and any other override key passes
|
|
411
|
+
// through untouched to the provider SDK.
|
|
412
|
+
const gatewayClientOptions = <
|
|
413
|
+
T extends ProviderClientOverrides = ProviderClientOverrides,
|
|
414
|
+
>(
|
|
415
|
+
defaultBaseURL: string,
|
|
416
|
+
overrides?: T,
|
|
417
|
+
): ProviderClientOptions<T> => {
|
|
418
|
+
if (projectId === undefined) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
"[to11ai/sdk] openaiOptions()/anthropicOptions() need a `projectId` (or `TO11_PROJECT_ID`) — it authenticates the gateway call via `x-to11-project-id`.",
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
// Static tenant auth for the provider client's defaultHeaders; per-call
|
|
424
|
+
// trace + prompt provenance still come from `turn().headers(prompt)`.
|
|
425
|
+
const authHeaders = gatewayAuthHeaders(
|
|
426
|
+
env !== undefined ? { apiKey, projectId, env } : { apiKey, projectId },
|
|
427
|
+
);
|
|
428
|
+
const {
|
|
429
|
+
apiKey: overrideApiKey,
|
|
430
|
+
baseURL: overrideBaseURL,
|
|
431
|
+
defaultHeaders: overrideHeaders,
|
|
432
|
+
...passthrough
|
|
433
|
+
} = overrides ?? ({} as T);
|
|
434
|
+
return {
|
|
435
|
+
...passthrough,
|
|
436
|
+
baseURL: overrideBaseURL ?? defaultBaseURL,
|
|
437
|
+
// Provider (BYOK) key when supplied, else the to11 key as a placeholder
|
|
438
|
+
// (the managed / server-side-credential path).
|
|
439
|
+
apiKey: overrideApiKey ?? providerApiKey ?? apiKey,
|
|
440
|
+
defaultHeaders: { ...authHeaders, ...overrideHeaders },
|
|
441
|
+
} as ProviderClientOptions<T>;
|
|
442
|
+
};
|
|
283
443
|
|
|
284
444
|
return {
|
|
285
445
|
prompts,
|
|
286
446
|
projectEnvironments,
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
447
|
+
apiKey,
|
|
448
|
+
baseUrl,
|
|
449
|
+
gatewayUrl,
|
|
450
|
+
projectId,
|
|
451
|
+
env,
|
|
452
|
+
session: (id) => new Session(gatewayAuthContext(), id),
|
|
453
|
+
conversation: (id) => clientDefaultSession().conversation(id),
|
|
454
|
+
turn: () => clientDefaultSession().turn(),
|
|
455
|
+
openaiOptions: <
|
|
456
|
+
T extends ProviderClientOverrides = ProviderClientOverrides,
|
|
457
|
+
>(
|
|
458
|
+
overrides?: T,
|
|
459
|
+
) => gatewayClientOptions(`${gatewayUrl}/v1`, overrides),
|
|
460
|
+
anthropicOptions: <
|
|
461
|
+
T extends ProviderClientOverrides = ProviderClientOverrides,
|
|
462
|
+
>(
|
|
463
|
+
overrides?: T,
|
|
464
|
+
) => gatewayClientOptions(gatewayUrl, overrides),
|
|
290
465
|
};
|
|
291
466
|
}
|