@builder.io/ai-utils 0.99.0 → 0.100.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/src/projects.js CHANGED
@@ -279,7 +279,10 @@ export const ShapeEffectSchema = z.discriminatedUnion("kind", [
279
279
  }),
280
280
  z.object({
281
281
  kind: z.literal("attach-design-system"),
282
+ /** The permanent join key. */
282
283
  designSystemId: z.string(),
284
+ /** What actually gets written: the field is matched by name downstream. */
285
+ designSystemName: z.string(),
283
286
  }),
284
287
  ]);
285
288
  export const ShapeOptionEffectSchema = z.object({
@@ -302,24 +305,93 @@ export const ShapeAnswerSchema = z.object({
302
305
  questionId: z.string(),
303
306
  optionId: z.string().optional(),
304
307
  designSystemId: z.string().optional(),
308
+ /**
309
+ * Server-resolved from `designSystemId` against the caller's accessible
310
+ * design systems. `settings.designSystems` is matched by name downstream, so
311
+ * the id alone cannot be written there.
312
+ */
313
+ designSystemName: z.string().optional(),
305
314
  skipped: z.boolean(),
306
315
  delegated: z.boolean(),
307
316
  resolvedFrom: z.enum(["user", "llm"]),
308
317
  llmOptionId: z.string().optional(),
309
318
  guessOptionId: z.string().optional(),
310
319
  });
320
+ const ShapeAnswerInputBaseSchema = ShapeAnswerSchema.pick({
321
+ questionId: true,
322
+ optionId: true,
323
+ designSystemId: true,
324
+ skipped: true,
325
+ delegated: true,
326
+ });
327
+ export const ShapeAnswerInputSchema = z.object({
328
+ ...ShapeAnswerInputBaseSchema.shape,
329
+ questionId: ShapeAnswerInputBaseSchema.shape.questionId.trim().min(1),
330
+ optionId: ShapeAnswerInputBaseSchema.shape.optionId
331
+ .unwrap()
332
+ .trim()
333
+ .min(1)
334
+ .optional(),
335
+ designSystemId: ShapeAnswerInputBaseSchema.shape.designSystemId
336
+ .unwrap()
337
+ .trim()
338
+ .min(1)
339
+ .optional(),
340
+ });
341
+ export const GetShapeQuestionnaireOptionsSchema = z.object({
342
+ projectId: z.string().trim().min(1),
343
+ });
344
+ export const SubmitShapeAnswersOptionsSchema = z.object({
345
+ projectId: z.string().trim().min(1),
346
+ questionnaireId: z.string().trim().min(1),
347
+ answers: z.array(ShapeAnswerInputSchema).min(1),
348
+ });
349
+ /**
350
+ * A file the client writes into the container's working tree over the
351
+ * launch-server RPC. The server renders the body; the container performs the
352
+ * write; the agent only reads it.
353
+ */
354
+ export const ShapeDecisionsFileSchema = z.object({
355
+ /** Repository-root relative. */
356
+ path: z.string().min(1),
357
+ contents: z.string().min(1),
358
+ });
359
+ export const SubmitShapeAnswersResponseSchema = z.object({
360
+ prompt: z.string().min(1),
361
+ instructionBlock: z.string().min(1).optional(),
362
+ decisionsFile: ShapeDecisionsFileSchema.optional(),
363
+ });
364
+ export const ShapeQuestionDecisionSchema = z.object({
365
+ questionId: z.string(),
366
+ ask: z.boolean(),
367
+ llmOptionId: z.string().optional(),
368
+ confidence: z.number().optional(),
369
+ guessOptionId: z.string(),
370
+ });
311
371
  export const ShapeSessionSchema = z.object({
312
372
  questionnaireId: z.string(),
313
373
  catalogVersion: z.string().regex(/^\d{4}-\d{2}-\d{2}\.\d+$/),
314
374
  source: z.enum(["static", "agent"]),
315
375
  status: z.enum(["assembling", "pending", "resolved"]),
316
- selection: z.enum(["llm", "fallback"]),
376
+ selection: z.enum(["llm", "fallback"]).optional(),
377
+ decisions: z.array(ShapeQuestionDecisionSchema).optional(),
317
378
  questions: z.array(ShapeQuestionSchema),
318
379
  initialPromptId: z.string(),
319
380
  answers: z.array(ShapeAnswerSchema).optional(),
381
+ issuedAt: z.string().optional(),
320
382
  assembledAt: z.string().optional(),
321
383
  resolvedAt: z.string().optional(),
322
384
  });
385
+ export const InitialPromptSchema = z.object({
386
+ id: z.string(),
387
+ projectId: z.string(),
388
+ branchName: z.string().optional(),
389
+ prompt: z.string(),
390
+ attachmentIds: z.array(z.string()).optional(),
391
+ createdBy: z.string(),
392
+ createdAt: z.number(),
393
+ deliveredAt: z.number().optional(),
394
+ });
323
395
  export const ProjectRolePermissionsSchema = z
324
396
  .object({
325
397
  view: z.boolean().optional(),
@@ -861,8 +933,9 @@ export const getBranchState = (branch) => {
861
933
  * Get the state of a project, checking `state` first and falling back to `deleted` for backwards compatibility.
862
934
  */
863
935
  export const getProjectState = (project) => {
864
- var _a;
865
- return (_a = project.state) !== null && _a !== void 0 ? _a : "active";
936
+ if (project.state)
937
+ return project.state;
938
+ return project.deleted ? "deleted" : "active";
866
939
  };
867
940
  /**
868
941
  * Check if a branch is deleted, supporting both `state` and legacy `deleted` fields.
@@ -1753,6 +1826,17 @@ export const GetHostingAiUsageResponseSchema = z.object({
1753
1826
  */
1754
1827
  coreSupportsGateway: z.boolean(),
1755
1828
  token: HostingAiUsageTokenStatusSchema.nullable(),
1829
+ /**
1830
+ * The `AI_USAGE_MANAGED_PROD_ENV_KEYS` currently holding a value the deployed
1831
+ * site will see, names only. The client cannot derive this: the write endpoint
1832
+ * deliberately leaves the caller's project model stale, so anything projected
1833
+ * locally is wrong the moment two writes or an out-of-band env edit interleave.
1834
+ *
1835
+ * Absent on an API that predates the field, which a client must read as
1836
+ * "unknown" and not as "none": reading it as none pre-selects a mode whose
1837
+ * write deletes the customer's provider key.
1838
+ */
1839
+ managedProdEnvKeys: z.array(z.string()).optional(),
1756
1840
  });
1757
1841
  /** Providers a customer may bring their own key for. */
1758
1842
  export const AiUsageByokProviderSchema = z.enum(["anthropic", "openai"]);
@@ -1770,6 +1854,7 @@ export const SetHostingAiUsageRequestSchema = z.strictObject({
1770
1854
  mode: AiPaymentModeSchema,
1771
1855
  provider: AiUsageByokProviderSchema.optional(),
1772
1856
  apiKey: z.string().min(1).optional(),
1857
+ reuseExistingKey: z.boolean().optional(),
1773
1858
  // https only: this value is written into a published site's prod env as
1774
1859
  // `OPENAI_BASE_URL`, so an `http://` endpoint would send the customer's
1775
1860
  // provider key and every prompt in plaintext from the deployed site.
@@ -1789,6 +1874,14 @@ export const SetHostingAiUsageResponseSchema = z.object({
1789
1874
  * mode), which is exactly the case where no redeploy is needed.
1790
1875
  */
1791
1876
  configUpdatedAt: z.number().optional(),
1877
+ /**
1878
+ * The `AI_USAGE_MANAGED_PROD_ENV_KEYS` present in prod env after the write.
1879
+ * The client cannot derive this: its project model is deliberately not updated
1880
+ * with the rewrite, so projecting it locally goes stale the moment two writes
1881
+ * or an out-of-band env edit interleave. Optional so a client can still talk to
1882
+ * an API that predates it.
1883
+ */
1884
+ managedProdEnvKeys: z.array(z.string()).optional(),
1792
1885
  });
1793
1886
  /** Body for `POST /projects/hosting/ai-usage/revoke`. */
1794
1887
  export const RevokeHostingAiTokenRequestSchema = z.strictObject({
@@ -2120,17 +2213,58 @@ export const ProjectTemplateOverridesSchema = z.object({
2120
2213
  settings: ProjectSettingsExternalSchema.partial().optional(),
2121
2214
  hosting: ProjectHostingExternalSchema.optional(),
2122
2215
  });
2123
- export const CreateProjectTemplateFromProjectOptionsSchema = z.object({
2124
- sourceProjectId: z.string().min(1).meta({
2125
- description: "Project whose settings, repo fields, and hosting config seed the template.",
2126
- }),
2127
- sourceBranchName: z.string().min(1).meta({
2128
- description: "Branch of the source project that projects created from this template are seeded from.",
2216
+ /** Mirrors `ProjectSourceSchema`'s repo/template split for project creation. */
2217
+ export const CreateTemplateSourceSchema = z.discriminatedUnion("kind", [
2218
+ z.object({
2219
+ kind: z.literal("project"),
2220
+ sourceProjectId: z.string().min(1).meta({
2221
+ description: "Project whose settings, repo fields, and hosting config seed the template.",
2222
+ }),
2223
+ sourceBranchName: z.string().min(1).meta({
2224
+ description: "Branch of the source project that projects created from this template are seeded from.",
2225
+ }),
2129
2226
  }),
2130
- overrides: ProjectTemplateOverridesSchema.optional().meta({
2131
- description: "Fields to override on top of the values copied from the source project.",
2227
+ z.object({
2228
+ kind: z.literal("template"),
2229
+ templateId: z.string().min(1).meta({
2230
+ description: "Built-in stub or custom template id whose settings, repo fields, and hosting config seed the new template.",
2231
+ }),
2132
2232
  }),
2233
+ ]);
2234
+ /**
2235
+ * Deprecation-window shim for callers still sending the old flat
2236
+ * `{ sourceProjectId, sourceBranchName }` shape — safe to delete once no
2237
+ * caller sends it anymore.
2238
+ */
2239
+ const LegacyFlatTemplateSourceSchema = z.object({
2240
+ sourceProjectId: z.string().min(1),
2241
+ sourceBranchName: z.string().min(1),
2133
2242
  });
2243
+ export const CreateProjectTemplateFromProjectOptionsSchema = z
2244
+ .union([
2245
+ z.object({
2246
+ source: CreateTemplateSourceSchema.meta({
2247
+ description: "The project or template whose settings, repo fields, and hosting config seed the new template.",
2248
+ }),
2249
+ overrides: ProjectTemplateOverridesSchema.optional().meta({
2250
+ description: "Fields to override on top of the values copied from the source.",
2251
+ }),
2252
+ }),
2253
+ z.object({
2254
+ ...LegacyFlatTemplateSourceSchema.shape,
2255
+ overrides: ProjectTemplateOverridesSchema.optional(),
2256
+ }),
2257
+ ])
2258
+ .transform((parsed) => "source" in parsed
2259
+ ? parsed
2260
+ : {
2261
+ source: {
2262
+ kind: "project",
2263
+ sourceProjectId: parsed.sourceProjectId,
2264
+ sourceBranchName: parsed.sourceBranchName,
2265
+ },
2266
+ overrides: parsed.overrides,
2267
+ });
2134
2268
  /**
2135
2269
  * Deliberately minimal: the stored template carries plaintext secret env values,
2136
2270
  * so nothing beyond the identity of the new template goes back to the caller.
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { AGENT_NATIVE_STARTER_REPO, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, matchesAgentNativeStarter, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectSettingsSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, } from "./projects";
2
+ import { AGENT_NATIVE_STARTER_REPO, getAgentNativeRootPackageJsonWriteError, getManagedDatabasePackageJsonError, getProjectState, GetShapeQuestionnaireOptionsSchema, InitialPromptSchema, isProjectDeleted, matchesAgentNativeStarter, ProjectHostingExternalSchema, ProjectHostingSchema, ProjectSettingsExternalSchema, ProjectSettingsSchema, ProjectTemplateOverridesSchema, ShapeSessionSchema, SubmitShapeAnswersOptionsSchema, } from "./projects";
3
3
  describe("project hosting schemas", () => {
4
4
  it("accepts the canonical published branch route", () => {
5
5
  expect(ProjectHostingSchema.parse({ publishedBranchId: "branch-live" })).toEqual({ publishedBranchId: "branch-live" });
@@ -42,6 +42,16 @@ describe("guided onboarding project settings", () => {
42
42
  },
43
43
  ],
44
44
  initialPromptId: "prompt-1",
45
+ issuedAt: "2026-09-09T12:00:00.000Z",
46
+ decisions: [
47
+ {
48
+ questionId: "authentication",
49
+ ask: false,
50
+ llmOptionId: "required",
51
+ confidence: 0.99,
52
+ guessOptionId: "required",
53
+ },
54
+ ],
45
55
  };
46
56
  it("parses a snapshotted questionnaire session", () => {
47
57
  expect(ShapeSessionSchema.parse(shapeSession)).toEqual(shapeSession);
@@ -55,10 +65,56 @@ describe("guided onboarding project settings", () => {
55
65
  catalogVersion: "v1",
56
66
  })).toThrow();
57
67
  });
68
+ it("parses a project-level initial prompt", () => {
69
+ const initialPrompt = {
70
+ id: "prompt-1",
71
+ projectId: "project-1",
72
+ prompt: "Build an expense tracker",
73
+ createdBy: "user-1",
74
+ createdAt: 1788952800000,
75
+ };
76
+ expect(InitialPromptSchema.parse(initialPrompt)).toEqual(initialPrompt);
77
+ });
58
78
  it("does not allow clients to write a shape session", () => {
59
79
  expect(ProjectSettingsExternalSchema.parse({ shapeSession })).toEqual({});
60
80
  expect(ProjectTemplateOverridesSchema.parse({ settings: { shapeSession } })).toEqual({ settings: {} });
61
81
  });
82
+ it("parses questionnaire endpoint inputs without accepting server fields", () => {
83
+ expect(GetShapeQuestionnaireOptionsSchema.parse({ projectId: "project-1" })).toEqual({ projectId: "project-1" });
84
+ expect(SubmitShapeAnswersOptionsSchema.parse({
85
+ projectId: "project-1",
86
+ questionnaireId: "questionnaire-1",
87
+ answers: [
88
+ {
89
+ questionId: "authentication",
90
+ optionId: "required",
91
+ skipped: false,
92
+ delegated: false,
93
+ resolvedFrom: "llm",
94
+ llmOptionId: "not-required",
95
+ guessOptionId: "not-required",
96
+ },
97
+ ],
98
+ })).toEqual({
99
+ projectId: "project-1",
100
+ questionnaireId: "questionnaire-1",
101
+ answers: [
102
+ {
103
+ questionId: "authentication",
104
+ optionId: "required",
105
+ skipped: false,
106
+ delegated: false,
107
+ },
108
+ ],
109
+ });
110
+ });
111
+ it("requires non-empty questionnaire ids and at least one answer", () => {
112
+ expect(() => SubmitShapeAnswersOptionsSchema.parse({
113
+ projectId: "",
114
+ questionnaireId: "",
115
+ answers: [],
116
+ })).toThrow();
117
+ });
62
118
  });
63
119
  describe("matchesAgentNativeStarter", () => {
64
120
  it("matches when repoName is the starter", () => {
@@ -136,3 +192,22 @@ describe("getAgentNativeRootPackageJsonWriteError", () => {
136
192
  })).toBeUndefined();
137
193
  });
138
194
  });
195
+ describe("getProjectState", () => {
196
+ const project = (fields) => fields;
197
+ it("prefers the state field", () => {
198
+ expect(getProjectState(project({ state: "archived" }))).toBe("archived");
199
+ expect(isProjectDeleted(project({ state: "deleted" }))).toBe(true);
200
+ });
201
+ it("falls back to the legacy deleted field", () => {
202
+ expect(getProjectState(project({ deleted: true }))).toBe("deleted");
203
+ expect(isProjectDeleted(project({ deleted: true }))).toBe(true);
204
+ });
205
+ /** A restored project keeps `deleted: true` but gets an explicit state. */
206
+ it("lets an explicit state win over the legacy field", () => {
207
+ expect(isProjectDeleted(project({ state: "active", deleted: true }))).toBe(false);
208
+ });
209
+ it("defaults to active", () => {
210
+ expect(getProjectState(project({}))).toBe("active");
211
+ expect(isProjectDeleted(project({ deleted: false }))).toBe(false);
212
+ });
213
+ });
@@ -1,5 +1,18 @@
1
1
  import type { GenerateCompletionStep } from "./codegen.js";
2
2
  import { z } from "zod";
3
+ /**
4
+ * Client-safe metadata for a Publish Agent skill: enough for a picker UI
5
+ * (id, name, description), without the instruction `content` sent to the
6
+ * model. `id` is the shared key the server uses to attach that content —
7
+ * see `PUBLISH_AGENT_SKILLS` in `packages/service/publish-agent/config.ts`.
8
+ */
9
+ export declare const PublishAgentSkillInfoSchema: z.ZodObject<{
10
+ id: z.ZodString;
11
+ name: z.ZodString;
12
+ description: z.ZodString;
13
+ }, z.core.$strip>;
14
+ export type PublishAgentSkillInfo = z.infer<typeof PublishAgentSkillInfoSchema>;
15
+ export declare const PUBLISH_AGENT_SKILLS_INFO: readonly PublishAgentSkillInfo[];
3
16
  export declare const PublishAgentSessionCursorSchema: z.ZodObject<{
4
17
  updatedAt: z.ZodNumber;
5
18
  id: z.ZodString;
@@ -1,4 +1,24 @@
1
1
  import { z } from "zod";
2
+ /**
3
+ * Client-safe metadata for a Publish Agent skill: enough for a picker UI
4
+ * (id, name, description), without the instruction `content` sent to the
5
+ * model. `id` is the shared key the server uses to attach that content —
6
+ * see `PUBLISH_AGENT_SKILLS` in `packages/service/publish-agent/config.ts`.
7
+ */
8
+ export const PublishAgentSkillInfoSchema = z
9
+ .object({
10
+ id: z.string(),
11
+ name: z.string(),
12
+ description: z.string(),
13
+ })
14
+ .meta({ title: "PublishAgentSkillInfo" });
15
+ export const PUBLISH_AGENT_SKILLS_INFO = [
16
+ {
17
+ id: "publish-agent-skill-create-page",
18
+ name: "create-page",
19
+ description: "Create a new page in the Builder CMS space. Use when the user asks to create, add, or scaffold a new page.",
20
+ },
21
+ ];
2
22
  export const PublishAgentSessionCursorSchema = z
3
23
  .object({
4
24
  updatedAt: z.number().int(),
package/src/realtime.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
- export declare const BUILDER_REALTIME_MODEL: "gpt-realtime-2.1";
2
+ export declare const BUILDER_REALTIME_MODEL: "gpt-live-1";
3
+ export declare const BUILDER_REALTIME_LEGACY_MODEL: "gpt-realtime-2.1";
4
+ export declare const BUILDER_REALTIME_DELEGATED_MODEL: "gpt-5.6-luna";
3
5
  export declare const BUILDER_REALTIME_MAX_SDP_LENGTH = 256000;
4
6
  export declare const BUILDER_REALTIME_MAX_SESSION_BYTES = 64000;
5
7
  export declare const OpenAIRealtimeFunctionToolSchema: z.ZodObject<{
@@ -137,9 +139,122 @@ export declare const OpenAIRealtimeSessionConfigSchema: z.ZodObject<{
137
139
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
138
140
  }, z.core.$strip>;
139
141
  export type OpenAIRealtimeSessionConfig = z.infer<typeof OpenAIRealtimeSessionConfigSchema>;
142
+ /** The subset of GPT-Live session configuration accepted by Builder Connect. */
143
+ export declare const OpenAILiveSessionConfigSchema: z.ZodObject<{
144
+ model: z.ZodLiteral<"gpt-live-1">;
145
+ instructions: z.ZodOptional<z.ZodString>;
146
+ audio: z.ZodOptional<z.ZodObject<{
147
+ output: z.ZodOptional<z.ZodObject<{
148
+ voice: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
149
+ id: z.ZodString;
150
+ }, z.core.$strip>]>>;
151
+ }, z.core.$strip>>;
152
+ }, z.core.$strip>>;
153
+ delegation: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
154
+ type: z.ZodLiteral<"responses">;
155
+ responses: z.ZodObject<{
156
+ model: z.ZodLiteral<"gpt-5.6-luna">;
157
+ instructions: z.ZodOptional<z.ZodString>;
158
+ tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
159
+ type: z.ZodLiteral<"function">;
160
+ name: z.ZodString;
161
+ description: z.ZodOptional<z.ZodString>;
162
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
163
+ strict: z.ZodOptional<z.ZodBoolean>;
164
+ }, z.core.$strip>, z.ZodObject<{
165
+ type: z.ZodLiteral<"web_search">;
166
+ }, z.core.$strip>]>>>;
167
+ tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
168
+ auto: "auto";
169
+ none: "none";
170
+ required: "required";
171
+ }>, z.ZodObject<{
172
+ type: z.ZodLiteral<"function">;
173
+ name: z.ZodString;
174
+ }, z.core.$strip>]>>;
175
+ parallel_tool_calls: z.ZodOptional<z.ZodBoolean>;
176
+ max_output_tokens: z.ZodOptional<z.ZodNumber>;
177
+ service_tier: z.ZodOptional<z.ZodEnum<{
178
+ auto: "auto";
179
+ default: "default";
180
+ priority: "priority";
181
+ }>>;
182
+ reasoning: z.ZodOptional<z.ZodObject<{
183
+ effort: z.ZodEnum<{
184
+ high: "high";
185
+ low: "low";
186
+ max: "max";
187
+ medium: "medium";
188
+ minimal: "minimal";
189
+ none: "none";
190
+ xhigh: "xhigh";
191
+ }>;
192
+ }, z.core.$strip>>;
193
+ }, z.core.$strip>;
194
+ }, z.core.$strip>, z.ZodObject<{
195
+ type: z.ZodLiteral<"client">;
196
+ }, z.core.$strip>]>>>;
197
+ store: z.ZodOptional<z.ZodBoolean>;
198
+ }, z.core.$strip>;
199
+ export type OpenAILiveSessionConfig = z.infer<typeof OpenAILiveSessionConfigSchema>;
140
200
  export declare const BuilderRealtimeSessionRequestSchema: z.ZodObject<{
141
201
  sdp: z.ZodString;
142
- session: z.ZodObject<{
202
+ session: z.ZodUnion<readonly [z.ZodObject<{
203
+ model: z.ZodLiteral<"gpt-live-1">;
204
+ instructions: z.ZodOptional<z.ZodString>;
205
+ audio: z.ZodOptional<z.ZodObject<{
206
+ output: z.ZodOptional<z.ZodObject<{
207
+ voice: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
208
+ id: z.ZodString;
209
+ }, z.core.$strip>]>>;
210
+ }, z.core.$strip>>;
211
+ }, z.core.$strip>>;
212
+ delegation: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
213
+ type: z.ZodLiteral<"responses">;
214
+ responses: z.ZodObject<{
215
+ model: z.ZodLiteral<"gpt-5.6-luna">;
216
+ instructions: z.ZodOptional<z.ZodString>;
217
+ tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
218
+ type: z.ZodLiteral<"function">;
219
+ name: z.ZodString;
220
+ description: z.ZodOptional<z.ZodString>;
221
+ parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
222
+ strict: z.ZodOptional<z.ZodBoolean>;
223
+ }, z.core.$strip>, z.ZodObject<{
224
+ type: z.ZodLiteral<"web_search">;
225
+ }, z.core.$strip>]>>>;
226
+ tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
227
+ auto: "auto";
228
+ none: "none";
229
+ required: "required";
230
+ }>, z.ZodObject<{
231
+ type: z.ZodLiteral<"function">;
232
+ name: z.ZodString;
233
+ }, z.core.$strip>]>>;
234
+ parallel_tool_calls: z.ZodOptional<z.ZodBoolean>;
235
+ max_output_tokens: z.ZodOptional<z.ZodNumber>;
236
+ service_tier: z.ZodOptional<z.ZodEnum<{
237
+ auto: "auto";
238
+ default: "default";
239
+ priority: "priority";
240
+ }>>;
241
+ reasoning: z.ZodOptional<z.ZodObject<{
242
+ effort: z.ZodEnum<{
243
+ high: "high";
244
+ low: "low";
245
+ max: "max";
246
+ medium: "medium";
247
+ minimal: "minimal";
248
+ none: "none";
249
+ xhigh: "xhigh";
250
+ }>;
251
+ }, z.core.$strip>>;
252
+ }, z.core.$strip>;
253
+ }, z.core.$strip>, z.ZodObject<{
254
+ type: z.ZodLiteral<"client">;
255
+ }, z.core.$strip>]>>>;
256
+ store: z.ZodOptional<z.ZodBoolean>;
257
+ }, z.core.$strip>, z.ZodObject<{
143
258
  type: z.ZodLiteral<"realtime">;
144
259
  model: z.ZodLiteral<"gpt-realtime-2.1">;
145
260
  output_modalities: z.ZodTuple<[z.ZodLiteral<"audio">], null>;
@@ -227,6 +342,6 @@ export declare const BuilderRealtimeSessionRequestSchema: z.ZodObject<{
227
342
  disabled: "disabled";
228
343
  }>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
229
344
  include: z.ZodOptional<z.ZodArray<z.ZodString>>;
230
- }, z.core.$strip>;
345
+ }, z.core.$strip>]>;
231
346
  }, z.core.$strip>;
232
347
  export type BuilderRealtimeSessionRequest = z.infer<typeof BuilderRealtimeSessionRequestSchema>;
package/src/realtime.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
- export const BUILDER_REALTIME_MODEL = "gpt-realtime-2.1";
2
+ export const BUILDER_REALTIME_MODEL = "gpt-live-1";
3
+ export const BUILDER_REALTIME_LEGACY_MODEL = "gpt-realtime-2.1";
4
+ export const BUILDER_REALTIME_DELEGATED_MODEL = "gpt-5.6-luna";
3
5
  export const BUILDER_REALTIME_MAX_SDP_LENGTH = 256000;
4
6
  export const BUILDER_REALTIME_MAX_SESSION_BYTES = 64000;
5
7
  const utf8ByteLength = (value) => new TextEncoder().encode(value).length;
@@ -109,7 +111,7 @@ const OpenAIRealtimeToolChoiceSchema = z.union([
109
111
  export const OpenAIRealtimeSessionConfigSchema = z
110
112
  .object({
111
113
  type: z.literal("realtime"),
112
- model: z.literal(BUILDER_REALTIME_MODEL),
114
+ model: z.literal(BUILDER_REALTIME_LEGACY_MODEL),
113
115
  output_modalities: z.tuple([z.literal("audio")]),
114
116
  instructions: z.string().max(32000).optional(),
115
117
  audio: z
@@ -148,11 +150,76 @@ export const OpenAIRealtimeSessionConfigSchema = z
148
150
  })
149
151
  .refine((session) => utf8ByteLength(JSON.stringify(session)) <=
150
152
  BUILDER_REALTIME_MAX_SESSION_BYTES, { message: "Realtime session configuration is too large" });
153
+ const OpenAILiveToolSchema = z.union([
154
+ OpenAIRealtimeFunctionToolSchema,
155
+ z.object({ type: z.literal("web_search") }),
156
+ ]);
157
+ const OpenAILiveResponsesDelegationSchema = z.object({
158
+ model: z.literal(BUILDER_REALTIME_DELEGATED_MODEL),
159
+ instructions: z.string().max(32000).optional(),
160
+ tools: z.array(OpenAILiveToolSchema).max(32).optional(),
161
+ tool_choice: z
162
+ .union([
163
+ z.enum(["auto", "none", "required"]),
164
+ z.object({
165
+ type: z.literal("function"),
166
+ name: z.string().min(1).max(64),
167
+ }),
168
+ ])
169
+ .optional(),
170
+ parallel_tool_calls: z.boolean().optional(),
171
+ max_output_tokens: z.number().int().min(16).max(4096).optional(),
172
+ service_tier: z.enum(["auto", "default", "priority"]).optional(),
173
+ reasoning: z
174
+ .object({
175
+ effort: z.enum([
176
+ "none",
177
+ "minimal",
178
+ "low",
179
+ "medium",
180
+ "high",
181
+ "xhigh",
182
+ "max",
183
+ ]),
184
+ })
185
+ .optional(),
186
+ });
187
+ const OpenAILiveDelegationSchema = z.union([
188
+ z.object({
189
+ type: z.literal("responses"),
190
+ responses: OpenAILiveResponsesDelegationSchema,
191
+ }),
192
+ z.object({ type: z.literal("client") }),
193
+ ]);
194
+ const OpenAILiveOutputAudioSchema = z.object({
195
+ voice: z
196
+ .union([
197
+ z.string().min(1).max(128),
198
+ z.object({ id: z.string().min(1).max(256) }),
199
+ ])
200
+ .optional(),
201
+ });
202
+ /** The subset of GPT-Live session configuration accepted by Builder Connect. */
203
+ export const OpenAILiveSessionConfigSchema = z
204
+ .object({
205
+ model: z.literal(BUILDER_REALTIME_MODEL),
206
+ instructions: z.string().max(32000).optional(),
207
+ audio: z
208
+ .object({ output: OpenAILiveOutputAudioSchema.optional() })
209
+ .optional(),
210
+ delegation: OpenAILiveDelegationSchema.nullable().optional(),
211
+ store: z.boolean().optional(),
212
+ })
213
+ .refine((session) => utf8ByteLength(JSON.stringify(session)) <=
214
+ BUILDER_REALTIME_MAX_SESSION_BYTES, { message: "Live session configuration is too large" });
151
215
  export const BuilderRealtimeSessionRequestSchema = z.object({
152
216
  sdp: z
153
217
  .string()
154
218
  .min(1)
155
219
  .max(BUILDER_REALTIME_MAX_SDP_LENGTH)
156
220
  .refine((sdp) => sdp.trim().length > 0, { message: "SDP cannot be blank" }),
157
- session: OpenAIRealtimeSessionConfigSchema,
221
+ session: z.union([
222
+ OpenAILiveSessionConfigSchema,
223
+ OpenAIRealtimeSessionConfigSchema,
224
+ ]),
158
225
  });