···11import { describe, expect, it } from 'vitest';
2233import { SymbolRegistry } from '../symbols/registry';
44+import { isSymbol } from '../symbols/symbol';
4556describe('SymbolRegistry', () => {
67 it('covers the full public interface', () => {
···259260 // The new stub isn't indexed, so query returns nothing yet
260261 const newQuery = registry.query({ something: 'else' });
261262 expect(newQuery).toEqual([]);
263263+ });
264264+265265+ it('isSymbol covers various inputs', () => {
266266+ const registry = new SymbolRegistry();
267267+268268+ // real registered symbol
269269+ const sym = registry.register({ meta: { a: 1 }, name: 'A' });
270270+ expect(isSymbol(sym)).toBe(true);
271271+272272+ // stub reference (unregistered)
273273+ const stub = registry.reference({ b: 2 });
274274+ expect(isSymbol(stub)).toBe(true);
275275+276276+ // primitives
277277+ expect(isSymbol(null)).toBe(false);
278278+ expect(isSymbol(undefined)).toBe(false);
279279+ expect(isSymbol(123)).toBe(false);
280280+ expect(isSymbol('foo')).toBe(false);
281281+ expect(isSymbol(true)).toBe(false);
282282+283283+ // arrays and plain objects
284284+ expect(isSymbol([])).toBe(false);
285285+ expect(isSymbol({})).toBe(false);
286286+287287+ // object with different tag
288288+ expect(isSymbol({ '~tag': 'not-a-symbol' })).toBe(false);
289289+290290+ // object masquerading as a symbol (matches tag)
291291+ expect(isSymbol({ '~tag': 'heyapi.symbol' })).toBe(true);
292292+293293+ // Date, Map, Set should be false
294294+ expect(isSymbol(new Date())).toBe(false);
295295+ expect(isSymbol(new Map())).toBe(false);
296296+ expect(isSymbol(new Set())).toBe(false);
297297+298298+ // Typed arrays and ArrayBuffer should be false
299299+ expect(isSymbol(new Uint8Array())).toBe(false);
300300+ expect(isSymbol(new ArrayBuffer(8))).toBe(false);
301301+302302+ // Functions without tag should be false
303303+ const fn = () => {};
304304+ expect(isSymbol(fn)).toBe(false);
305305+306306+ // Class instance without tag should be false
307307+ class Foo {}
308308+ const foo = new Foo();
309309+ expect(isSymbol(foo)).toBe(false);
310310+311311+ // Proxy with tag should be true if own property is present
312312+ const target = {} as Record<string, unknown>;
313313+ const proxied = new Proxy(target, {
314314+ get(_, prop) {
315315+ if (prop === '~tag') return 'heyapi.symbol';
316316+ return undefined;
317317+ },
318318+ getOwnPropertyDescriptor(_, prop) {
319319+ if (prop === '~tag')
320320+ return {
321321+ configurable: true,
322322+ enumerable: true,
323323+ value: 'heyapi.symbol',
324324+ writable: false,
325325+ };
326326+ return undefined;
327327+ },
328328+ has(_, prop) {
329329+ return prop === '~tag';
330330+ },
331331+ });
332332+ // Define as own property to satisfy hasOwn
333333+ Object.defineProperty(target, '~tag', {
334334+ configurable: true,
335335+ value: 'heyapi.symbol',
336336+ });
337337+ expect(isSymbol(proxied)).toBe(true);
338338+339339+ // Inherited tag should be false (not own property)
340340+ const proto = { '~tag': 'heyapi.symbol' };
341341+ const objWithProto = Object.create(proto);
342342+ expect(isSymbol(objWithProto)).toBe(false);
343343+344344+ // Primitive edge cases
345345+ expect(isSymbol(Symbol('x'))).toBe(false);
346346+ expect(isSymbol(0n)).toBe(false);
262347 });
263348});
+76
packages/codegen-core/src/bindings/plan.d.ts
···11+import type { SymbolImportKind } from '../symbols/types';
22+33+export interface PlannedImport {
44+ /** ID of the file where the symbol lives */
55+ from: number;
66+ /** The final exported name of the symbol in its source file */
77+ importedName: string;
88+ /** Whether this import is type-only. */
99+ isTypeOnly: boolean;
1010+ /** Import flavor. */
1111+ kind: SymbolImportKind;
1212+ /**
1313+ * The name this symbol will have locally in this file.
1414+ * This is where aliasing is applied:
1515+ *
1616+ * import { Foo as Foo$2 } from "./x"
1717+ *
1818+ * localName === "Foo$2"
1919+ */
2020+ localName: string;
2121+ /** ID of the symbol being imported */
2222+ symbolId: number;
2323+}
2424+2525+export interface PlannedExport {
2626+ /**
2727+ * Whether the export was explicitly requested by the plugin/DSL
2828+ * (e.g. symbol.exported = true) vs implicitly required (e.g. re-export).
2929+ */
3030+ explicit: boolean;
3131+ /**
3232+ * The name this symbol will be exported under from this file.
3333+ *
3434+ * This may differ from the symbol's finalName if aliasing is needed:
3535+ *
3636+ * export { Foo as Foo2 }
3737+ *
3838+ * exportedName === "Foo2"
3939+ */
4040+ exportedName: string;
4141+ /** Whether this export is type-only. */
4242+ isTypeOnly: boolean;
4343+ /** Export flavor. */
4444+ kind: SymbolImportKind;
4545+ /** ID of the symbol being exported */
4646+ symbolId: number;
4747+}
4848+4949+export interface PlannedReexport {
5050+ /**
5151+ * Name under which the symbol is exported in this file.
5252+ *
5353+ * export { Foo as Bar } from "./models"
5454+ *
5555+ * exportedName === "Bar"
5656+ */
5757+ exportedName: string;
5858+ /** ID of the source file containing the symbol */
5959+ from: number;
6060+ /**
6161+ * The name the symbol has in the source file’s exports.
6262+ *
6363+ * export { Foo as Bar } from "./models"
6464+ *
6565+ * importedName === "Foo"
6666+ *
6767+ * This handles aliasing in the source file's export list.
6868+ */
6969+ importedName: string;
7070+ /** Whether this re-export is type-only. */
7171+ isTypeOnly: boolean;
7272+ /** Export flavor. */
7373+ kind: SymbolImportKind;
7474+ /** ID of the symbol being re-exported */
7575+ symbolId: number;
7676+}
···11+export interface Rules {
22+ /** Whether two exported names may collide. */
33+ allowExportNameShadowing: boolean;
44+ /** Whether a local symbol can shadow another local name without error. */
55+ allowLocalNameShadowing: boolean;
66+ /** Whether the language requires file-scoped name uniqueness. */
77+ fileScopedNamesMustBeUnique: boolean;
88+ /** Whether `import { X } from "mod"` introduces a local binding `X`. */
99+ importCreatesLocalBinding: boolean;
1010+ /** Whether `export { X } from "mod"` introduces a local binding `X`. */
1111+ reexportCreatesLocalBinding: boolean;
1212+ /** Whether the language distinguishes type-only imports. */
1313+ supportsTypeImports: boolean;
1414+}
+24-33
packages/codegen-core/src/files/types.d.ts
···11import type { IBiMap } from '../bimap/types';
22+import type {
33+ PlannedExport,
44+ PlannedImport,
55+ PlannedReexport,
66+} from '../bindings/plan';
77+import type { Symbol } from '../symbols/symbol';
88+import type { SymbolKind } from '../symbols/types';
99+import type { Rules } from './rules';
210311/**
412 * Selector array used to reference files.
···1018export type IFileIdentifier = number | IFileSelector;
11191220export type IFileIn = {
1313- /**
1414- * File extension, if any.
1515- */
2121+ /** File extension, if any. */
1622 extension?: string;
1723 /**
1824 * Indicates whether the file is external, meaning it is not generated
···2228 * @example true
2329 */
2430 external?: boolean;
2525- /**
2626- * Unique file ID. If one is not provided, it will be auto-generated.
2727- */
3131+ /** Unique file ID. If one is not provided, it will be auto-generated. */
2832 readonly id?: number;
2933 /**
3034 * The desired name for the file within the project. If there are multiple files
···4852};
49535054export type IFileOut = IFileIn & {
5151- /**
5252- * Unique file ID.
5353- */
5555+ /** Named exports originating from this file */
5656+ readonly exports: Array<PlannedExport>;
5757+ /** Unique file ID. */
5458 readonly id: number;
5555- /**
5656- * Names declared in local (non‑top‑level) scopes within this file.
5757- */
5858- readonly localNames: Set<string>;
5959- /**
6060- * Map holding resolved names for symbols in this file.
6161- */
5959+ /** Fully resolved imports this file needs */
6060+ readonly imports: Array<PlannedImport>;
6161+ /** Re-exports (“export { X } from …”) */
6262+ readonly reexports: Array<PlannedReexport>;
6363+ /** Top-level names in this file that cannot be reused (imports, exports, declarations, symbol names). */
6464+ readonly reservedNames: Map<string, Set<SymbolKind>>;
6565+ /** Map holding resolved names for symbols in this file. */
6266 readonly resolvedNames: IBiMap<number, string>;
6363- /**
6464- * Symbols in this file, categorized by their role.
6565- */
6666- readonly symbols: {
6767- /**
6868- * Symbols declared in the body of this file.
6969- */
7070- body: Array<number>;
7171- /**
7272- * Symbols re-exported from other files.
7373- */
7474- exports: Array<number>;
7575- /**
7676- * Symbols imported from other files.
7777- */
7878- imports: Array<number>;
7979- };
6767+ /** Rules that control naming, imports, reexports, and scope behavior for this file. */
6868+ rules?: Rules;
6969+ /** Symbols defined inside this file */
7070+ readonly symbols: Array<Symbol>;
8071};
81728273export interface IFileRegistry {
+8-2
packages/codegen-core/src/index.ts
···11export type { IBiMap as BiMap } from './bimap/types';
22+export type {
33+ PlannedExport,
44+ PlannedImport,
55+ PlannedReexport,
66+} from './bindings/plan';
27export type { IBinding as Binding } from './bindings/types';
38export { createBinding, mergeBindings } from './bindings/utils';
49export { debug } from './debug';
···1116 IFileIdentifier as FileIdentifier,
1217 IFileIn as FileIn,
1318} from './files/types';
1919+export type { INode as Node } from './nodes/node';
1420export type { IOutput as Output } from './output';
1521export { Project } from './project/project';
1622export type { IProject } from './project/types';
1723export type { IRenderer as Renderer } from './renderer/types';
1824export { renderIds } from './renderer/utils';
1919-export { Symbol } from './symbols/symbol';
2525+export { AnalysisContext, Analyzer } from './symbols/analyzer';
2626+export { isSymbol, Symbol, symbolBrand } from './symbols/symbol';
2027export type {
2128 ISymbolIdentifier as SymbolIdentifier,
2229 ISymbolIn as SymbolIn,
2330} from './symbols/types';
2424-export type { ISyntaxNode as SyntaxNode } from './syntax-node';
+13
packages/codegen-core/src/nodes/node.d.ts
···11+import type { IAnalysisContext } from '../symbols/analyzer';
22+import type { Symbol } from '../symbols/symbol';
33+44+export interface INode {
55+ /** Perform semantic analysis. */
66+ analyze(ctx: IAnalysisContext): void;
77+ /** Parent node in the constructed syntax tree. */
88+ parent?: INode;
99+ /** The symbol associated with this node, if it defines a top‑level symbol. */
1010+ symbol?: Symbol;
1111+ /** Brand used for renderer dispatch. */
1212+ readonly '~brand': symbol;
1313+}
+26
packages/codegen-core/src/nodes/registry.ts
···11+import type { INode } from './node';
22+import type { INodeRegistry } from './types';
33+44+export class NodeRegistry implements INodeRegistry {
55+ private brands: Map<symbol, Array<INode>> = new Map();
66+ private list: Array<INode> = [];
77+88+ add(node: INode): void {
99+ this.list.push(node);
1010+1111+ let group = this.brands.get(node['~brand']);
1212+ if (!group) {
1313+ group = [];
1414+ this.brands.set(node['~brand'], group);
1515+ }
1616+ group.push(node);
1717+ }
1818+1919+ all(): ReadonlyArray<INode> {
2020+ return this.list;
2121+ }
2222+2323+ byBrand(brand: symbol): ReadonlyArray<INode> {
2424+ return this.brands.get(brand) ?? [];
2525+ }
2626+}
+16
packages/codegen-core/src/nodes/types.d.ts
···11+import type { INode } from './node';
22+33+export interface INodeRegistry {
44+ /**
55+ * Register a syntax node.
66+ */
77+ add(node: INode): void;
88+ /**
99+ * All nodes in insertion order.
1010+ */
1111+ all(): ReadonlyArray<INode>;
1212+ /**
1313+ * Nodes by backend brand, so planner doesn't need to filter repeatedly.
1414+ */
1515+ byBrand(brand: symbol): ReadonlyArray<INode>;
1616+}
+77
packages/codegen-core/src/project/namespace.ts
···11+import type { SymbolKind } from '../symbols/types';
22+33+/**
44+ * Returns true if two declarations of given kinds
55+ * are allowed to share the same identifier in TypeScript.
66+ */
77+export function canShareName(a: SymbolKind, b: SymbolKind): boolean {
88+ // same-kind always valid for interfaces (merging)
99+ if (a === 'interface' && b === 'interface') return true;
1010+1111+ // type vs interface merges
1212+ if (
1313+ (a === 'interface' && b === 'type') ||
1414+ (a === 'type' && b === 'interface')
1515+ ) {
1616+ return false; // TypeScript does NOT merge type-alias with interface.
1717+ }
1818+1919+ // type vs type = conflict
2020+ if (a === 'type' && b === 'type') return false;
2121+2222+ // interface vs class = allowed (declare-merge)
2323+ if (
2424+ (a === 'interface' && b === 'class') ||
2525+ (a === 'class' && b === 'interface')
2626+ ) {
2727+ return true;
2828+ }
2929+3030+ // enum vs namespace = allowed (merges into value+type)
3131+ if (
3232+ (a === 'enum' && b === 'namespace') ||
3333+ (a === 'namespace' && b === 'enum')
3434+ ) {
3535+ return true;
3636+ }
3737+3838+ // class vs namespace = allowed
3939+ if (
4040+ (a === 'class' && b === 'namespace') ||
4141+ (a === 'namespace' && b === 'class')
4242+ ) {
4343+ return true;
4444+ }
4545+4646+ // namespace vs namespace = allowed (merging)
4747+ if (a === 'namespace' && b === 'namespace') return true;
4848+4949+ // enum vs enum = conflict IF values conflict (TypeScript flags duplicates)
5050+ if (a === 'enum' && b === 'enum') return false;
5151+5252+ // function and namespace merge (namespace can augment function)
5353+ if (
5454+ (a === 'function' && b === 'namespace') ||
5555+ (a === 'namespace' && b === 'function')
5656+ ) {
5757+ return true;
5858+ }
5959+6060+ // these collide with each other in the value namespace
6161+ const valueKinds = new Set<SymbolKind>(['class', 'enum', 'function', 'var']);
6262+6363+ const aInValue = valueKinds.has(a);
6464+ const bInValue = valueKinds.has(b);
6565+6666+ if (aInValue && bInValue) return false;
6767+6868+ // type-only declarations do not collide with value-only declarations
6969+ const typeKinds = new Set<SymbolKind>(['interface', 'type']);
7070+ const aInType = typeKinds.has(a);
7171+ const bInType = typeKinds.has(b);
7272+7373+ // if one is type-only and the other is value-only, they do NOT collide
7474+ if (aInType !== bInType) return true;
7575+7676+ return true;
7777+}
+191-72
packages/codegen-core/src/project/project.ts
···2233import type { IProjectRenderMeta } from '../extensions';
44import { FileRegistry } from '../files/registry';
55-import type { IFileOut, IFileSelector } from '../files/types';
55+import type { IFileSelector } from '../files/types';
66+import { NodeRegistry } from '../nodes/registry';
67import type { IOutput } from '../output';
78import type { IRenderer } from '../renderer/types';
99+import { Analyzer } from '../symbols/analyzer';
810import { SymbolRegistry } from '../symbols/registry';
911import type { Symbol } from '../symbols/symbol';
1212+import type { SymbolKind } from '../symbols/types';
1313+import { canShareName } from './namespace';
1014import type { IProject } from './types';
11151216const externalSourceSymbol = '@';
13171418export class Project implements IProject {
1515- private symbolIdToFileIds: Map<number, Set<number>> = new Map();
1616-1919+ readonly analyzer = new Analyzer();
1720 readonly defaultFileName: string;
1821 readonly files = new FileRegistry();
1922 readonly fileName?: (name: string) => string;
2323+ readonly nodes = new NodeRegistry();
2024 readonly renderers: Record<string, IRenderer> = {};
2125 readonly root: string;
2226 readonly symbols = new SymbolRegistry();
···3337 this.root = root;
3438 }
35393636- private getRenderer(file: IFileOut): IRenderer | undefined {
3737- return file.extension ? this.renderers[file.extension] : undefined;
4040+ render(meta?: IProjectRenderMeta): ReadonlyArray<IOutput> {
4141+ this.prepareFiles();
4242+ return this.renderFiles(meta);
3843 }
39444045 private prepareFiles(): void {
4141- // TODO: infer extension from symbols
4242- const extension = '.ts';
4343- for (const symbol of this.symbols.registered()) {
4646+ this.assignFiles();
4747+ this.registerFiles();
4848+ this.resolveFinalSymbolNames();
4949+ this.planImports();
5050+ this.planExports();
5151+ }
5252+5353+ /**
5454+ * Creates a file for every symbol so all files exist before planning.
5555+ */
5656+ private assignFiles(): void {
5757+ this.analyzer.analyze(this.nodes.all(), (ctx) => {
5858+ const symbol = ctx.root;
4459 const selector = this.symbolToFileSelector(symbol);
4560 const file = this.files.reference(selector);
4646- file.symbols.body.push(symbol.id);
4747- // update symbol->files map
4848- const symbolIdToFileIds =
4949- this.symbolIdToFileIds.get(symbol.id) ?? new Set();
5050- symbolIdToFileIds.add(file.id);
5151- this.symbolIdToFileIds.set(symbol.id, symbolIdToFileIds);
5252- // update re-exports
5353- if (symbol.exportFrom) {
5454- for (const exportFrom of symbol.exportFrom) {
5555- const exportSelector = [exportFrom];
5656- const exportFile = this.files.reference(exportSelector);
5757- if (exportFile.id !== file.id) {
5858- exportFile.symbols.exports.push(symbol.id);
5959- }
6161+ file.symbols.push(symbol);
6262+ symbol.setFile(file);
6363+ for (const exportFrom of symbol.exportFrom) {
6464+ const selector = [exportFrom];
6565+ this.files.reference(selector);
6666+ }
6767+ for (const dependency of ctx.symbols) {
6868+ if (dependency.external) {
6969+ const selector = this.symbolToFileSelector(dependency);
7070+ const file = this.files.reference(selector);
7171+ dependency.setFile(file);
6072 }
6173 }
7474+ });
7575+ }
7676+7777+ private planExports(): void {
7878+ const seenByFile = new Map<
7979+ number,
8080+ Map<string, { dep: Symbol; kinds: Set<SymbolKind> }>
8181+ >();
8282+ const sourceFile = new Map<number, number>();
8383+8484+ this.analyzer.analyze(this.nodes.all(), (ctx) => {
8585+ const symbol = ctx.root;
8686+ const file = ctx.root.file;
8787+ if (!file) return;
8888+8989+ for (const exportFrom of symbol.exportFrom) {
9090+ const target = this.files.reference([exportFrom]);
9191+ if (target.id === file.id) continue;
9292+9393+ let map = seenByFile.get(target.id);
9494+ if (!map) {
9595+ map = new Map();
9696+ seenByFile.set(target.id, map);
9797+ }
9898+9999+ const dep = this.symbols.register({
100100+ exported: true,
101101+ external: symbol.external,
102102+ importKind: symbol.importKind,
103103+ kind: symbol.kind,
104104+ meta: symbol.meta,
105105+ name: symbol.finalName,
106106+ });
107107+ dep.setFile(target);
108108+ sourceFile.set(dep.id, file.id);
109109+ this.resolveSymbolFinalName(dep);
110110+111111+ let entry = map.get(dep.finalName);
112112+ if (!entry) {
113113+ entry = { dep, kinds: new Set() };
114114+ map.set(dep.finalName, entry);
115115+ }
116116+ entry.kinds.add(dep.kind);
117117+ }
118118+ });
119119+120120+ for (const [fileId, map] of seenByFile) {
121121+ const target = this.files.get(fileId)!;
122122+ for (const [, entry] of map) {
123123+ const symbol = entry.dep;
124124+ target.reexports.push({
125125+ exportedName: symbol.finalName,
126126+ from: sourceFile.get(symbol.id)!,
127127+ importedName: symbol.name,
128128+ isTypeOnly: [...entry.kinds].every(
129129+ (kind) => kind === 'type' || kind === 'interface',
130130+ ),
131131+ kind: symbol.importKind,
132132+ symbolId: symbol.id,
133133+ });
134134+ }
62135 }
136136+ }
137137+138138+ private planImports(): void {
139139+ const seenByFile = new Map<number, Set<string>>();
140140+141141+ this.analyzer.analyze(this.nodes.all(), (ctx) => {
142142+ const file = ctx.root.file;
143143+ if (!file) return;
144144+145145+ let seen = seenByFile.get(file.id);
146146+ if (!seen) {
147147+ seen = new Set();
148148+ seenByFile.set(file.id, seen);
149149+ }
150150+151151+ for (const dependency of ctx.symbols) {
152152+ if (!dependency.file || dependency.file.id === file.id) continue;
153153+154154+ this.resolveSymbolFinalName(dependency);
155155+ const from = dependency.file.id;
156156+ const importedName = dependency.name;
157157+ const localName = dependency.finalName;
158158+ const isTypeOnly = false; // keep as-is for now
159159+ const kind = dependency.importKind;
160160+161161+ const key = `${from}|${importedName}|${localName}|${kind}|${isTypeOnly}`;
162162+ if (seen.has(key)) continue;
163163+ seen.add(key);
164164+165165+ file.imports.push({
166166+ from,
167167+ importedName,
168168+ isTypeOnly,
169169+ kind,
170170+ localName,
171171+ symbolId: dependency.id,
172172+ });
173173+ }
174174+ });
175175+ }
176176+177177+ /**
178178+ * Registers all files.
179179+ */
180180+ private registerFiles(): void {
63181 for (const file of this.files.referenced()) {
6464- if (!file.selector) continue;
6565- if (file.selector[0] === externalSourceSymbol) {
6666- const filePath = file.selector[1];
6767- if (!filePath) {
6868- this.files.register({
6969- external: true,
7070- selector: file.selector,
7171- });
7272- continue;
7373- }
7474- const extension = path.extname(filePath);
7575- if (!extension) {
7676- this.files.register({
7777- external: true,
7878- path: filePath,
7979- selector: file.selector,
8080- });
8181- continue;
8282- }
182182+ const selector = file.selector;
183183+ if (!selector) continue;
184184+ if (selector[0] === externalSourceSymbol) {
185185+ this.files.register({
186186+ external: true,
187187+ path: selector[1],
188188+ selector,
189189+ });
190190+ } else {
191191+ const dirs = file.selector.slice(0, -1);
192192+ let name = file.selector[file.selector.length - 1]!;
193193+ name = this.fileName?.(name) || name;
194194+ const extension = '.ts';
83195 this.files.register({
84196 extension,
8585- external: true,
8686- path: filePath,
197197+ name,
198198+ path: path.resolve(this.root, ...dirs, `${name}${extension}`),
87199 selector: file.selector,
88200 });
8989- continue;
90201 }
9191- const dirs = file.selector.slice(0, -1);
9292- let name = file.selector[file.selector.length - 1]!;
9393- name = this.fileName?.(name) || name;
9494- this.files.register({
9595- extension,
9696- name,
9797- path: path.resolve(this.root, ...dirs, `${name}${extension}`),
9898- selector: file.selector,
9999- });
100202 }
101101-102102- // TODO: track symbol dependencies and inject imports into files
103103- // based on symbol references so the render step can just render
104203 }
105204106106- render(meta?: IProjectRenderMeta): ReadonlyArray<IOutput> {
107107- this.prepareFiles();
205205+ private renderFiles(meta?: IProjectRenderMeta): ReadonlyArray<IOutput> {
108206 const files: Map<number, IOutput> = new Map();
109207 for (const file of this.files.registered()) {
110208 if (file.external || !file.path) continue;
111111- const renderer = this.getRenderer(file);
209209+ const renderer = file.extension
210210+ ? this.renderers[file.extension]
211211+ : undefined;
112212 if (!renderer) continue;
113213 files.set(file.id, {
114114- content: renderer.renderSymbols(file, this, meta),
214214+ content: renderer.render(file, this, meta),
115215 path: file.path,
116216 });
117217 }
118118- for (const [fileId, value] of files.entries()) {
119119- const file = this.files.get(fileId)!;
120120- const renderer = this.getRenderer(file)!;
121121- const content = renderer.renderFile(value.content, file, this, meta);
122122- if (content) {
123123- files.set(file.id, { ...value, content });
124124- } else {
125125- files.delete(file.id);
218218+ return Array.from(files.values());
219219+ }
220220+221221+ private resolveSymbolFinalName(symbol: Symbol): void {
222222+ const file = symbol.file;
223223+ if (symbol._finalName || !file) return;
224224+225225+ let name = symbol.name;
226226+ let index = 1;
227227+ while (file.reservedNames.has(name)) {
228228+ const scopes = file.reservedNames.get(name)!;
229229+ let exit = true;
230230+ for (const kind of scopes) {
231231+ if (!canShareName(symbol.kind, kind)) {
232232+ exit = false;
233233+ index = index + 1;
234234+ name = `${name}${index}`;
235235+ break;
236236+ }
126237 }
238238+ if (exit) break;
127239 }
128128- return Array.from(files.values());
240240+ // TODO: ensure valid names
241241+ symbol.setFinalName(name);
242242+ const scopes = file.reservedNames.get(name) ?? new Set<SymbolKind>();
243243+ scopes.add(symbol.kind);
244244+ file.reservedNames.set(name, scopes);
129245 }
130246131131- symbolIdToFiles(symbolId: number): ReadonlyArray<IFileOut> {
132132- const fileIds = this.symbolIdToFileIds.get(symbolId);
133133- return Array.from(fileIds ?? []).map((fileId) => this.files.get(fileId)!);
247247+ private resolveFinalSymbolNames(): void {
248248+ for (const file of this.files.registered()) {
249249+ for (const symbol of file.symbols) {
250250+ this.resolveSymbolFinalName(symbol);
251251+ }
252252+ }
134253 }
135254136255 private symbolToFileSelector(symbol: Symbol): IFileSelector {
+9-24
packages/codegen-core/src/project/types.d.ts
···11import type { IProjectRenderMeta } from '../extensions';
22-import type { IFileOut, IFileRegistry } from '../files/types';
22+import type { IFileRegistry } from '../files/types';
33+import type { INodeRegistry } from '../nodes/types';
34import type { IOutput } from '../output';
45import type { IRenderer } from '../renderer/types';
56import type { ISymbolRegistry } from '../symbols/types';
6778/**
88- * Represents a code generation project consisting of multiple codegen files.
99+ * Represents a code generation project consisting of codegen files.
1010+ *
911 * Manages imports, symbols, and output generation across the project.
1012 */
1113export interface IProject {
···2224 * @returns The transformed file name.
2325 */
2426 readonly fileName?: (name: string) => string;
2525- /**
2626- * Centralized file registry for the project.
2727- */
2727+ /** Centralized file registry for the project. */
2828 readonly files: IFileRegistry;
2929+ /** Centralized node registry for the project. */
3030+ readonly nodes: INodeRegistry;
2931 /**
3032 * Produces output representations for all files in the project.
3133 *
···4547 * }
4648 */
4749 readonly renderers: Record<string, IRenderer>;
4848- /**
4949- * The absolute path to the root folder of the project.
5050- */
5050+ /** The absolute path to the root folder of the project. */
5151 readonly root: string;
5252- /**
5353- * Retrieves files that include symbol ID. The first file is the one
5454- * where the symbol is declared, the rest are files that re-export it.
5555- *
5656- * @param symbolId The symbol ID to find.
5757- * @returns An array of files containing the symbol.
5858- * @example
5959- * const files = project.symbolIdToFiles(31);
6060- * for (const file of files) {
6161- * console.log(file.path);
6262- * }
6363- */
6464- symbolIdToFiles(symbolId: number): ReadonlyArray<IFileOut>;
6565- /**
6666- * Centralized symbol registry for the project.
6767- */
5252+ /** Centralized symbol registry for the project. */
6853 readonly symbols: ISymbolRegistry;
6954}
+9
packages/codegen-core/src/renderer/types.d.ts
···4455export interface IRenderer {
66 /**
77+ * Renders the given file.
88+ *
99+ * @param file The file to render.
1010+ * @param project The project the file belongs to.
1111+ * @param meta Arbitrary metadata.
1212+ * @returns Rendered content.
1313+ */
1414+ render(file: IFileOut, project: IProject, meta?: IProjectRenderMeta): string;
1515+ /**
716 * Renders content with replaced symbols.
817 *
918 * @param content Content to render.
+61
packages/codegen-core/src/symbols/analyzer.ts
···11+import { debug } from '../debug';
22+import type { INode } from '../nodes/node';
33+import type { Symbol } from './symbol';
44+55+export interface IAnalysisContext {
66+ /** Register a dependency on another symbol. */
77+ addDependency(symbol: Symbol): void;
88+ /** Local names declared by nodes within the analyzed symbol. */
99+ localNames: Set<string>;
1010+ /** Root symbol for the current top‑level analysis pass. */
1111+ root: Symbol;
1212+ /** Collected symbol references discovered during analysis. */
1313+ symbols: Set<Symbol>;
1414+}
1515+1616+export class AnalysisContext implements IAnalysisContext {
1717+ localNames: Set<string> = new Set();
1818+ root: Symbol;
1919+ symbols: Set<Symbol> = new Set();
2020+2121+ constructor(symbol: Symbol) {
2222+ this.root = symbol;
2323+ }
2424+2525+ addDependency(symbol: Symbol): void {
2626+ if (this.root !== symbol) {
2727+ this.symbols.add(symbol);
2828+ }
2929+ }
3030+}
3131+3232+export class Analyzer {
3333+ private nodeCache = new WeakMap<INode, AnalysisContext>();
3434+3535+ analyzeNode(node: INode): AnalysisContext {
3636+ const cached = this.nodeCache.get(node);
3737+ if (cached) return cached;
3838+3939+ if (!node.symbol) {
4040+ const message = `Analyzer: cannot analyze node "${node}" without a defining symbol.`;
4141+ debug(message, 'analyzer');
4242+ throw new Error(message);
4343+ }
4444+4545+ const ctx = new AnalysisContext(node.symbol);
4646+ node.analyze(ctx);
4747+4848+ this.nodeCache.set(node, ctx);
4949+ return ctx;
5050+ }
5151+5252+ analyze(
5353+ nodes: ReadonlyArray<INode>,
5454+ callback?: (ctx: AnalysisContext) => void,
5555+ ): void {
5656+ for (const node of nodes) {
5757+ const ctx = this.analyzeNode(node);
5858+ callback?.(ctx);
5959+ }
6060+ }
6161+}
···11import { debug } from '../debug';
22import type { ISymbolMeta } from '../extensions';
33import type { IFileOut } from '../files/types';
44+import type { INode } from '../nodes/node';
45import { wrapId } from '../renderer/utils';
55-import type { ISyntaxNode } from '../syntax-node';
66import type { ISymbolIn, SymbolImportKind, SymbolKind } from './types';
77+88+export const symbolBrand = globalThis.Symbol('symbol');
79810export class Symbol {
911 /**
···4951 private _file?: IFileOut;
5052 /**
5153 * The alias-resolved, conflict-free emitted name.
5252- *
5353- * @private
5454 */
5555- private _finalName?: string;
5555+ _finalName?: string;
5656 /**
5757 * Custom strategy to determine file output path.
5858 *
···8484 */
8585 private _name: string;
8686 /**
8787- * Root node that defines this symbol.
8787+ * Node that defines this symbol.
8888 *
8989 * @private
9090 */
9191- private _rootNode?: ISyntaxNode;
9191+ private _node?: INode;
92929393+ /** Brand used for identifying symbols. */
9494+ readonly '~brand': symbol = symbolBrand;
9395 /**
9496 * Globally unique, stable symbol ID.
9597 */
···208210 }
209211210212 /**
211211- * Read‑only accessor for the defining DSL root node.
213213+ * Read‑only accessor for the defining node.
212214 */
213213- get rootNode(): ISyntaxNode | undefined {
214214- return this.canonical._rootNode;
215215+ get node(): INode | undefined {
216216+ return this.canonical._node;
215217 }
216218217219 /**
···315317 *
316318 * This may only be set once.
317319 */
318318- setRootNode(node: ISyntaxNode): void {
320320+ setNode(node: INode): void {
319321 this.assertCanonical();
320320- if (this._rootNode && this._rootNode !== node) {
321321- throw new Error('Symbol is already bound to a different root node.');
322322+ if (this._node && this._node !== node) {
323323+ throw new Error('Symbol is already bound to a different node.');
322324 }
323323- this._rootNode = node;
325325+ this._node = node;
326326+ node.symbol = this;
324327 }
325328326329 /**
···349352 }
350353 }
351354}
355355+356356+export function isSymbol(value: unknown): value is Symbol {
357357+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
358358+ const obj = value as { '~brand'?: unknown };
359359+ return obj['~brand'] === symbolBrand && Object.hasOwn(obj, '~brand');
360360+}
-20
packages/codegen-core/src/syntax-node.d.ts
···11-import type { Symbol } from './symbols/symbol';
22-33-export interface ISyntaxNode {
44- /**
55- * Collect symbols referenced directly by this node into the provided accumulator.
66- */
77- collectSymbols(out: Set<Symbol>): void;
88- /**
99- * Return local names introduced by this node.
1010- */
1111- getLocalNames(): Iterable<string>;
1212- /**
1313- * Rewrite local identifiers based on a rename map.
1414- */
1515- rewriteIdentifiers(map: Map<string, string>): void;
1616- /**
1717- * Walk this node and its children with a visitor.
1818- */
1919- traverse(visitor: (node: ISyntaxNode) => void): void;
2020-}
···11-import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node, Symbol } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344-import type { MaybeTsDsl } from '../base';
44+import { isTsDsl, type MaybeTsDsl } from '../base';
55import { DecoratorTsDsl } from '../decl/decorator';
66import type { BaseCtor, MixinCtor } from './types';
7788-export interface DecoratorMethods extends SyntaxNode {
88+export interface DecoratorMethods extends Node {
99 /** Renders the decorators into an array of `ts.Decorator`s. */
1010 $decorators(): ReadonlyArray<ts.Decorator>;
1111 /** Adds a decorator (e.g. `@sealed({ in: 'root' })`). */
···2121 abstract class Decorator extends Base {
2222 protected decorators: Array<DecoratorTsDsl> = [];
23232424+ override analyze(ctx: AnalysisContext): void {
2525+ super.analyze(ctx);
2626+ for (const decorator of this.decorators) {
2727+ if (isTsDsl(decorator)) decorator.analyze(ctx);
2828+ }
2929+ }
3030+2431 protected decorator(
2532 name: Symbol | string | MaybeTsDsl<ts.Expression>,
2633 ...args: ReadonlyArray<string | MaybeTsDsl<ts.Expression>>
2734 ): this {
2828- this.decorators.push(new DecoratorTsDsl(name, ...args).setParent(this));
3535+ this.decorators.push(new DecoratorTsDsl(name, ...args));
2936 return this;
3037 }
3138
+10-3
packages/openapi-ts/src/ts-dsl/mixins/do.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344-import type { MaybeTsDsl } from '../base';
44+import { isTsDsl, type MaybeTsDsl } from '../base';
55import { StmtTsDsl } from '../stmt/stmt';
66import type { BaseCtor, MixinCtor } from './types';
7788-export interface DoMethods extends SyntaxNode {
88+export interface DoMethods extends Node {
99 /** Renders the collected `.do()` calls into an array of `Statement` nodes. */
1010 $do(): ReadonlyArray<ts.Statement>;
1111 /** Adds one or more expressions/statements to the body. */
···2020) {
2121 abstract class Do extends Base {
2222 protected _do: Array<MaybeTsDsl<ts.Expression | ts.Statement>> = [];
2323+2424+ override analyze(ctx: AnalysisContext): void {
2525+ super.analyze(ctx);
2626+ for (const item of this._do) {
2727+ if (isTsDsl(item)) item.analyze(ctx);
2828+ }
2929+ }
23302431 protected do(
2532 ...items: ReadonlyArray<MaybeTsDsl<ts.Expression | ts.Statement>>
+6-2
packages/openapi-ts/src/ts-dsl/mixins/doc.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344import type { MaybeArray } from '../base';
55import { DocTsDsl } from '../layout/doc';
66import type { BaseCtor, MixinCtor } from './types';
7788-export interface DocMethods extends SyntaxNode {
88+export interface DocMethods extends Node {
99 doc(lines?: MaybeArray<string>, fn?: (d: DocTsDsl) => void): this;
1010}
1111···1414) {
1515 abstract class Doc extends Base {
1616 protected _doc?: DocTsDsl;
1717+1818+ override analyze(ctx: AnalysisContext): void {
1919+ super.analyze(ctx);
2020+ }
17211822 protected doc(
1923 lines?: MaybeArray<string>,
+31-42
packages/openapi-ts/src/ts-dsl/mixins/expr.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344-import type { MaybeTsDsl } from '../base';
55-import type { AttrTsDsl } from '../expr/attr';
66-import type { AwaitTsDsl } from '../expr/await';
77-import type { CallTsDsl } from '../expr/call';
88-import type { ReturnTsDsl } from '../stmt/return';
44+import type { AttrCtor, AttrRight, AttrTsDsl } from '../expr/attr';
55+import type { AwaitCtor, AwaitTsDsl } from '../expr/await';
66+import type { CallArgs, CallCtor, CallTsDsl } from '../expr/call';
77+import type { ReturnCtor, ReturnTsDsl } from '../stmt/return';
98import type { BaseCtor, MixinCtor } from './types';
1091111-type AttrFactory = (
1212- expr: MaybeTsDsl<ts.Expression>,
1313- name: string | ts.MemberName | number,
1414-) => AttrTsDsl;
1515-let attrFactory: AttrFactory | undefined;
1616-/** Registers the Attr DSL factory after its module has finished evaluating. */
1717-export function registerLazyAccessAttrFactory(factory: AttrFactory): void {
1818- attrFactory = factory;
1010+let attrFactory: AttrCtor | undefined;
1111+/** Lazy register the factory to avoid circular imports. */
1212+export function setAttrFactory(fn: AttrCtor): void {
1313+ attrFactory = fn;
1914}
20152121-type AwaitFactory = (expr: MaybeTsDsl<ts.Expression>) => AwaitTsDsl;
2222-let awaitFactory: AwaitFactory | undefined;
2323-/** Registers the Await DSL factory after its module has finished evaluating. */
2424-export function registerLazyAccessAwaitFactory(factory: AwaitFactory): void {
2525- awaitFactory = factory;
1616+let awaitFactory: AwaitCtor | undefined;
1717+/** Lazy register the factory to avoid circular imports. */
1818+export function setAwaitFactory(fn: AwaitCtor): void {
1919+ awaitFactory = fn;
2620}
27212828-type CallFactory = (
2929- expr: MaybeTsDsl<ts.Expression>,
3030- args: ReadonlyArray<string | MaybeTsDsl<ts.Expression> | undefined>,
3131-) => CallTsDsl;
3232-let callFactory: CallFactory | undefined;
3333-/** Registers the Call DSL factory after its module has finished evaluating. */
3434-export function registerLazyAccessCallFactory(factory: CallFactory): void {
3535- callFactory = factory;
2222+let callFactory: CallCtor | undefined;
2323+/** Lazy register the factory to avoid circular imports. */
2424+export function setCallFactory(fn: CallCtor): void {
2525+ callFactory = fn;
3626}
37273838-type ReturnFactory = (expr: MaybeTsDsl<ts.Expression>) => ReturnTsDsl;
3939-let returnFactory: ReturnFactory | undefined;
4040-/** Registers the Return DSL factory after its module has finished evaluating. */
4141-export function registerLazyAccessReturnFactory(factory: ReturnFactory): void {
4242- returnFactory = factory;
2828+let returnFactory: ReturnCtor | undefined;
2929+/** Lazy register the factory to avoid circular imports. */
3030+export function setReturnFactory(fn: ReturnCtor): void {
3131+ returnFactory = fn;
4332}
44334545-export interface ExprMethods extends SyntaxNode {
3434+export interface ExprMethods extends Node {
4635 /** Accesses a property on the current expression (e.g. `this.foo`). */
4747- attr(name: string | ts.MemberName | number): AttrTsDsl;
3636+ attr(name: AttrRight): AttrTsDsl;
4837 /** Awaits the current expression (e.g. `await expr`). */
4938 await(): AwaitTsDsl;
5039 /** Calls the current expression (e.g. `fn(arg1, arg2)`). */
5151- call(
5252- ...args: ReadonlyArray<string | MaybeTsDsl<ts.Expression> | undefined>
5353- ): CallTsDsl;
4040+ call(...args: CallArgs): CallTsDsl;
5441 /** Produces a `return` statement returning the current expression. */
5542 return(): ReturnTsDsl;
5643}
···5946 Base: TBase,
6047) {
6148 abstract class Expr extends Base {
6262- protected attr(name: string | ts.MemberName | number): AttrTsDsl {
4949+ override analyze(ctx: AnalysisContext): void {
5050+ super.analyze(ctx);
5151+ }
5252+5353+ protected attr(name: AttrRight): AttrTsDsl {
6354 return attrFactory!(this, name);
6455 }
6556···6758 return awaitFactory!(this);
6859 }
69607070- protected call(
7171- ...args: ReadonlyArray<string | MaybeTsDsl<ts.Expression> | undefined>
7272- ): CallTsDsl {
7373- return callFactory!(this, args);
6161+ protected call(...args: CallArgs): CallTsDsl {
6262+ return callFactory!(this, ...args);
7463 }
75647665 protected return(): ReturnTsDsl {
+6-2
packages/openapi-ts/src/ts-dsl/mixins/hint.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344import type { MaybeArray } from '../base';
55import { HintTsDsl } from '../layout/hint';
66import type { BaseCtor, MixinCtor } from './types';
7788-export interface HintMethods extends SyntaxNode {
88+export interface HintMethods extends Node {
99 hint(lines?: MaybeArray<string>, fn?: (h: HintTsDsl) => void): this;
1010}
1111···1414) {
1515 abstract class Hint extends Base {
1616 protected _hint?: HintTsDsl;
1717+1818+ override analyze(ctx: AnalysisContext): void {
1919+ super.analyze(ctx);
2020+ }
17211822 protected hint(
1923 lines?: MaybeArray<string>,
+6-2
packages/openapi-ts/src/ts-dsl/mixins/layout.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344import type { BaseCtor, MixinCtor } from './types';
5566-export interface LayoutMethods extends SyntaxNode {
66+export interface LayoutMethods extends Node {
77 /** Computes whether output should be multiline based on layout setting and element count. */
88 $multiline(count: number): boolean;
99 /** Sets automatic line output with optional threshold (default: 3). */
···2020 abstract class Layout extends Base {
2121 protected static readonly DEFAULT_THRESHOLD = 3;
2222 protected layout: boolean | number | undefined;
2323+2424+ override analyze(ctx: AnalysisContext): void {
2525+ super.analyze(ctx);
2626+ }
23272428 protected auto(threshold: number = Layout.DEFAULT_THRESHOLD): this {
2529 this.layout = threshold;
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
22-import { Symbol } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
33import type ts from 'typescript';
4455-import type { MaybeTsDsl } from '../base';
66-import { TsDsl } from '../base';
55+import { isTsDsl, type MaybeTsDsl } from '../base';
76import { TypeParamTsDsl } from '../type/param';
87import type { BaseCtor, MixinCtor } from './types';
981010-export interface TypeParamsMethods extends SyntaxNode {
99+export interface TypeParamsMethods extends Node {
1110 /** Returns the type parameters as an array of ts.TypeParameterDeclaration nodes. */
1211 $generics(): ReadonlyArray<ts.TypeParameterDeclaration> | undefined;
1312 /** Adds a single type parameter (e.g. `T` in `Array<T>`). */
···2423 abstract class TypeParams extends Base {
2524 protected _generics: Array<MaybeTsDsl<TypeParamTsDsl>> = [];
26252626+ override analyze(ctx: AnalysisContext): void {
2727+ super.analyze(ctx);
2828+ for (const g of this._generics) {
2929+ if (isTsDsl(g)) g.analyze(ctx);
3030+ }
3131+ }
3232+2733 protected generic(
2834 ...args: ConstructorParameters<typeof TypeParamTsDsl>
2935 ): this {
3030- const g = new TypeParamTsDsl(...args).setParent(this);
3636+ const g = new TypeParamTsDsl(...args);
3137 this._generics.push(g);
3238 return this;
3339 }
···3642 ...args: ReadonlyArray<Symbol | string | MaybeTsDsl<TypeParamTsDsl>>
3743 ): this {
3844 for (let arg of args) {
3939- if (typeof arg === 'string' || arg instanceof Symbol) {
4545+ if (typeof arg === 'string' || isSymbol(arg)) {
4046 arg = new TypeParamTsDsl(arg);
4141- }
4242- if (arg instanceof TsDsl) {
4343- arg.setParent(this);
4447 }
4548 this._generics.push(arg);
4649 }
+13-6
packages/openapi-ts/src/ts-dsl/mixins/value.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Node } from '@hey-api/codegen-core';
22import type ts from 'typescript';
3344-import type { MaybeTsDsl } from '../base';
44+import { isTsDsl, type MaybeTsDsl } from '../base';
55import type { BaseCtor, MixinCtor } from './types';
6677-export interface ValueMethods extends SyntaxNode {
77+export type ValueExpr = string | MaybeTsDsl<ts.Expression>;
88+99+export interface ValueMethods extends Node {
810 $value(): ts.Expression | undefined;
911 /** Sets the initializer expression (e.g. `= expr`). */
1010- assign(expr: string | MaybeTsDsl<ts.Expression>): this;
1212+ assign(expr: ValueExpr): this;
1113}
12141315export function ValueMixin<T extends ts.Node, TBase extends BaseCtor<T>>(
1416 Base: TBase,
1517) {
1618 abstract class Value extends Base {
1717- protected value?: string | MaybeTsDsl<ts.Expression>;
1919+ protected value?: ValueExpr;
2020+2121+ override analyze(ctx: AnalysisContext): void {
2222+ super.analyze(ctx);
2323+ if (isTsDsl(this.value)) this.value.analyze(ctx);
2424+ }
18251919- protected assign(expr: string | MaybeTsDsl<ts.Expression>): this {
2626+ protected assign(expr: ValueExpr): this {
2027 this.value = expr;
2128 return this;
2229 }
+12-6
packages/openapi-ts/src/ts-dsl/stmt/if.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TsDsl } from '../base';
55+import { isTsDsl, TsDsl } from '../base';
66import { DoMixin } from '../mixins/do';
7788const Mixed = DoMixin(TsDsl<ts.IfStatement>);
···1616 if (condition) this.condition(condition);
1717 }
18181919+ override analyze(ctx: AnalysisContext): void {
2020+ super.analyze(ctx);
2121+ if (isTsDsl(this._condition)) this._condition.analyze(ctx);
2222+ if (this._else) {
2323+ for (const stmt of this._else) {
2424+ if (isTsDsl(stmt)) stmt.analyze(ctx);
2525+ }
2626+ }
2727+ }
2828+1929 condition(condition: string | MaybeTsDsl<ts.Expression>): this {
2030 this._condition = condition;
2131 return this;
···2434 otherwise(...statements: ReadonlyArray<MaybeTsDsl<ts.Statement>>): this {
2535 this._else = statements;
2636 return this;
2727- }
2828-2929- override traverse(visitor: (node: SyntaxNode) => void): void {
3030- super.traverse(visitor);
3137 }
32383339 protected override _render() {
+17-8
packages/openapi-ts/src/ts-dsl/stmt/return.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
55-import { TsDsl } from '../base';
66-import { registerLazyAccessReturnFactory } from '../mixins/expr';
66+import { isTsDsl, TsDsl } from '../base';
77+import { setReturnFactory } from '../mixins/expr';
88+99+export type ReturnExpr = Symbol | string | MaybeTsDsl<ts.Expression>;
1010+export type ReturnCtor = (expr?: ReturnExpr) => ReturnTsDsl;
711812const Mixed = TsDsl<ts.ReturnStatement>;
9131014export class ReturnTsDsl extends Mixed {
1111- protected _returnExpr?: string | MaybeTsDsl<ts.Expression>;
1515+ protected _returnExpr?: ReturnExpr;
12161313- constructor(expr?: string | MaybeTsDsl<ts.Expression>) {
1717+ constructor(expr?: ReturnExpr) {
1418 super();
1519 this._returnExpr = expr;
1620 }
17211818- override traverse(visitor: (node: SyntaxNode) => void): void {
1919- super.traverse(visitor);
2222+ override analyze(ctx: AnalysisContext): void {
2323+ super.analyze(ctx);
2424+ if (isSymbol(this._returnExpr)) {
2525+ ctx.addDependency(this._returnExpr);
2626+ } else if (isTsDsl(this._returnExpr)) {
2727+ this._returnExpr.analyze(ctx);
2828+ }
2029 }
21302231 protected override _render() {
···2433 }
2534}
26352727-registerLazyAccessReturnFactory((...args) => new ReturnTsDsl(...args));
3636+setReturnFactory((...args) => new ReturnTsDsl(...args));
+5-4
packages/openapi-ts/src/ts-dsl/stmt/stmt.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344-import { TsDsl } from '../base';
44+import { isTsDsl, TsDsl } from '../base';
5566const Mixed = TsDsl<ts.Statement>;
77···1313 this._inner = inner;
1414 }
15151616- override traverse(visitor: (node: SyntaxNode) => void): void {
1717- super.traverse(visitor);
1616+ override analyze(ctx: AnalysisContext): void {
1717+ super.analyze(ctx);
1818+ if (isTsDsl(this._inner)) this._inner.analyze(ctx);
1819 }
19202021 protected override _render() {
+8-6
packages/openapi-ts/src/ts-dsl/stmt/throw.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TsDsl } from '../base';
55+import { isTsDsl, TsDsl } from '../base';
66import { LiteralTsDsl } from '../expr/literal';
7788const Mixed = TsDsl<ts.ThrowStatement>;
···1818 this.useNew = useNew;
1919 }
20202121+ override analyze(ctx: AnalysisContext): void {
2222+ super.analyze(ctx);
2323+ if (isTsDsl(this.error)) this.error.analyze(ctx);
2424+ if (isTsDsl(this.msg)) this.msg.analyze(ctx);
2525+ }
2626+2127 message(value: string | MaybeTsDsl<ts.Expression>): this {
2228 this.msg = value;
2329 return this;
2424- }
2525-2626- override traverse(visitor: (node: SyntaxNode) => void): void {
2727- super.traverse(visitor);
2830 }
29313032 protected override _render() {
+18-17
packages/openapi-ts/src/ts-dsl/stmt/var.ts
···11-import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import { TsDsl, TypeTsDsl } from '../base';
···89import { PatternMixin } from '../mixins/pattern';
910import { ValueMixin } from '../mixins/value';
1011import { TypeExprTsDsl } from '../type/expr';
1212+1313+export type VarName = Symbol | string;
11141215const Mixed = DefaultMixin(
1316 DocMixin(
···19222023export class VarTsDsl extends Mixed {
2124 protected kind: ts.NodeFlags = ts.NodeFlags.None;
2222- protected name?: string;
2525+ protected name?: VarName;
2326 protected _type?: TypeTsDsl;
24272525- constructor(name?: Symbol | string) {
2828+ constructor(name?: VarName) {
2629 super();
2727- if (name) {
2828- if (typeof name === 'string') {
2929- this.name = name;
3030- } else {
3131- this.name = name.finalName;
3232- this.symbol = name;
3333- this.symbol.setKind('var');
3434- this.symbol.setRootNode(this);
3535- }
3030+ this.name = name;
3131+ if (isSymbol(name)) {
3232+ name.setKind('var');
3333+ name.setNode(this);
3634 }
3735 }
38363737+ override analyze(ctx: AnalysisContext): void {
3838+ super.analyze(ctx);
3939+ if (isSymbol(this.name)) ctx.addDependency(this.name);
4040+ this._type?.analyze(ctx);
4141+ }
4242+3943 const(): this {
4044 this.kind = ts.NodeFlags.Const;
4145 return this;
···4650 return this;
4751 }
48524949- override traverse(visitor: (node: SyntaxNode) => void): void {
5050- super.traverse(visitor);
5151- }
5252-5353 /** Sets the variable type. */
5454 type(type: string | TypeTsDsl): this {
5555 this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
···6262 }
63636464 protected override _render() {
6565- const name = this.$pattern() ?? this.name;
6565+ const name = this.$pattern() ?? this.$node(this.name);
6666 if (!name)
6767 throw new Error('Var must have either a name or a destructuring pattern');
6868 return ts.factory.createVariableStatement(
···7070 ts.factory.createVariableDeclarationList(
7171 [
7272 ts.factory.createVariableDeclaration(
7373+ // @ts-expect-error need to improve types
7374 name,
7475 undefined,
7576 this.$type(this._type),
+13-28
packages/openapi-ts/src/ts-dsl/type/alias.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
22-import { Symbol } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
33import ts from 'typescript';
4455import type { MaybeTsDsl } from '../base';
66-import { TsDsl } from '../base';
66+import { isTsDsl, TsDsl } from '../base';
77import { DocMixin } from '../mixins/doc';
88import { ExportMixin } from '../mixins/modifiers';
99import { TypeParamsMixin } from '../mixins/type-params';
···21212222 constructor(name: Name, fn?: (t: TypeAliasTsDsl) => void) {
2323 super();
2424- if (typeof name === 'string') {
2525- this.name = name;
2626- } else {
2727- this.name = name;
2828- this.symbol = name;
2929- this.symbol.setKind('type');
3030- this.symbol.setRootNode(this);
2424+ this.name = name;
2525+ if (isSymbol(name)) {
2626+ name.setKind('type');
2727+ name.setNode(this);
3128 }
3229 fn?.(this);
3330 }
34313535- override collectSymbols(out: Set<Symbol>): void {
3636- super.collectSymbols(out);
3737- if (this.name instanceof Symbol) {
3838- out.add(this.name);
3939- }
4040- if (this.value instanceof TsDsl) {
4141- this.value.collectSymbols(out);
4242- }
4343- }
4444-4545- override traverse(visitor: (node: SyntaxNode) => void): void {
4646- super.traverse(visitor);
4747- if (this.value instanceof TsDsl) {
4848- this.value.traverse(visitor);
4949- }
3232+ override analyze(ctx: AnalysisContext): void {
3333+ super.analyze(ctx);
3434+ if (isSymbol(this.name)) ctx.addDependency(this.name);
3535+ if (isTsDsl(this.value)) this.value.analyze(ctx);
5036 }
51375238 /** Sets the type expression on the right-hand side of `= ...`. */
5339 type(node: Value): this {
5440 this.value = node;
5555- if (this.value instanceof TsDsl) this.value.setParent(this);
5641 return this;
5742 }
58435944 protected override _render() {
6045 if (!this.value)
6146 throw new Error(`Type alias '${this.name}' is missing a type definition`);
6262- const name = this.name instanceof Symbol ? this.name.finalName : this.name;
6347 return ts.factory.createTypeAliasDeclaration(
6448 this.modifiers,
6565- name,
4949+ // @ts-expect-error need to improve types
5050+ this.$node(this.name),
6651 this.$generics(),
6752 this.$type(this.value),
6853 );
+17-7
packages/openapi-ts/src/ts-dsl/type/and.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
23import ts from 'typescript';
3444-import { TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66+77+type Type = Symbol | string | ts.TypeNode | TypeTsDsl;
5869const Mixed = TypeTsDsl<ts.IntersectionTypeNode>;
710811export class TypeAndTsDsl extends Mixed {
99- protected _types: Array<string | ts.TypeNode | TypeTsDsl> = [];
1212+ protected _types: Array<Type> = [];
10131111- constructor(...nodes: Array<string | ts.TypeNode | TypeTsDsl>) {
1414+ constructor(...nodes: Array<Type>) {
1215 super();
1316 this.types(...nodes);
1417 }
15181616- override traverse(visitor: (node: SyntaxNode) => void): void {
1717- super.traverse(visitor);
1919+ override analyze(ctx: AnalysisContext): void {
2020+ super.analyze(ctx);
2121+ for (const t of this._types) {
2222+ if (isSymbol(t)) {
2323+ ctx.addDependency(t);
2424+ } else if (isTsDsl(t)) {
2525+ t.analyze(ctx);
2626+ }
2727+ }
1828 }
19292020- types(...nodes: Array<string | ts.TypeNode | TypeTsDsl>): this {
3030+ types(...nodes: Array<Type>): this {
2131 this._types.push(...nodes);
2232 return this;
2333 }
+19-34
packages/openapi-ts/src/ts-dsl/type/attr.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
22-import { Symbol } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
33import ts from 'typescript';
4455import type { MaybeTsDsl } from '../base';
66-import { TsDsl, TypeTsDsl } from '../base';
66+import { isTsDsl, TypeTsDsl } from '../base';
77import { TypeExprMixin } from '../mixins/type-expr';
8899type Base = Symbol | string | MaybeTsDsl<ts.EntityName>;
···2828 }
2929 }
30303131+ override analyze(ctx: AnalysisContext): void {
3232+ super.analyze(ctx);
3333+ if (isSymbol(this._base)) {
3434+ ctx.addDependency(this._base);
3535+ } else if (isTsDsl(this._base)) {
3636+ this._base.analyze(ctx);
3737+ }
3838+ if (isSymbol(this._right)) ctx.addDependency(this._right);
3939+ }
4040+3141 base(base?: Base): this {
3242 this._base = base;
3333- if (this._base instanceof TsDsl) this._base.setParent(this);
3443 return this;
3544 }
3645···3948 return this;
4049 }
41504242- override collectSymbols(out: Set<Symbol>): void {
4343- super.collectSymbols(out);
4444- if (this._base) {
4545- if (this._base instanceof Symbol) {
4646- out.add(this._base);
4747- } else if (this._base instanceof TsDsl) {
4848- this._base.collectSymbols(out);
4949- }
5050- }
5151- if (this._right instanceof Symbol) {
5252- out.add(this._right);
5353- }
5454- }
5555-5656- override traverse(visitor: (node: SyntaxNode) => void): void {
5757- super.traverse(visitor);
5858- if (this._base instanceof TsDsl) {
5959- this._base.traverse(visitor);
6060- }
6161- }
6262-6351 protected override _render() {
6452 if (!this._base) {
6553 throw new Error('TypeAttrTsDsl: missing base for qualified name');
6654 }
6767- const left =
6868- this._base instanceof Symbol
6969- ? this.$node(this._base.finalName)
7070- : this.$node(this._base);
5555+ const left = this.$node(this._base);
7156 if (!ts.isEntityName(left)) {
7257 throw new Error('TypeAttrTsDsl: base must be an EntityName');
7358 }
7474- const right =
7575- this._right instanceof Symbol
7676- ? this.$maybeId(this._right.finalName)
7777- : this.$maybeId(this._right);
7878- return ts.factory.createQualifiedName(left, right);
5959+ return ts.factory.createQualifiedName(
6060+ left,
6161+ // @ts-expect-error need to improve types
6262+ this.$node(this._right),
6363+ );
7964 }
8065}
+23-36
packages/openapi-ts/src/ts-dsl/type/expr.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
22-import { Symbol } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
33import ts from 'typescript';
4455-import { TsDsl, TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import { TypeArgsMixin } from '../mixins/type-args';
77import {
88 registerLazyAccessTypeExprFactory,
···1010} from '../mixins/type-expr';
1111import { TypeAttrTsDsl } from './attr';
12121313+export type TypeExprName = Symbol | string;
1414+export type TypeExprExpr = TypeExprName | TypeAttrTsDsl;
1515+1316const Mixed = TypeArgsMixin(TypeExprMixin(TypeTsDsl<ts.TypeReferenceNode>));
14171518export class TypeExprTsDsl extends Mixed {
1616- protected _exprInput?: Symbol | string | TypeAttrTsDsl;
1919+ protected _exprInput?: TypeExprExpr;
17201821 constructor();
1922 constructor(fn: (t: TypeExprTsDsl) => void);
2020- constructor(name: Symbol | string);
2121- constructor(name: Symbol | string, fn?: (t: TypeExprTsDsl) => void);
2323+ constructor(name: TypeExprName);
2424+ constructor(name: TypeExprName, fn?: (t: TypeExprTsDsl) => void);
2225 constructor(
2323- name?: Symbol | string | ((t: TypeExprTsDsl) => void),
2626+ name?: TypeExprName | ((t: TypeExprTsDsl) => void),
2427 fn?: (t: TypeExprTsDsl) => void,
2528 ) {
2629 super();
···3235 }
3336 }
34373838+ override analyze(ctx: AnalysisContext): void {
3939+ super.analyze(ctx);
4040+ if (isSymbol(this._exprInput)) {
4141+ ctx.addDependency(this._exprInput);
4242+ } else if (isTsDsl(this._exprInput)) {
4343+ this._exprInput.analyze(ctx);
4444+ }
4545+ }
4646+3547 /** Accesses a nested type (e.g. `Foo.Bar`). */
3648 attr(right: string | ts.Identifier | TypeAttrTsDsl): this {
3737- this._exprInput =
3838- right instanceof TypeAttrTsDsl
3939- ? right.base(this._exprInput)
4040- : new TypeAttrTsDsl(this._exprInput!, right);
4141- this._exprInput.setParent(this);
4949+ this._exprInput = isTsDsl(right)
5050+ ? right.base(this._exprInput)
5151+ : new TypeAttrTsDsl(this._exprInput!, right);
4252 return this;
4353 }
44544545- override collectSymbols(out: Set<Symbol>): void {
4646- super.collectSymbols(out);
4747- if (this._exprInput && typeof this._exprInput !== 'string') {
4848- if (this._exprInput instanceof Symbol) {
4949- out.add(this._exprInput);
5050- } else {
5151- this._exprInput.collectSymbols(out);
5252- }
5353- }
5454- }
5555-5656- override traverse(visitor: (node: SyntaxNode) => void): void {
5757- super.traverse(visitor);
5858- if (this._exprInput instanceof TsDsl) {
5959- this._exprInput.traverse(visitor);
6060- }
6161- }
6262-6355 protected override _render() {
6456 if (!this._exprInput) throw new Error('TypeExpr must have an expression');
6565- const typeName =
6666- typeof this._exprInput === 'string' ||
6767- this._exprInput instanceof TypeAttrTsDsl
6868- ? this.$type(this._exprInput)
6969- : this._exprInput.finalName;
7057 return ts.factory.createTypeReferenceNode(
7158 // @ts-expect-error --- need to fix types
7272- typeName,
5959+ this.$type(this._exprInput),
7360 this.$generics(),
7461 );
7562 }
+4-3
packages/openapi-ts/src/ts-dsl/type/fromValue.ts
···11import type ts from 'typescript';
2233-import { TsDsl } from '../base';
33+import type { TsDsl } from '../base';
44+import { isTsDsl } from '../base';
45import { TypeLiteralTsDsl } from './literal';
56import { TypeObjectTsDsl } from './object';
67import { TypeTupleTsDsl } from './tuple';
7889export const fromValue = (input: unknown): TsDsl<ts.TypeNode> => {
99- if (input instanceof TsDsl) {
1010- return input;
1010+ if (isTsDsl(input)) {
1111+ return input as TsDsl<ts.TypeNode>;
1112 }
12131314 if (input === null) {
+6-5
packages/openapi-ts/src/ts-dsl/type/func.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import { TypeTsDsl } from '../base';
···1414export class TypeFuncTsDsl extends Mixed {
1515 protected _returns?: TypeTsDsl;
16161717+ override analyze(ctx: AnalysisContext): void {
1818+ super.analyze(ctx);
1919+ this._returns?.analyze(ctx);
2020+ }
2121+1722 /** Sets the return type. */
1823 returns(type: string | TypeTsDsl): this {
1924 this._returns = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
2025 return this;
2121- }
2222-2323- override traverse(visitor: (node: SyntaxNode) => void): void {
2424- super.traverse(visitor);
2526 }
26272728 protected override _render() {
+19-16
packages/openapi-ts/src/ts-dsl/type/idx-sig.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import { DocMixin } from '../mixins/doc';
77import { ReadonlyMixin } from '../mixins/modifiers';
8899-type Type = string | MaybeTsDsl<ts.TypeNode>;
99+export type TypeIdxSigName = string;
1010+export type TypeIdxSigType = string | MaybeTsDsl<ts.TypeNode>;
10111112const Mixed = DocMixin(ReadonlyMixin(TypeTsDsl<ts.IndexSignatureDeclaration>));
12131314export class TypeIdxSigTsDsl extends Mixed {
1414- protected _key?: Type;
1515- protected _name: string;
1616- protected _type?: Type;
1515+ protected _key?: TypeIdxSigType;
1616+ protected _name: TypeIdxSigName;
1717+ protected _type?: TypeIdxSigType;
17181818- constructor(name: string, fn?: (i: TypeIdxSigTsDsl) => void) {
1919+ constructor(name: TypeIdxSigName, fn?: (i: TypeIdxSigTsDsl) => void) {
1920 super();
2021 this._name = name;
2122 fn?.(this);
2223 }
23242525+ override analyze(ctx: AnalysisContext): void {
2626+ super.analyze(ctx);
2727+ if (isTsDsl(this._key)) this._key.analyze(ctx);
2828+ if (isTsDsl(this._type)) this._type.analyze(ctx);
2929+ }
3030+2431 /** Returns true when all required builder calls are present. */
2532 get isValid(): boolean {
2633 return this.missingRequiredCalls().length === 0;
2734 }
28352936 /** Sets the key type: `[name: T]` */
3030- key(type: Type): this {
3737+ key(type: TypeIdxSigType): this {
3138 this._key = type;
3239 return this;
3340 }
34413535- override traverse(visitor: (node: SyntaxNode) => void): void {
3636- super.traverse(visitor);
3737- }
3838-3942 /** Sets the property type. */
4040- type(type: Type): this {
4343+ type(type: TypeIdxSigType): this {
4144 this._type = type;
4245 return this;
4346 }
···6063 }
61646265 $validate(): asserts this is this & {
6363- _key: Type;
6464- _name: string;
6565- _type: Type;
6666+ _key: TypeIdxSigType;
6767+ _name: TypeIdxSigName;
6868+ _type: TypeIdxSigType;
6669 } {
6770 const missing = this.missingRequiredCalls();
6871 if (missing.length === 0) return;
+8-14
packages/openapi-ts/src/ts-dsl/type/idx.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TsDsl, TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import {
77 registerLazyAccessTypeIdxFactory,
88 TypeExprMixin,
···2323 this.index(index);
2424 }
25252626+ override analyze(ctx: AnalysisContext): void {
2727+ super.analyze(ctx);
2828+ if (isTsDsl(this._base)) this._base.analyze(ctx);
2929+ if (isTsDsl(this._index)) this._index.analyze(ctx);
3030+ }
3131+2632 base(base: Base): this {
2733 this._base = base;
2828- if (this._base instanceof TsDsl) this._base.setParent(this);
2934 return this;
3035 }
31363237 index(index: Index): this {
3338 this._index = index;
3434- if (this._index instanceof TsDsl) this._index.setParent(this);
3539 return this;
3636- }
3737-3838- override traverse(visitor: (node: SyntaxNode) => void): void {
3939- super.traverse(visitor);
4040- if (this._base instanceof TsDsl) {
4141- this._base.traverse(visitor);
4242- }
4343- if (this._index instanceof TsDsl) {
4444- this._index.traverse(visitor);
4545- }
4640 }
47414842 protected override _render() {
+3-3
packages/openapi-ts/src/ts-dsl/type/literal.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import { TypeTsDsl } from '../base';
···1414 this.value = value;
1515 }
16161717- override traverse(visitor: (node: SyntaxNode) => void): void {
1818- super.traverse(visitor);
1717+ override analyze(ctx: AnalysisContext): void {
1818+ super.analyze(ctx);
1919 }
20202121 protected override _render() {
+10-6
packages/openapi-ts/src/ts-dsl/type/mapped.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import { TokenTsDsl } from '../token';
7788const Mixed = TypeTsDsl<ts.MappedTypeNode>;
···2525 constructor(name?: string) {
2626 super();
2727 this.name(name);
2828+ }
2929+3030+ override analyze(ctx: AnalysisContext): void {
3131+ super.analyze(ctx);
3232+ this.questionToken?.analyze(ctx);
3333+ this.readonlyToken?.analyze(ctx);
3434+ if (isTsDsl(this._key)) this._key.analyze(ctx);
3535+ if (isTsDsl(this._type)) this._type.analyze(ctx);
2836 }
29373038 /** Returns true when all required builder calls are present. */
···6674 required(): this {
6775 this.questionToken = new TokenTsDsl().minus();
6876 return this;
6969- }
7070-7171- override traverse(visitor: (node: SyntaxNode) => void): void {
7272- super.traverse(visitor);
7377 }
74787579 /** Sets the mapped value type: `[K in X]: ValueType` */
+8-5
packages/openapi-ts/src/ts-dsl/type/object.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import { TypeTsDsl } from '../base';
···991010export class TypeObjectTsDsl extends Mixed {
1111 protected props: Array<TypePropTsDsl | TypeIdxSigTsDsl> = [];
1212+1313+ override analyze(ctx: AnalysisContext): void {
1414+ super.analyze(ctx);
1515+ for (const prop of this.props) {
1616+ prop.analyze(ctx);
1717+ }
1818+ }
12191320 /** Returns true if object has at least one property or spread. */
1421 hasProps(): boolean {
···3239 const prop = new TypePropTsDsl(name, fn);
3340 this.props.push(prop);
3441 return this;
3535- }
3636-3737- override traverse(visitor: (node: SyntaxNode) => void): void {
3838- super.traverse(visitor);
3942 }
40434144 protected override _render() {
+5-12
packages/openapi-ts/src/ts-dsl/type/operator.ts
···11-import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TsDsl, TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import { registerLazyAccessTypeOperatorFactory } from '../mixins/type-expr';
7788type Op =
···2929 protected _op?: Op;
3030 protected _type?: Type;
31313232- override collectSymbols(out: Set<Symbol>): void {
3333- super.collectSymbols(out);
3232+ override analyze(ctx: AnalysisContext): void {
3333+ super.analyze(ctx);
3434+ if (isTsDsl(this._type)) this._type.analyze(ctx);
3435 }
35363637 /** Shorthand: builds `keyof T`. */
···5354 return this;
5455 }
55565656- override traverse(visitor: (node: SyntaxNode) => void): void {
5757- super.traverse(visitor);
5858- if (this._type instanceof TsDsl) {
5959- this._type.traverse(visitor);
6060- }
6161- }
6262-6357 /** Sets the target type of the operator. */
6458 type(type: Type): this {
6559 this._type = type;
6666- if (this._type instanceof TsDsl) this._type.setParent(this);
6760 return this;
6861 }
6962
+12-14
packages/openapi-ts/src/ts-dsl/type/or.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
22-import { Symbol } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
33import ts from 'typescript';
4455-import { TsDsl, TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
6677type Type = Symbol | string | ts.TypeNode | TypeTsDsl;
88···1616 this.types(...nodes);
1717 }
18181919- override traverse(visitor: (node: SyntaxNode) => void): void {
2020- super.traverse(visitor);
2121- for (const node of this._types) {
2222- if (node instanceof TsDsl) {
2323- node.traverse(visitor);
1919+ override analyze(ctx: AnalysisContext): void {
2020+ super.analyze(ctx);
2121+ for (const t of this._types) {
2222+ if (isSymbol(t)) {
2323+ ctx.addDependency(t);
2424+ } else if (isTsDsl(t)) {
2525+ t.analyze(ctx);
2426 }
2527 }
2628 }
27292830 types(...nodes: Array<Type>): this {
2929- for (const node of nodes) {
3030- if (node instanceof TsDsl) node.setParent(this);
3131- this._types.push(node);
3232- }
3131+ this._types.push(...nodes);
3332 return this;
3433 }
3534···3736 const flat: Array<ts.TypeNode> = [];
38373938 for (const node of this._types) {
4040- const value = node instanceof Symbol ? node.finalName : node;
4141- const type = this.$type(value);
3939+ const type = this.$type(node);
4240 if (ts.isUnionTypeNode(type)) {
4341 flat.push(...type.types);
4442 } else {
+27-20
packages/openapi-ts/src/ts-dsl/type/param.ts
···11-import type { Symbol, SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
66+import { isTsDsl, TypeTsDsl } from '../base';
77+88+export type TypeParamName = Symbol | string;
99+export type TypeParamExpr = Symbol | string | boolean | MaybeTsDsl<TypeTsDsl>;
610711const Mixed = TypeTsDsl<ts.TypeParameterDeclaration>;
812913export class TypeParamTsDsl extends Mixed {
1010- protected name?: Symbol | string;
1111- protected constraint?: string | MaybeTsDsl<TypeTsDsl> | boolean;
1212- protected defaultValue?: string | MaybeTsDsl<TypeTsDsl> | boolean;
1414+ protected name?: TypeParamName;
1515+ protected constraint?: TypeParamExpr;
1616+ protected defaultValue?: TypeParamExpr;
13171414- constructor(name?: Symbol | string, fn?: (name: TypeParamTsDsl) => void) {
1818+ constructor(name?: TypeParamName, fn?: (name: TypeParamTsDsl) => void) {
1519 super();
1620 this.name = name;
1717- if (name && typeof name !== 'string') {
1818- this.getRootSymbol().addDependency(name);
1919- }
2021 fn?.(this);
2122 }
22232323- override collectSymbols(out: Set<Symbol>): void {
2424- console.log(out);
2424+ override analyze(ctx: AnalysisContext): void {
2525+ super.analyze(ctx);
2626+ if (isSymbol(this.name)) ctx.addDependency(this.name);
2727+ if (isSymbol(this.constraint)) {
2828+ ctx.addDependency(this.constraint);
2929+ } else if (isTsDsl(this.constraint)) {
3030+ this.constraint.analyze(ctx);
3131+ }
3232+ if (isSymbol(this.defaultValue)) {
3333+ ctx.addDependency(this.defaultValue);
3434+ } else if (isTsDsl(this.defaultValue)) {
3535+ this.defaultValue.analyze(ctx);
3636+ }
2537 }
26382727- default(value: string | MaybeTsDsl<TypeTsDsl> | boolean): this {
3939+ default(value: TypeParamExpr): this {
2840 this.defaultValue = value;
2941 return this;
3042 }
31433232- extends(constraint: string | MaybeTsDsl<TypeTsDsl> | boolean): this {
4444+ extends(constraint: TypeParamExpr): this {
3345 this.constraint = constraint;
3446 return this;
3535- }
3636-3737- override traverse(visitor: (node: SyntaxNode) => void): void {
3838- super.traverse(visitor);
3947 }
40484149 protected override _render() {
4250 if (!this.name) throw new Error('Missing type name');
4343- const name =
4444- typeof this.name === 'string' ? this.name : this.name.finalName;
4551 return ts.factory.createTypeParameterDeclaration(
4652 undefined,
4747- this.$maybeId(name),
5353+ // @ts-expect-error need to improve types
5454+ this.$node(this.name),
4855 this.$type(this.constraint),
4956 this.$type(this.defaultValue),
5057 );
+17-8
packages/openapi-ts/src/ts-dsl/type/prop.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext, Symbol } from '@hey-api/codegen-core';
22+import { isSymbol } from '@hey-api/codegen-core';
23import ts from 'typescript';
3445import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
66+import { isTsDsl, TypeTsDsl } from '../base';
67import { DocMixin } from '../mixins/doc';
78import { ReadonlyMixin } from '../mixins/modifiers';
89import { OptionalMixin } from '../mixins/optional';
910import { TokenTsDsl } from '../token';
1011import { safePropName } from '../utils/prop';
11121313+export type TypePropName = string;
1414+export type TypePropType = Symbol | string | MaybeTsDsl<ts.TypeNode>;
1515+1216const Mixed = DocMixin(OptionalMixin(ReadonlyMixin(TypeTsDsl<ts.TypeElement>)));
13171418export class TypePropTsDsl extends Mixed {
1515- protected name: string;
1616- protected _type?: string | MaybeTsDsl<ts.TypeNode>;
1919+ protected name: TypePropName;
2020+ protected _type?: TypePropType;
17211818- constructor(name: string, fn: (p: TypePropTsDsl) => void) {
2222+ constructor(name: TypePropName, fn: (p: TypePropTsDsl) => void) {
1923 super();
2024 this.name = name;
2125 fn(this);
2226 }
23272424- override traverse(visitor: (node: SyntaxNode) => void): void {
2525- super.traverse(visitor);
2828+ override analyze(ctx: AnalysisContext): void {
2929+ super.analyze(ctx);
3030+ if (isSymbol(this._type)) {
3131+ ctx.addDependency(this._type);
3232+ } else if (isTsDsl(this._type)) {
3333+ this._type.analyze(ctx);
3434+ }
2635 }
27362837 /** Sets the property type. */
2929- type(type: string | MaybeTsDsl<ts.TypeNode>): this {
3838+ type(type: TypePropType): this {
3039 this._type = type;
3140 return this;
3241 }
+5-4
packages/openapi-ts/src/ts-dsl/type/query.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
66import {
77 registerLazyAccessTypeQueryFactory,
88 TypeExprMixin,
···1818 this._expr = expr;
1919 }
20202121- override traverse(visitor: (node: SyntaxNode) => void): void {
2222- super.traverse(visitor);
2121+ override analyze(ctx: AnalysisContext): void {
2222+ super.analyze(ctx);
2323+ if (isTsDsl(this._expr)) this._expr.analyze(ctx);
2324 }
24252526 protected override _render() {
+9-6
packages/openapi-ts/src/ts-dsl/type/template.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344import type { MaybeTsDsl } from '../base';
55-import { TypeTsDsl } from '../base';
55+import { isTsDsl, TypeTsDsl } from '../base';
6677const Mixed = TypeTsDsl<ts.TemplateLiteralTypeNode>;
88···1414 if (value !== undefined) this.add(value);
1515 }
16161717+ override analyze(ctx: AnalysisContext): void {
1818+ super.analyze(ctx);
1919+ for (const part of this.parts) {
2020+ if (isTsDsl(part)) part.analyze(ctx);
2121+ }
2222+ }
2323+1724 /** Adds a raw string segment or embedded type expression. */
1825 add(part: string | MaybeTsDsl<ts.TypeNode>): this {
1926 this.parts.push(part);
2027 return this;
2121- }
2222-2323- override traverse(visitor: (node: SyntaxNode) => void): void {
2424- super.traverse(visitor);
2528 }
26292730 protected override _render() {
+9-6
packages/openapi-ts/src/ts-dsl/type/tuple.ts
···11-import type { SyntaxNode } from '@hey-api/codegen-core';
11+import type { AnalysisContext } from '@hey-api/codegen-core';
22import ts from 'typescript';
3344-import { TypeTsDsl } from '../base';
44+import { isTsDsl, TypeTsDsl } from '../base';
5566const Mixed = TypeTsDsl<ts.TupleTypeNode>;
77···1313 this.elements(...nodes);
1414 }
15151616+ override analyze(ctx: AnalysisContext): void {
1717+ super.analyze(ctx);
1818+ for (const t of this._elements) {
1919+ if (isTsDsl(t)) t.analyze(ctx);
2020+ }
2121+ }
2222+1623 elements(...types: Array<string | ts.TypeNode | TypeTsDsl>): this {
1724 this._elements.push(...types);
1825 return this;
1919- }
2020-2121- override traverse(visitor: (node: SyntaxNode) => void): void {
2222- super.traverse(visitor);
2326 }
24272528 protected override _render() {
+264-264
specs/3.1.x/openai.yaml
···41134113 }
41144114 description: >
41154115 **Starting a new project?** We recommend trying
41164116- [Responses](https://platform.openai.com/docs/api-reference/responses)
41164116+ [Responses](https://platform.openai.com/docs/api-reference/responses)
4117411741184118 to take advantage of the latest OpenAI platform features. Compare
41194119···4136413641374137 response, particularly for newer reasoning models. Parameters that are only
4138413841394139- supported for reasoning models are noted below. For the current state of
41394139+ supported for reasoning models are noted below. For the current state of
4140414041414141- unsupported parameters in reasoning models,
41414141+ unsupported parameters in reasoning models,
4142414241434143 [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning).
41444144 /chat/completions/{completion_id}:
···1456614566 ],
1456714567 }
1456814568 description: |
1456914569- Deactivate certificates at the project level. You can atomically and
1456914569+ Deactivate certificates at the project level. You can atomically and
1457014570 idempotently deactivate up to 10 certificates at a time.
1457114571 /organization/projects/{project_id}/rate_limits:
1457214572 get:
···1659216592 "speed": 1.1,
1659316593 "tracing": "auto",
1659416594 "client_secret": {
1659516595- "value": "ek_abc123",
1659516595+ "value": "ek_abc123",
1659616596 "expires_at": 1234567890
1659716597 }
1659816598 }
···1673916739 }
1674016740 description: |
1674116741 Create an ephemeral API token for use in client-side applications with the
1674216742- Realtime API specifically for realtime transcriptions.
1674216742+ Realtime API specifically for realtime transcriptions.
1674316743 Can be configured with the same session parameters as the `transcription_session.update` client event.
16744167441674516745 It responds with a session object, plus a `client_secret` key which contains
···1888518885 puts(response)
1888618886 description: |
1888718887 Cancels a model response with the given ID. Only responses created with
1888818888- the `background` parameter set to `true` can be cancelled.
1888818888+ the `background` parameter set to `true` can be cancelled.
1888918889 [Learn more](https://platform.openai.com/docs/guides/background).
1889018890 /responses/{response_id}/input_items:
1889118891 get:
···2317023170 File object.
231712317123172231722317323173- For certain `purpose` values, the correct `mime_type` must be specified.
2317323173+ For certain `purpose` values, the correct `mime_type` must be specified.
23174231742317523175- Please refer to documentation for the
2317523175+ Please refer to documentation for the
23176231762317723177 [supported MIME types for your use
2317823178 case](https://platform.openai.com/docs/assistants/tools/file-search#supported-files).
···23433234332343423434 puts(upload)
2343523435 description: >
2343623436- Completes the [Upload](https://platform.openai.com/docs/api-reference/uploads/object).
2343623436+ Completes the [Upload](https://platform.openai.com/docs/api-reference/uploads/object).
234372343723438234382343923439 Within the returned Upload object, there is a nested
···2357523575 description: >
2357623576 Adds a [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an
2357723577 [Upload](https://platform.openai.com/docs/api-reference/uploads/object) object. A Part represents a
2357823578- chunk of bytes from the file you are trying to upload.
2357823578+ chunk of bytes from the file you are trying to upload.
235792357923580235802358123581 Each Part can be at most 64 MB, and you can add Parts until you hit the Upload maximum of 8 GB.
···2584925849 responses:
2585025850 '200':
2585125851 description: |
2585225852- Return a 200 status code to acknowledge receipt of the event. Non-200
2585225852+ Return a 200 status code to acknowledge receipt of the event. Non-200
2585325853 status codes will be retried.
2585425854 batch_completed:
2585525855 post:
···2586225862 responses:
2586325863 '200':
2586425864 description: |
2586525865- Return a 200 status code to acknowledge receipt of the event. Non-200
2586525865+ Return a 200 status code to acknowledge receipt of the event. Non-200
2586625866 status codes will be retried.
2586725867 batch_expired:
2586825868 post:
···2587525875 responses:
2587625876 '200':
2587725877 description: |
2587825878- Return a 200 status code to acknowledge receipt of the event. Non-200
2587825878+ Return a 200 status code to acknowledge receipt of the event. Non-200
2587925879 status codes will be retried.
2588025880 batch_failed:
2588125881 post:
···2588825888 responses:
2588925889 '200':
2589025890 description: |
2589125891- Return a 200 status code to acknowledge receipt of the event. Non-200
2589125891+ Return a 200 status code to acknowledge receipt of the event. Non-200
2589225892 status codes will be retried.
2589325893 eval_run_canceled:
2589425894 post:
···2590125901 responses:
2590225902 '200':
2590325903 description: |
2590425904- Return a 200 status code to acknowledge receipt of the event. Non-200
2590425904+ Return a 200 status code to acknowledge receipt of the event. Non-200
2590525905 status codes will be retried.
2590625906 eval_run_failed:
2590725907 post:
···2591425914 responses:
2591525915 '200':
2591625916 description: |
2591725917- Return a 200 status code to acknowledge receipt of the event. Non-200
2591725917+ Return a 200 status code to acknowledge receipt of the event. Non-200
2591825918 status codes will be retried.
2591925919 eval_run_succeeded:
2592025920 post:
···2592725927 responses:
2592825928 '200':
2592925929 description: |
2593025930- Return a 200 status code to acknowledge receipt of the event. Non-200
2593025930+ Return a 200 status code to acknowledge receipt of the event. Non-200
2593125931 status codes will be retried.
2593225932 fine_tuning_job_cancelled:
2593325933 post:
···2594025940 responses:
2594125941 '200':
2594225942 description: |
2594325943- Return a 200 status code to acknowledge receipt of the event. Non-200
2594325943+ Return a 200 status code to acknowledge receipt of the event. Non-200
2594425944 status codes will be retried.
2594525945 fine_tuning_job_failed:
2594625946 post:
···2595325953 responses:
2595425954 '200':
2595525955 description: |
2595625956- Return a 200 status code to acknowledge receipt of the event. Non-200
2595625956+ Return a 200 status code to acknowledge receipt of the event. Non-200
2595725957 status codes will be retried.
2595825958 fine_tuning_job_succeeded:
2595925959 post:
···2596625966 responses:
2596725967 '200':
2596825968 description: |
2596925969- Return a 200 status code to acknowledge receipt of the event. Non-200
2596925969+ Return a 200 status code to acknowledge receipt of the event. Non-200
2597025970 status codes will be retried.
2597125971 response_cancelled:
2597225972 post:
···2597925979 responses:
2598025980 '200':
2598125981 description: |
2598225982- Return a 200 status code to acknowledge receipt of the event. Non-200
2598225982+ Return a 200 status code to acknowledge receipt of the event. Non-200
2598325983 status codes will be retried.
2598425984 response_completed:
2598525985 post:
···2599225992 responses:
2599325993 '200':
2599425994 description: |
2599525995- Return a 200 status code to acknowledge receipt of the event. Non-200
2599525995+ Return a 200 status code to acknowledge receipt of the event. Non-200
2599625996 status codes will be retried.
2599725997 response_failed:
2599825998 post:
···2600526005 responses:
2600626006 '200':
2600726007 description: |
2600826008- Return a 200 status code to acknowledge receipt of the event. Non-200
2600826008+ Return a 200 status code to acknowledge receipt of the event. Non-200
2600926009 status codes will be retried.
2601026010 response_incomplete:
2601126011 post:
···2601826018 responses:
2601926019 '200':
2602026020 description: |
2602126021- Return a 200 status code to acknowledge receipt of the event. Non-200
2602126021+ Return a 200 status code to acknowledge receipt of the event. Non-200
2602226022 status codes will be retried.
2602326023components:
2602426024 schemas:
···2759227592 nullable: true
2759327593 description: >
2759427594 If a content parts array was provided, this is an array of `text` and `image_url`
2759527595- parts.
2759527595+ parts.
27596275962759727597 Otherwise, null.
2759827598 items:
···2782227822 type: object
2782327823 nullable: true
2782427824 description: |
2782527825- Data about a previous audio response from the model.
2782527825+ Data about a previous audio response from the model.
2782627826 [Learn more](https://platform.openai.com/docs/guides/audio).
2782727827 required:
2782827828 - id
···2798627986 filename:
2798727987 type: string
2798827988 description: |
2798927989- The name of the file, used when passing the file to the model as a
2798927989+ The name of the file, used when passing the file to the model as a
2799027990 string.
2799127991 file_data:
2799227992 type: string
2799327993 description: |
2799427994- The base64 encoded file data, used when passing the file to the model
2799427994+ The base64 encoded file data, used when passing the file to the model
2799527995 as a string.
2799627996 file_id:
2799727997 type: string
···2852828528 - click
2852928529 default: click
2853028530 description: |
2853128531- Specifies the event type. For a click action, this property is
2853128531+ Specifies the event type. For a click action, this property is
2853228532 always set to `click`.
2853328533 x-stainless-const: true
2853428534 button:
···2874028740 propertyName: type
2874128741 nullable: true
2874228742 description: |
2874328743- The outputs generated by the code interpreter, such as logs or images.
2874328743+ The outputs generated by the code interpreter, such as logs or images.
2874428744 Can be null if no outputs are available.
2874528745 required:
2874628746 - type
···2891528915 - computer_screenshot
2891628916 default: computer_screenshot
2891728917 description: |
2891828918- Specifies the event type. For a computer screenshot, this property is
2891828918+ Specifies the event type. For a computer screenshot, this property is
2891928919 always set to `computer_screenshot`.
2892028920 x-stainless-const: true
2892128921 image_url:
···2893028930 type: object
2893128931 title: Computer tool call
2893228932 description: |
2893328933- A tool call to a computer use tool. See the
2893328933+ A tool call to a computer use tool. See the
2893428934 [computer use guide](https://platform.openai.com/docs/guides/tools-computer-use) for more information.
2893528935 properties:
2893628936 type:
···2899528995 acknowledged_safety_checks:
2899628996 type: array
2899728997 description: |
2899828998- The safety checks reported by the API that have been acknowledged by the
2899828998+ The safety checks reported by the API that have been acknowledged by the
2899928999 developer.
2900029000 items:
2900129001 $ref: '#/components/schemas/ComputerToolCallSafetyCheck'
···2991629916 type: object
2991729917 description: |
2991829918 Represents a streamed chunk of a chat completion response returned
2991929919- by the model, based on the provided input.
2991929919+ by the model, based on the provided input.
2992029920 [Learn more](https://platform.openai.com/docs/guides/streaming-responses).
2992129921 properties:
2992229922 id:
···3135431354 description: |
3135531355 The image(s) to edit. Must be a supported image file or an array of images.
31356313563135731357- For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less
3135731357+ For `gpt-image-1`, each image should be a `png`, `webp`, or `jpg` file less
3135831358 than 50MB. You can provide up to 16 images.
31359313593136031360- For `dall-e-2`, you can only provide one image, and it should be a square
3136031360+ For `dall-e-2`, you can only provide one image, and it should be a square
3136131361 `png` file less than 4MB.
3136231362 x-oaiMeta:
3136331363 exampleFilePath: otter.png
···3138631386 example: transparent
3138731387 nullable: true
3138831388 description: |
3138931389- Allows to set transparency for the background of the generated image(s).
3139031390- This parameter is only supported for `gpt-image-1`. Must be one of
3139131391- `transparent`, `opaque` or `auto` (default value). When `auto` is used, the
3138931389+ Allows to set transparency for the background of the generated image(s).
3139031390+ This parameter is only supported for `gpt-image-1`. Must be one of
3139131391+ `transparent`, `opaque` or `auto` (default value). When `auto` is used, the
3139231392 model will automatically determine the best background for the image.
31393313933139431394- If `transparent`, the output format needs to support transparency, so it
3139431394+ If `transparent`, the output format needs to support transparency, so it
3139531395 should be set to either `png` (default value) or `webp`.
3139631396 model:
3139731397 anyOf:
···3146131461 example: 100
3146231462 nullable: true
3146331463 description: |
3146431464- The compression level (0-100%) for the generated images. This parameter
3146531465- is only supported for `gpt-image-1` with the `webp` or `jpeg` output
3146431464+ The compression level (0-100%) for the generated images. This parameter
3146531465+ is only supported for `gpt-image-1` with the `webp` or `jpeg` output
3146631466 formats, and defaults to 100.
3146731467 user:
3146831468 type: string
···3147831478 example: false
3147931479 nullable: true
3148031480 description: >
3148131481- Edit the image in streaming mode. Defaults to `false`. See the
3148131481+ Edit the image in streaming mode. Defaults to `false`. See the
31482314823148331483 [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more
3148431484 information.
···3154731547 example: medium
3154831548 nullable: true
3154931549 description: |
3155031550- The quality of the image that will be generated.
3155031550+ The quality of the image that will be generated.
31551315513155231552 - `auto` (default value) will automatically select the best quality for the given model.
3155331553 - `high`, `medium` and `low` are supported for `gpt-image-1`.
···3159131591 example: false
3159231592 nullable: true
3159331593 description: >
3159431594- Generate the image in streaming mode. Defaults to `false`. See the
3159431594+ Generate the image in streaming mode. Defaults to `false`. See the
31595315953159631596 [Image generation guide](https://platform.openai.com/docs/guides/image-generation) for more
3159731597 information.
···3163831638 example: transparent
3163931639 nullable: true
3164031640 description: |
3164131641- Allows to set transparency for the background of the generated image(s).
3164231642- This parameter is only supported for `gpt-image-1`. Must be one of
3164331643- `transparent`, `opaque` or `auto` (default value). When `auto` is used, the
3164131641+ Allows to set transparency for the background of the generated image(s).
3164231642+ This parameter is only supported for `gpt-image-1`. Must be one of
3164331643+ `transparent`, `opaque` or `auto` (default value). When `auto` is used, the
3164431644 model will automatically determine the best background for the image.
31645316453164631646- If `transparent`, the output format needs to support transparency, so it
3164631646+ If `transparent`, the output format needs to support transparency, so it
3164731647 should be set to either `png` (default value) or `webp`.
3164831648 style:
3164931649 type: string
···3266432664 CreateThreadRequest:
3266532665 type: object
3266632666 description: |
3266732667- Options to create a new thread. If no thread is provided when running a
3266732667+ Options to create a new thread. If no thread is provided when running a
3266832668 request, an empty thread will be created.
3266932669 additionalProperties: false
3267032670 properties:
···3285332853 If set to true, the model response data will be streamed to the client
32854328543285532855 as it is generated using [server-sent
3285632856- events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).
3285632856+ events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format).
32857328573285832858 See the [Streaming section of the Speech-to-Text
3285932859 guide](https://platform.openai.com/docs/guides/speech-to-text?lang=curl#streaming-transcriptions)
···3288332883 - segment
3288432884 include:
3288532885 description: |
3288632886- Additional information to include in the transcription response.
3288732887- `logprobs` will return the log probabilities of the tokens in the
3288832888- response to understand the model's confidence in the transcription.
3288932889- `logprobs` only works with response_format set to `json` and only with
3288632886+ Additional information to include in the transcription response.
3288732887+ `logprobs` will return the log probabilities of the tokens in the
3288832888+ response to understand the model's confidence in the transcription.
3288932889+ `logprobs` only works with response_format set to `json` and only with
3289032890 the models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe`.
3289132891 type: array
3289232892 items:
···3357333573 - double_click
3357433574 default: double_click
3357533575 description: |
3357633576- Specifies the event type. For a double click action, this property is
3357633576+ Specifies the event type. For a double click action, this property is
3357733577 always set to `double_click`.
3357833578 x-stainless-const: true
3357933579 x:
···3360033600 - drag
3360133601 default: drag
3360233602 description: |
3360333603- Specifies the event type. For a drag action, this property is
3360333603+ Specifies the event type. For a drag action, this property is
3360433604 always set to `drag`.
3360533605 x-stainless-const: true
3360633606 path:
···3518935189 type: object
3519035190 title: File search tool call
3519135191 description: |
3519235192- The results of a file search tool call. See the
3519235192+ The results of a file search tool call. See the
3519335193 [file search guide](https://platform.openai.com/docs/guides/tools-file-search) for more information.
3519435194 properties:
3519535195 id:
···3520635206 status:
3520735207 type: string
3520835208 description: |
3520935209- The status of the file search tool call. One of `in_progress`,
3520935209+ The status of the file search tool call. One of `in_progress`,
3521035210 `searching`, `incomplete` or `failed`,
3521135211 enum:
3521235212 - in_progress
···3614636146 description: >-
3614736147 The parameters the functions accepts, described as a JSON Schema object. See the
3614836148 [guide](https://platform.openai.com/docs/guides/function-calling) for examples, and the [JSON Schema
3614936149- reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
3614936149+ reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
361503615036151361513615236152 Omitting `parameters` defines a function with an empty parameter list.
···3615536155 type: object
3615636156 title: Function tool call
3615736157 description: >
3615836158- A tool call to run a function. See the
3615836158+ A tool call to run a function. See the
36159361593616036160 [function calling guide](https://platform.openai.com/docs/guides/function-calling) for more
3616136161 information.
···3657836578 - rouge_5
3657936579 - rouge_l
3658036580 description: |
3658136581- The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`,
3658236582- `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`,
3658136581+ The evaluation metric to use. One of `cosine`, `fuzzy_match`, `bleu`,
3658236582+ `gleu`, `meteor`, `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`,
3658336583 or `rouge_l`.
3658436584 required:
3658536585 - type
···3699136991 - high
3699236992 - auto
3699336993 description: |
3699436994- The quality of the generated image. One of `low`, `medium`, `high`,
3699436994+ The quality of the generated image. One of `low`, `medium`, `high`,
3699536995 or `auto`. Default: `auto`.
3699636996 default: auto
3699736997 size:
···3700237002 - 1536x1024
3700337003 - auto
3700437004 description: |
3700537005- The size of the generated image. One of `1024x1024`, `1024x1536`,
3700537005+ The size of the generated image. One of `1024x1024`, `1024x1536`,
3700637006 `1536x1024`, or `auto`. Default: `auto`.
3700737007 default: auto
3700837008 output_format:
···3701237012 - webp
3701337013 - jpeg
3701437014 description: |
3701537015- The output format of the generated image. One of `png`, `webp`, or
3701537015+ The output format of the generated image. One of `png`, `webp`, or
3701637016 `jpeg`. Default: `png`.
3701737017 default: png
3701837018 output_compression:
···3703737037 - opaque
3703837038 - auto
3703937039 description: |
3704037040- Background type for the generated image. One of `transparent`,
3704037040+ Background type for the generated image. One of `transparent`,
3704137041 `opaque`, or `auto`. Default: `auto`.
3704237042 default: auto
3704337043 input_fidelity:
···3704537045 input_image_mask:
3704637046 type: object
3704737047 description: |
3704837048- Optional mask for inpainting. Contains `image_url`
3704837048+ Optional mask for inpainting. Contains `image_url`
3704937049 (string, optional) and `file_id` (string, optional).
3705037050 properties:
3705137051 image_url:
···3728437284 - type: object
3728537285 title: Item
3728637286 description: |
3728737287- An item representing part of the context for the response to be
3728737287+ An item representing part of the context for the response to be
3728837288 generated by the model. Can contain text, images, and audio inputs,
3728937289 as well as previous assistant responses and tool call outputs.
3729037290 $ref: '#/components/schemas/Item'
···3733037330 type: array
3733137331 title: Input item content list
3733237332 description: |
3733337333- A list of one or many input items to the model, containing different content
3733337333+ A list of one or many input items to the model, containing different content
3733437334 types.
3733537335 items:
3733637336 $ref: '#/components/schemas/InputContent'
···3756337563 - keypress
3756437564 default: keypress
3756537565 description: |
3756637566- Specifies the event type. For a keypress action, this property is
3756637566+ Specifies the event type. For a keypress action, this property is
3756737567 always set to `keypress`.
3756837568 x-stainless-const: true
3756937569 keys:
···3830738307 type: object
3830838308 title: MCP tool
3830938309 description: |
3831038310- Give the model access to additional tools via remote Model Context Protocol
3831038310+ Give the model access to additional tools via remote Model Context Protocol
3831138311 (MCP) servers. [Learn more about MCP](https://platform.openai.com/docs/guides/tools-remote-mcp).
3831238312 properties:
3831338313 type:
···3839038390 - type: string
3839138391 title: MCP tool approval setting
3839238392 description: |
3839338393- Specify a single approval policy for all tools. One of `always` or
3839438394- `never`. When set to `always`, all tools will require approval. When
3839338393+ Specify a single approval policy for all tools. One of `always` or
3839438394+ `never`. When set to `always`, all tools will require approval. When
3839538395 set to `never`, all tools will not require approval.
3839638396 enum:
3839738397 - always
···3911639116 description: |
3911739117 Set of 16 key-value pairs that can be attached to an object. This can be
3911839118 useful for storing additional information about the object in a structured
3911939119- format, and querying for objects via API or the dashboard.
3911939119+ format, and querying for objects via API or the dashboard.
39120391203912139121 Keys are strings with a maximum length of 64 characters. Values are strings
3912239122 with a maximum length of 512 characters.
···3923039230 This field is being replaced by `safety_identifier` and `prompt_cache_key`. Use `prompt_cache_key`
3923139231 instead to maintain caching optimizations.
39232392323923339233- A stable identifier for your end-users.
3923339233+ A stable identifier for your end-users.
39234392343923539235 Used to boost cache hit rates by better bucketing similar requests and to help OpenAI detect and
3923639236 prevent abuse. [Learn
···3924039240 example: safety-identifier-1234
3924139241 description: >
3924239242 A stable identifier used to help detect users of your application that may be violating OpenAI's
3924339243- usage policies.
3924339243+ usage policies.
39244392443924539245 The IDs should be a string that uniquely identifies each user. We recommend hashing their username
3924639246 or email address, in order to avoid sending us any identifying information. [Learn
···3942739427 - move
3942839428 default: move
3942939429 description: |
3943039430- Specifies the event type. For a move action, this property is
3943039430+ Specifies the event type. For a move action, this property is
3943139431 always set to `move`.
3943239432 x-stainless-const: true
3943339433 x:
···3964639646 streaming responses that return partial images. Value must be between 0 and 3.
3964739647 When set to 0, the response will be a single image sent in one streaming event.
39648396483964939649- Note that the final image may be sent before the full number of partial images
3964939649+ Note that the final image may be sent before the full number of partial images
3965039650 are generated if the full image is generated more quickly.
3965139651 PredictionContent:
3965239652 type: object
···4023040230 type: object
4023140231 nullable: true
4023240232 description: |
4023340233- Reference to a prompt template and its variables.
4023340233+ Reference to a prompt template and its variables.
4023440234 [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
4023540235 required:
4023640236 - id
···4026540265 RealtimeClientEventConversationItemCreate:
4026640266 type: object
4026740267 description: |
4026840268- Add a new Item to the Conversation's context, including messages, function
4026940269- calls, and function call responses. This event can be used both to populate a
4027040270- "history" of the conversation and to add new items mid-stream, but has the
4026840268+ Add a new Item to the Conversation's context, including messages, function
4026940269+ calls, and function call responses. This event can be used both to populate a
4027040270+ "history" of the conversation and to add new items mid-stream, but has the
4027140271 current limitation that it cannot populate assistant audio messages.
40272402724027340273- If successful, the server will respond with a `conversation.item.created`
4027340273+ If successful, the server will respond with a `conversation.item.created`
4027440274 event, otherwise an `error` event will be sent.
4027540275 properties:
4027640276 event_id:
···4028340283 previous_item_id:
4028440284 type: string
4028540285 description: |
4028640286- The ID of the preceding item after which the new item will be inserted.
4028640286+ The ID of the preceding item after which the new item will be inserted.
4028740287 If not set, the new item will be appended to the end of the conversation.
4028840288 If set to `root`, the new item will be added to the beginning of the conversation.
4028940289 If set to an existing ID, it allows an item to be inserted mid-conversation. If the
···4031640316 RealtimeClientEventConversationItemDelete:
4031740317 type: object
4031840318 description: |
4031940319- Send this event when you want to remove any item from the conversation
4032040320- history. The server will respond with a `conversation.item.deleted` event,
4032140321- unless the item does not exist in the conversation history, in which case the
4031940319+ Send this event when you want to remove any item from the conversation
4032040320+ history. The server will respond with a `conversation.item.deleted` event,
4032140321+ unless the item does not exist in the conversation history, in which case the
4032240322 server will respond with an error.
4032340323 properties:
4032440324 event_id:
···4035040350 conversation history. This is useful, for example, to inspect user audio after noise cancellation and
4035140351 VAD.
40352403524035340353- The server will respond with a `conversation.item.retrieved` event,
4035340353+ The server will respond with a `conversation.item.retrieved` event,
40354403544035540355- unless the item does not exist in the conversation history, in which case the
4035540355+ unless the item does not exist in the conversation history, in which case the
40356403564035740357 server will respond with an error.
4035840358 properties:
···4038140381 RealtimeClientEventConversationItemTruncate:
4038240382 type: object
4038340383 description: |
4038440384- Send this event to truncate a previous assistant message’s audio. The server
4038540385- will produce audio faster than realtime, so this event is useful when the user
4038640386- interrupts to truncate audio that has already been sent to the client but not
4038740387- yet played. This will synchronize the server's understanding of the audio with
4038440384+ Send this event to truncate a previous assistant message’s audio. The server
4038540385+ will produce audio faster than realtime, so this event is useful when the user
4038640386+ interrupts to truncate audio that has already been sent to the client but not
4038740387+ yet played. This will synchronize the server's understanding of the audio with
4038840388 the client's playback.
40389403894039040390- Truncating audio will delete the server-side text transcript to ensure there
4039040390+ Truncating audio will delete the server-side text transcript to ensure there
4039140391 is not text in the context that hasn't been heard by the user.
40392403924039340393- If successful, the server will respond with a `conversation.item.truncated`
4039340393+ If successful, the server will respond with a `conversation.item.truncated`
4039440394 event.
4039540395 properties:
4039640396 event_id:
···4040340403 item_id:
4040440404 type: string
4040540405 description: |
4040640406- The ID of the assistant message item to truncate. Only assistant message
4040640406+ The ID of the assistant message item to truncate. Only assistant message
4040740407 items can be truncated.
4040840408 content_index:
4040940409 type: integer
···4041140411 audio_end_ms:
4041240412 type: integer
4041340413 description: |
4041440414- Inclusive duration up to which audio is truncated, in milliseconds. If
4041540415- the audio_end_ms is greater than the actual audio duration, the server
4041440414+ Inclusive duration up to which audio is truncated, in milliseconds. If
4041540415+ the audio_end_ms is greater than the actual audio duration, the server
4041640416 will respond with an error.
4041740417 required:
4041840418 - type
···4043340433 RealtimeClientEventInputAudioBufferAppend:
4043440434 type: object
4043540435 description: |
4043640436- Send this event to append audio bytes to the input audio buffer. The audio
4043740437- buffer is temporary storage you can write to and later commit. In Server VAD
4043840438- mode, the audio buffer is used to detect speech and the server will decide
4043640436+ Send this event to append audio bytes to the input audio buffer. The audio
4043740437+ buffer is temporary storage you can write to and later commit. In Server VAD
4043840438+ mode, the audio buffer is used to detect speech and the server will decide
4043940439 when to commit. When Server VAD is disabled, you must commit the audio buffer
4044040440 manually.
40441404414044240442- The client may choose how much audio to place in each event up to a maximum
4044340443- of 15 MiB, for example streaming smaller chunks from the client may allow the
4044440444- VAD to be more responsive. Unlike made other client events, the server will
4044240442+ The client may choose how much audio to place in each event up to a maximum
4044340443+ of 15 MiB, for example streaming smaller chunks from the client may allow the
4044440444+ VAD to be more responsive. Unlike made other client events, the server will
4044540445 not send a confirmation response to this event.
4044640446 properties:
4044740447 event_id:
···4045440454 audio:
4045540455 type: string
4045640456 description: |
4045740457- Base64-encoded audio bytes. This must be in the format specified by the
4045740457+ Base64-encoded audio bytes. This must be in the format specified by the
4045840458 `input_audio_format` field in the session configuration.
4045940459 required:
4046040460 - type
···4047140471 RealtimeClientEventInputAudioBufferClear:
4047240472 type: object
4047340473 description: |
4047440474- Send this event to clear the audio bytes in the buffer. The server will
4047440474+ Send this event to clear the audio bytes in the buffer. The server will
4047540475 respond with an `input_audio_buffer.cleared` event.
4047640476 properties:
4047740477 event_id:
···4049440494 RealtimeClientEventInputAudioBufferCommit:
4049540495 type: object
4049640496 description: |
4049740497- Send this event to commit the user input audio buffer, which will create a
4049840498- new user message item in the conversation. This event will produce an error
4049940499- if the input audio buffer is empty. When in Server VAD mode, the client does
4050040500- not need to send this event, the server will commit the audio buffer
4049740497+ Send this event to commit the user input audio buffer, which will create a
4049840498+ new user message item in the conversation. This event will produce an error
4049940499+ if the input audio buffer is empty. When in Server VAD mode, the client does
4050040500+ not need to send this event, the server will commit the audio buffer
4050140501 automatically.
40502405024050340503- Committing the input audio buffer will trigger input audio transcription
4050440504- (if enabled in session configuration), but it will not create a response
4050540505- from the model. The server will respond with an `input_audio_buffer.committed`
4050340503+ Committing the input audio buffer will trigger input audio transcription
4050440504+ (if enabled in session configuration), but it will not create a response
4050540505+ from the model. The server will respond with an `input_audio_buffer.committed`
4050640506 event.
4050740507 properties:
4050840508 event_id:
···4052740527 description: >
4052840528 **WebRTC Only:** Emit to cut off the current audio response. This will trigger the server to
40529405294053040530- stop generating audio and emit a `output_audio_buffer.cleared` event. This
4053040530+ stop generating audio and emit a `output_audio_buffer.cleared` event. This
40531405314053240532- event should be preceded by a `response.cancel` client event to stop the
4053240532+ event should be preceded by a `response.cancel` client event to stop the
40533405334053440534 generation of the current response.
4053540535···4055640556 RealtimeClientEventResponseCancel:
4055740557 type: object
4055840558 description: |
4055940559- Send this event to cancel an in-progress response. The server will respond
4056040560- with a `response.done` event with a status of `response.status=cancelled`. If
4055940559+ Send this event to cancel an in-progress response. The server will respond
4056040560+ with a `response.done` event with a status of `response.status=cancelled`. If
4056140561 there is no response to cancel, the server will respond with an error.
4056240562 properties:
4056340563 event_id:
···4057040570 response_id:
4057140571 type: string
4057240572 description: |
4057340573- A specific response ID to cancel - if not provided, will cancel an
4057340573+ A specific response ID to cancel - if not provided, will cancel an
4057440574 in-progress response in the default conversation.
4057540575 required:
4057640576 - type
···4058540585 RealtimeClientEventResponseCreate:
4058640586 type: object
4058740587 description: |
4058840588- This event instructs the server to create a Response, which means triggering
4058940589- model inference. When in Server VAD mode, the server will create Responses
4058840588+ This event instructs the server to create a Response, which means triggering
4058940589+ model inference. When in Server VAD mode, the server will create Responses
4059040590 automatically.
40591405914059240592- A Response will include at least one Item, and may have two, in which case
4059340593- the second will be a function call. These Items will be appended to the
4059240592+ A Response will include at least one Item, and may have two, in which case
4059340593+ the second will be a function call. These Items will be appended to the
4059440594 conversation history.
40595405954059640596- The server will respond with a `response.created` event, events for Items
4059740597- and content created, and finally a `response.done` event to indicate the
4059640596+ The server will respond with a `response.created` event, events for Items
4059740597+ and content created, and finally a `response.done` event to indicate the
4059840598 Response is complete.
40599405994060040600- The `response.create` event includes inference configuration like
4060140601- `instructions`, and `temperature`. These fields will override the Session's
4060040600+ The `response.create` event includes inference configuration like
4060140601+ `instructions`, and `temperature`. These fields will override the Session's
4060240602 configuration for this Response only.
4060340603 properties:
4060440604 event_id:
···4076640766 id:
4076740767 type: string
4076840768 description: |
4076940769- The unique ID of the item, this can be generated by the client to help
4077040770- manage server-side context, but is not required because the server will
4076940769+ The unique ID of the item, this can be generated by the client to help
4077040770+ manage server-side context, but is not required because the server will
4077140771 generate one if not provided.
4077240772 type:
4077340773 type: string
···4079140791 - incomplete
4079240792 - in_progress
4079340793 description: |
4079440794- The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect
4079540795- on the conversation, but are accepted for consistency with the
4079440794+ The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect
4079540795+ on the conversation, but are accepted for consistency with the
4079640796 `conversation.item.created` event.
4079740797 role:
4079840798 type: string
···4080140801 - assistant
4080240802 - system
4080340803 description: |
4080440804- The role of the message sender (`user`, `assistant`, `system`), only
4080440804+ The role of the message sender (`user`, `assistant`, `system`), only
4080540805 applicable for `message` items.
4080640806 content:
4080740807 type: array
4080840808 description: |
4080940809- The content of the message, applicable for `message` items.
4080940809+ The content of the message, applicable for `message` items.
4081040810 - Message items of role `system` support only `input_text` content
4081140811- - Message items of role `user` support `input_text` and `input_audio`
4081140811+ - Message items of role `user` support `input_text` and `input_audio`
4081240812 content
4081340813 - Message items of role `assistant` support `text` content.
4081440814 items:
···4081640816 call_id:
4081740817 type: string
4081840818 description: |
4081940819- The ID of the function call (for `function_call` and
4082040820- `function_call_output` items). If passed on a `function_call_output`
4082140821- item, the server will check that a `function_call` item with the same
4081940819+ The ID of the function call (for `function_call` and
4082040820+ `function_call_output` items). If passed on a `function_call_output`
4082140821+ item, the server will check that a `function_call` item with the same
4082240822 ID exists in the conversation history.
4082340823 name:
4082440824 type: string
···4086840868 - incomplete
4086940869 - in_progress
4087040870 description: |
4087140871- The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect
4087240872- on the conversation, but are accepted for consistency with the
4087140871+ The status of the item (`completed`, `incomplete`, `in_progress`). These have no effect
4087240872+ on the conversation, but are accepted for consistency with the
4087340873 `conversation.item.created` event.
4087440874 role:
4087540875 type: string
···4087840878 - assistant
4087940879 - system
4088040880 description: |
4088140881- The role of the message sender (`user`, `assistant`, `system`), only
4088140881+ The role of the message sender (`user`, `assistant`, `system`), only
4088240882 applicable for `message` items.
4088340883 content:
4088440884 type: array
4088540885 description: |
4088640886- The content of the message, applicable for `message` items.
4088640886+ The content of the message, applicable for `message` items.
4088740887 - Message items of role `system` support only `input_text` content
4088840888- - Message items of role `user` support `input_text` and `input_audio`
4088840888+ - Message items of role `user` support `input_text` and `input_audio`
4088940889 content
4089040890 - Message items of role `assistant` support `text` content.
4089140891 items:
···4092140921 call_id:
4092240922 type: string
4092340923 description: |
4092440924- The ID of the function call (for `function_call` and
4092540925- `function_call_output` items). If passed on a `function_call_output`
4092640926- item, the server will check that a `function_call` item with the same
4092440924+ The ID of the function call (for `function_call` and
4092540925+ `function_call_output` items). If passed on a `function_call_output`
4092640926+ item, the server will check that a `function_call` item with the same
4092740927 ID exists in the conversation history.
4092840928 name:
4092940929 type: string
···4095740957 - incomplete
4095840958 - in_progress
4095940959 description: |
4096040960- The final status of the response (`completed`, `cancelled`, `failed`, or
4096040960+ The final status of the response (`completed`, `cancelled`, `failed`, or
4096140961 `incomplete`, `in_progress`).
4096240962 status_details:
4096340963 type: object
···4097140971 - incomplete
4097240972 - failed
4097340973 description: |
4097440974- The type of error that caused the response to fail, corresponding
4097540975- with the `status` field (`completed`, `cancelled`, `incomplete`,
4097440974+ The type of error that caused the response to fail, corresponding
4097540975+ with the `status` field (`completed`, `cancelled`, `incomplete`,
4097640976 `failed`).
4097740977 reason:
4097840978 type: string
···4098240982 - max_output_tokens
4098340983 - content_filter
4098440984 description: |
4098540985- The reason the Response did not complete. For a `cancelled` Response,
4098640986- one of `turn_detected` (the server VAD detected a new start of speech)
4098740987- or `client_cancelled` (the client sent a cancel event). For an
4098840988- `incomplete` Response, one of `max_output_tokens` or `content_filter`
4098540985+ The reason the Response did not complete. For a `cancelled` Response,
4098640986+ one of `turn_detected` (the server VAD detected a new start of speech)
4098740987+ or `client_cancelled` (the client sent a cancel event). For an
4098840988+ `incomplete` Response, one of `max_output_tokens` or `content_filter`
4098940989 (the server-side safety filter activated and cut off the response).
4099040990 error:
4099140991 type: object
4099240992 description: |
4099340993- A description of the error that caused the response to fail,
4099340993+ A description of the error that caused the response to fail,
4099440994 populated when the `status` is `failed`.
4099540995 properties:
4099640996 type:
···4100941009 usage:
4101041010 type: object
4101141011 description: |
4101241012- Usage statistics for the Response, this will correspond to billing. A
4101341013- Realtime API session will maintain a conversation context and append new
4101441014- Items to the Conversation, thus output from previous turns (text and
4101241012+ Usage statistics for the Response, this will correspond to billing. A
4101341013+ Realtime API session will maintain a conversation context and append new
4101441014+ Items to the Conversation, thus output from previous turns (text and
4101541015 audio tokens) will become the input for later turns.
4101641016 properties:
4101741017 total_tokens:
4101841018 type: integer
4101941019 description: |
4102041020- The total number of tokens in the Response including input and output
4102041020+ The total number of tokens in the Response including input and output
4102141021 text and audio tokens.
4102241022 input_tokens:
4102341023 type: integer
4102441024 description: |
4102541025- The number of input tokens used in the Response, including text and
4102541025+ The number of input tokens used in the Response, including text and
4102641026 audio tokens.
4102741027 output_tokens:
4102841028 type: integer
4102941029 description: |
4103041030- The number of output tokens sent in the Response, including text and
4103041030+ The number of output tokens sent in the Response, including text and
4103141031 audio tokens.
4103241032 input_token_details:
4103341033 type: object
···4111841118 instructions:
4111941119 type: string
4112041120 description: |
4112141121- The default system instructions (i.e. system message) prepended to model
4112241122- calls. This field allows the client to guide the model on desired
4112341123- responses. The model can be instructed on response content and format,
4112441124- (e.g. "be extremely succinct", "act friendly", "here are examples of good
4112541125- responses") and on audio behavior (e.g. "talk quickly", "inject emotion
4112641126- into your voice", "laugh frequently"). The instructions are not guaranteed
4112741127- to be followed by the model, but they provide guidance to the model on the
4112141121+ The default system instructions (i.e. system message) prepended to model
4112241122+ calls. This field allows the client to guide the model on desired
4112341123+ responses. The model can be instructed on response content and format,
4112441124+ (e.g. "be extremely succinct", "act friendly", "here are examples of good
4112541125+ responses") and on audio behavior (e.g. "talk quickly", "inject emotion
4112641126+ into your voice", "laugh frequently"). The instructions are not guaranteed
4112741127+ to be followed by the model, but they provide guidance to the model on the
4112841128 desired behavior.
41129411294113041130- Note that the server sets default instructions which will be used if this
4113141131- field is not set and are visible in the `session.created` event at the
4113041130+ Note that the server sets default instructions which will be used if this
4113141131+ field is not set and are visible in the `session.created` event at the
4113241132 start of the session.
4113341133 voice:
4113441134 $ref: '#/components/schemas/VoiceIdsShared'
4113541135 description: |
4113641136- The voice the model uses to respond. Voice cannot be changed during the
4113741137- session once the model has responded with audio at least once. Current
4113641136+ The voice the model uses to respond. Voice cannot be changed during the
4113741137+ session once the model has responded with audio at least once. Current
4113841138 voice options are `alloy`, `ash`, `ballad`, `coral`, `echo`, `sage`,
4113941139 `shimmer`, and `verse`.
4114041140 output_audio_format:
···4116341163 description:
4116441164 type: string
4116541165 description: |
4116641166- The description of the function, including guidance on when and how
4116741167- to call it, and guidance about what to tell the user when calling
4116641166+ The description of the function, including guidance on when and how
4116741167+ to call it, and guidance about what to tell the user when calling
4116841168 (if anything).
4116941169 parameters:
4117041170 type: object
···4117241172 tool_choice:
4117341173 type: string
4117441174 description: |
4117541175- How the model chooses tools. Options are `auto`, `none`, `required`, or
4117541175+ How the model chooses tools. Options are `auto`, `none`, `required`, or
4117641176 specify a function, like `{"type": "function", "function": {"name": "my_function"}}`.
4117741177 temperature:
4117841178 type: number
···4119541195 Controls which conversation the response is added to. Currently supports
4119641196 `auto` and `none`, with `auto` as the default value. The `auto` value
4119741197 means that the contents of the response will be added to the default
4119841198- conversation. Set this to `none` to create an out-of-band response which
4119841198+ conversation. Set this to `none` to create an out-of-band response which
4119941199 will not add items to default conversation.
4120041200 anyOf:
4120141201 - type: string
···4129741297 type: object
4129841298 description: |
4129941299 Returned when a conversation item is created. There are several scenarios that produce this event:
4130041300- - The server is generating a Response, which if successful will produce
4130141301- either one or two Items, which will be of type `message`
4130041300+ - The server is generating a Response, which if successful will produce
4130141301+ either one or two Items, which will be of type `message`
4130241302 (role `assistant`) or type `function_call`.
4130341303- - The input audio buffer has been committed, either by the client or the
4130441304- server (in `server_vad` mode). The server will take the content of the
4130341303+ - The input audio buffer has been committed, either by the client or the
4130441304+ server (in `server_vad` mode). The server will take the content of the
4130541305 input audio buffer and add it to a new user message Item.
4130641306- - The client has sent a `conversation.item.create` event to add a new Item
4130641306+ - The client has sent a `conversation.item.create` event to add a new Item
4130741307 to the Conversation.
4130841308 properties:
4130941309 event_id:
···4131741317 type: string
4131841318 nullable: true
4131941319 description: |
4132041320- The ID of the preceding item in the Conversation context, allows the
4132141321- client to understand the order of the conversation. Can be `null` if the
4132041320+ The ID of the preceding item in the Conversation context, allows the
4132141321+ client to understand the order of the conversation. Can be `null` if the
4132241322 item has no predecessor.
4132341323 item:
4132441324 $ref: '#/components/schemas/RealtimeConversationItem'
···4134641346 RealtimeServerEventConversationItemDeleted:
4134741347 type: object
4134841348 description: |
4134941349- Returned when an item in the conversation is deleted by the client with a
4135041350- `conversation.item.delete` event. This event is used to synchronize the
4134941349+ Returned when an item in the conversation is deleted by the client with a
4135041350+ `conversation.item.delete` event. This event is used to synchronize the
4135141351 server's understanding of the conversation history with the client's view.
4135241352 properties:
4135341353 event_id:
···4149441494 RealtimeServerEventConversationItemInputAudioTranscriptionFailed:
4149541495 type: object
4149641496 description: |
4149741497- Returned when input audio transcription is configured, and a transcription
4149841498- request for a user message failed. These events are separate from other
4149741497+ Returned when input audio transcription is configured, and a transcription
4149841498+ request for a user message failed. These events are separate from other
4149941499 `error` events so that the client can identify the related Item.
4150041500 properties:
4150141501 event_id:
···4159741597 RealtimeServerEventConversationItemTruncated:
4159841598 type: object
4159941599 description: |
4160041600- Returned when an earlier assistant audio message item is truncated by the
4160141601- client with a `conversation.item.truncate` event. This event is used to
4160041600+ Returned when an earlier assistant audio message item is truncated by the
4160141601+ client with a `conversation.item.truncate` event. This event is used to
4160241602 synchronize the server's understanding of the audio with the client's playback.
41603416034160441604- This action will truncate the audio and remove the server-side text transcript
4160441604+ This action will truncate the audio and remove the server-side text transcript
4160541605 to ensure there is no text in the context that hasn't been heard by the user.
4160641606 properties:
4160741607 event_id:
···4164141641 RealtimeServerEventError:
4164241642 type: object
4164341643 description: |
4164441644- Returned when an error occurs, which could be a client problem or a server
4164541645- problem. Most errors are recoverable and the session will stay open, we
4164441644+ Returned when an error occurs, which could be a client problem or a server
4164541645+ problem. Most errors are recoverable and the session will stay open, we
4164641646 recommend to implementors to monitor and log error messages by default.
4164741647 properties:
4164841648 event_id:
···4170141701 RealtimeServerEventInputAudioBufferCleared:
4170241702 type: object
4170341703 description: |
4170441704- Returned when the input audio buffer is cleared by the client with a
4170441704+ Returned when the input audio buffer is cleared by the client with a
4170541705 `input_audio_buffer.clear` event.
4170641706 properties:
4170741707 event_id:
···4172541725 RealtimeServerEventInputAudioBufferCommitted:
4172641726 type: object
4172741727 description: |
4172841728- Returned when an input audio buffer is committed, either by the client or
4172841728+ Returned when an input audio buffer is committed, either by the client or
4172941729 automatically in server VAD mode. The `item_id` property is the ID of the user
4173041730- message item that will be created, thus a `conversation.item.created` event
4173041730+ message item that will be created, thus a `conversation.item.created` event
4173141731 will also be sent to the client.
4173241732 properties:
4173341733 event_id:
···4176341763 RealtimeServerEventInputAudioBufferSpeechStarted:
4176441764 type: object
4176541765 description: |
4176641766- Sent by the server when in `server_vad` mode to indicate that speech has been
4176741767- detected in the audio buffer. This can happen any time audio is added to the
4176841768- buffer (unless speech is already detected). The client may want to use this
4176941769- event to interrupt audio playback or provide visual feedback to the user.
4176641766+ Sent by the server when in `server_vad` mode to indicate that speech has been
4176741767+ detected in the audio buffer. This can happen any time audio is added to the
4176841768+ buffer (unless speech is already detected). The client may want to use this
4176941769+ event to interrupt audio playback or provide visual feedback to the user.
41770417704177141771- The client should expect to receive a `input_audio_buffer.speech_stopped` event
4177241772- when speech stops. The `item_id` property is the ID of the user message item
4177341773- that will be created when speech stops and will also be included in the
4177441774- `input_audio_buffer.speech_stopped` event (unless the client manually commits
4177141771+ The client should expect to receive a `input_audio_buffer.speech_stopped` event
4177241772+ when speech stops. The `item_id` property is the ID of the user message item
4177341773+ that will be created when speech stops and will also be included in the
4177441774+ `input_audio_buffer.speech_stopped` event (unless the client manually commits
4177541775 the audio buffer during VAD activation).
4177641776 properties:
4177741777 event_id:
···4178441784 audio_start_ms:
4178541785 type: integer
4178641786 description: |
4178741787- Milliseconds from the start of all audio written to the buffer during the
4178841788- session when speech was first detected. This will correspond to the
4178941789- beginning of audio sent to the model, and thus includes the
4178741787+ Milliseconds from the start of all audio written to the buffer during the
4178841788+ session when speech was first detected. This will correspond to the
4178941789+ beginning of audio sent to the model, and thus includes the
4179041790 `prefix_padding_ms` configured in the Session.
4179141791 item_id:
4179241792 type: string
···4181041810 RealtimeServerEventInputAudioBufferSpeechStopped:
4181141811 type: object
4181241812 description: |
4181341813- Returned in `server_vad` mode when the server detects the end of speech in
4181441814- the audio buffer. The server will also send an `conversation.item.created`
4181341813+ Returned in `server_vad` mode when the server detects the end of speech in
4181441814+ the audio buffer. The server will also send an `conversation.item.created`
4181541815 event with the user message item that is created from the audio buffer.
4181641816 properties:
4181741817 event_id:
···4182441824 audio_end_ms:
4182541825 type: integer
4182641826 description: |
4182741827- Milliseconds since the session started when speech stopped. This will
4182841828- correspond to the end of audio sent to the model, and thus includes the
4182741827+ Milliseconds since the session started when speech stopped. This will
4182841828+ correspond to the end of audio sent to the model, and thus includes the
4182941829 `min_silence_duration_ms` configured in the Session.
4183041830 item_id:
4183141831 type: string
···4195541955 RealtimeServerEventRateLimitsUpdated:
4195641956 type: object
4195741957 description: |
4195841958- Emitted at the beginning of a Response to indicate the updated rate limits.
4195941959- When a Response is created some tokens will be "reserved" for the output
4196041960- tokens, the rate limits shown here reflect that reservation, which is then
4195841958+ Emitted at the beginning of a Response to indicate the updated rate limits.
4195941959+ When a Response is created some tokens will be "reserved" for the output
4196041960+ tokens, the rate limits shown here reflect that reservation, which is then
4196141961 adjusted accordingly once the Response is completed.
4196241962 properties:
4196341963 event_id:
···4237842378 RealtimeServerEventResponseDone:
4237942379 type: object
4238042380 description: |
4238142381- Returned when a Response is done streaming. Always emitted, no matter the
4238242382- final state. The Response object included in the `response.done` event will
4238142381+ Returned when a Response is done streaming. Always emitted, no matter the
4238242382+ final state. The Response object included in the `response.done` event will
4238342383 include all output Items in the Response but will omit the raw audio data.
4238442384 properties:
4238542385 event_id:
···4258742587 RealtimeServerEventResponseOutputItemDone:
4258842588 type: object
4258942589 description: |
4259042590- Returned when an Item is done streaming. Also emitted when a Response is
4259042590+ Returned when an Item is done streaming. Also emitted when a Response is
4259142591 interrupted, incomplete, or cancelled.
4259242592 properties:
4259342593 event_id:
···4273342733 RealtimeServerEventSessionCreated:
4273442734 type: object
4273542735 description: |
4273642736- Returned when a Session is created. Emitted automatically when a new
4273742737- connection is established as the first server event. This event will contain
4273642736+ Returned when a Session is created. Emitted automatically when a new
4273742737+ connection is established as the first server event. This event will contain
4273842738 the default Session configuration.
4273942739 properties:
4274042740 event_id:
···4278442784 RealtimeServerEventSessionUpdated:
4278542785 type: object
4278642786 description: |
4278742787- Returned when a session is updated with a `session.update` event, unless
4278742787+ Returned when a session is updated with a `session.update` event, unless
4278842788 there is an error.
4278942789 properties:
4279042790 event_id:
···4283142831 RealtimeServerEventTranscriptionSessionUpdated:
4283242832 type: object
4283342833 description: |
4283442834- Returned when a transcription session is updated with a `transcription_session.update` event, unless
4283442834+ Returned when a transcription session is updated with a `transcription_session.update` event, unless
4283542835 there is an error.
4283642836 properties:
4283742837 event_id:
···4388043880 A new Realtime transcription session configuration.
43881438814388243882 When a session is created on the server via REST API, the session object
4388343883- also contains an ephemeral key. Default TTL for keys is 10 minutes. This
4388343883+ also contains an ephemeral key. Default TTL for keys is 10 minutes. This
4388443884 property is not present when a session is updated via the WebSocket API.
4388543885 properties:
4388643886 client_secret:
···4394843948 turn_detection:
4394943949 type: object
4395043950 description: |
4395143951- Configuration for turn detection. Can be set to `null` to turn off. Server
4395243952- VAD means that the model will detect the start and end of speech based on
4395143951+ Configuration for turn detection. Can be set to `null` to turn off. Server
4395243952+ VAD means that the model will detect the start and end of speech based on
4395343953 audio volume and respond at the end of user speech.
4395443954 properties:
4395543955 type:
···4395943959 threshold:
4396043960 type: number
4396143961 description: |
4396243962- Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A
4396343963- higher threshold will require louder audio to activate the model, and
4396243962+ Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A
4396343963+ higher threshold will require louder audio to activate the model, and
4396443964 thus might perform better in noisy environments.
4396543965 prefix_padding_ms:
4396643966 type: integer
4396743967 description: |
4396843968- Amount of audio to include before the VAD detected speech (in
4396843968+ Amount of audio to include before the VAD detected speech (in
4396943969 milliseconds). Defaults to 300ms.
4397043970 silence_duration_ms:
4397143971 type: integer
4397243972 description: |
4397343973- Duration of silence to detect speech stop (in milliseconds). Defaults
4397443974- to 500ms. With shorter values the model will respond more quickly,
4397343973+ Duration of silence to detect speech stop (in milliseconds). Defaults
4397443974+ to 500ms. With shorter values the model will respond more quickly,
4397543975 but may jump in on short pauses from the user.
4397643976 required:
4397743977 - client_secret
···4404444044 default: medium
4404544045 nullable: true
4404644046 description: |
4404744047- Constrains effort on reasoning for
4404744047+ Constrains effort on reasoning for
4404844048 [reasoning models](https://platform.openai.com/docs/guides/reasoning).
4404944049 Currently supported values are `minimal`, `low`, `medium`, and `high`. Reducing
4405044050 reasoning effort can result in faster responses and fewer tokens used
···4405444054 description: |
4405544055 A description of the chain of thought used by a reasoning model while generating
4405644056 a response. Be sure to include these items in your `input` to the Responses API
4405744057- for subsequent turns of a conversation if you are manually
4405744057+ for subsequent turns of a conversation if you are manually
4405844058 [managing context](https://platform.openai.com/docs/guides/conversation-state).
4405944059 title: Reasoning
4406044060 properties:
···4415144151 status:
4415244152 type: string
4415344153 description: |
4415444154- The status of the response generation. One of `completed`, `failed`,
4415444154+ The status of the response generation. One of `completed`, `failed`,
4415544155 `in_progress`, `cancelled`, `queued`, or `incomplete`.
4415644156 enum:
4415744157 - completed
···44185441854418644186 - The length and order of items in the `output` array is dependent
4418744187 on the model's response.
4418844188- - Rather than accessing the first item in the `output` array and
4418844188+ - Rather than accessing the first item in the `output` array and
4418944189 assuming it's an `assistant` message with the content generated by
4419044190 the model, you might consider using the `output_text` property where
4419144191 supported in SDKs.
···4420244202 anyOf:
4420344203 - type: string
4420444204 description: |
4420544205- A text input to the model, equivalent to a text input with the
4420544205+ A text input to the model, equivalent to a text input with the
4420644206 `developer` role.
4420744207 - type: array
4420844208 title: Input item list
4420944209 description: |
4421044210- A list of one or many input items to the model, containing
4421044210+ A list of one or many input items to the model, containing
4421144211 different content types.
4421244212 items:
4421344213 $ref: '#/components/schemas/InputItem'
···4421544215 type: string
4421644216 nullable: true
4421744217 description: |
4421844218- SDK-only convenience property that contains the aggregated text output
4421944219- from all `output_text` items in the `output` array, if any are present.
4421844218+ SDK-only convenience property that contains the aggregated text output
4421944219+ from all `output_text` items in the `output` array, if any are present.
4422044220 Supported in the Python and JavaScript SDKs.
4422144221 x-oaiSupportedSDKs:
4422244222 - python
···4557745577 "object": "response",
4557845578 "created_at": 1740855869,
4557945579 "status": "incomplete",
4558045580- "error": null,
4558045580+ "error": null,
4558145581 "incomplete_details": {
4558245582 "reason": "max_tokens"
4558345583 },
···4565845658 ResponseLogProb:
4565945659 type: object
4566045660 description: |
4566145661- A logprob is the logarithmic probability that the model assigns to producing
4566245662- a particular token at a given position in the sequence. Less-negative (higher)
4566145661+ A logprob is the logarithmic probability that the model assigns to producing
4566245662+ a particular token at a given position in the sequence. Less-negative (higher)
4566345663 logprob values indicate greater model confidence in that token choice.
4566445664 properties:
4566545665 token:
···45994459944599545995 `["text"]`
45996459964599745997- The `gpt-4o-audio-preview` model can also be used to
4599845998- [generate audio](https://platform.openai.com/docs/guides/audio). To request that this model generate
4599745997+ The `gpt-4o-audio-preview` model can also be used to
4599845998+ [generate audio](https://platform.openai.com/docs/guides/audio). To request that this model generate
4599945999 both text and audio responses, you can use:
46000460004600146001 `["text", "audio"]`
···4694646946 cached_tokens:
4694746947 type: integer
4694846948 description: |
4694946949- The number of tokens that were retrieved from the cache.
4694946949+ The number of tokens that were retrieved from the cache.
4695046950 [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching).
4695146951 required:
4695246952 - cached_tokens
···4712047120 item:
4712147121 type: object
4712247122 description: >
4712347123- The dataset item provided to the grader. This will be used to populate
4712347123+ The dataset item provided to the grader. This will be used to populate
47124471244712547125 the `item` namespace. See [the guide](https://platform.openai.com/docs/guides/graders) for more
4712647126 details.
4712747127 model_sample:
4712847128 type: string
4712947129 description: >
4713047130- The model sample to be evaluated. This value will be used to populate
4713047130+ The model sample to be evaluated. This value will be used to populate
47131471314713247132 the `sample` namespace. See [the guide](https://platform.openai.com/docs/guides/graders) for more
4713347133 details.
47134471344713547135- The `output_json` variable will be populated if the model sample is a
4713547135+ The `output_json` variable will be populated if the model sample is a
47136471364713747137 valid JSON string.
4713847138···4842548425 - screenshot
4842648426 default: screenshot
4842748427 description: |
4842848428- Specifies the event type. For a screenshot action, this property is
4842848428+ Specifies the event type. For a screenshot action, this property is
4842948429 always set to `screenshot`.
4843048430 x-stainless-const: true
4843148431 required:
···4844248442 - scroll
4844348443 default: scroll
4844448444 description: |
4844548445- Specifies the event type. For a scroll action, this property is
4844548445+ Specifies the event type. For a scroll action, this property is
4844648446 always set to `scroll`.
4844748447 x-stainless-const: true
4844848448 x:
···4865748657 description: |
4865848658 An object specifying the format that the model must output.
48659486594866048660- Configuring `{ "type": "json_schema" }` enables Structured Outputs,
4866148661- which ensures the model will match your supplied JSON schema. Learn more in the
4866048660+ Configuring `{ "type": "json_schema" }` enables Structured Outputs,
4866148661+ which ensures the model will match your supplied JSON schema. Learn more in the
4866248662 [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs).
48663486634866448664 The default format is `{ "type": "text" }` with no additional options.
···4928149281 - type
4928249282 default: type
4928349283 description: |
4928449284- Specifies the event type. For a type action, this property is
4928449284+ Specifies the event type. For a type action, this property is
4928549285 always set to `type`.
4928649286 x-stainless-const: true
4928749287 text:
···4997849978 type: integer
4997949979 default: 300
4998049980 description: |
4998149981- Amount of audio to include before the VAD detected speech (in
4998149981+ Amount of audio to include before the VAD detected speech (in
4998249982 milliseconds).
4998349983 silence_duration_ms:
4998449984 type: integer
4998549985 default: 200
4998649986 description: |
4998749987 Duration of silence to detect speech stop (in milliseconds).
4998849988- With shorter values the model will respond more quickly,
4998849988+ With shorter values the model will respond more quickly,
4998949989 but may jump in on short pauses from the user.
4999049990 threshold:
4999149991 type: number
4999249992 default: 0.5
4999349993 description: |
4999449994- Sensitivity threshold (0.0 to 1.0) for voice activity detection. A
4999549995- higher threshold will require louder audio to activate the model, and
4999449994+ Sensitivity threshold (0.0 to 1.0) for voice activity detection. A
4999549995+ higher threshold will require louder audio to activate the model, and
4999649996 thus might perform better in noisy environments.
4999749997 ValidateGraderRequest:
4999849998 type: object
···5004450044 VectorStoreFileAttributes:
5004550045 type: object
5004650046 description: |
5004750047- Set of 16 key-value pairs that can be attached to an object. This can be
5004850048- useful for storing additional information about the object in a structured
5004950049- format, and querying for objects via API or the dashboard. Keys are strings
5005050050- with a maximum length of 64 characters. Values are strings with a maximum
5004750047+ Set of 16 key-value pairs that can be attached to an object. This can be
5004850048+ useful for storing additional information about the object in a structured
5004950049+ format, and querying for objects via API or the dashboard. Keys are strings
5005050050+ with a maximum length of 64 characters. Values are strings with a maximum
5005150051 length of 512 characters, booleans, or numbers.
5005250052 maxProperties: 16
5005350053 propertyNames:
···5053250532 - wait
5053350533 default: wait
5053450534 description: |
5053550535- Specifies the event type. For a wait action, this property is
5053550535+ Specifies the event type. For a wait action, this property is
5053650536 always set to `wait`.
5053750537 x-stainless-const: true
5053850538 required:
···5060750607 WebSearchContextSize:
5060850608 type: string
5060950609 description: |
5061050610- High level guidance for the amount of context window space to use for the
5061050610+ High level guidance for the amount of context window space to use for the
5061150611 search. One of `low`, `medium`, or `high`. `medium` is the default.
5061250612 enum:
5061350613 - low
···5062250622 country:
5062350623 type: string
5062450624 description: |
5062550625- The two-letter
5062550625+ The two-letter
5062650626 [ISO country code](https://en.wikipedia.org/wiki/ISO_3166-1) of the user,
5062750627 e.g. `US`.
5062850628 region:
···5063650636 timezone:
5063750637 type: string
5063850638 description: |
5063950639- The [IANA timezone](https://timeapi.io/documentation/iana-timezones)
5063950639+ The [IANA timezone](https://timeapi.io/documentation/iana-timezones)
5064050640 of the user, e.g. `America/Los_Angeles`.
5064150641 WebSearchToolCall:
5064250642 type: object
5064350643 title: Web search tool call
5064450644 description: |
5064550645- The results of a web search tool call. See the
5064550645+ The results of a web search tool call. See the
5064650646 [web search guide](https://platform.openai.com/docs/guides/tools-web-search) for more information.
5064750647 properties:
5064850648 id:
···5211652116 transcript:
5211752117 type: string
5211852118 description: |
5211952119- The transcript of the audio, used for `input_audio` and `audio`
5211952119+ The transcript of the audio, used for `input_audio` and `audio`
5212052120 content types.
5212152121 RealtimeConnectParams:
5212252122 type: object
···5289352893 title: Webhook Events
5289452894 description: |
5289552895 Webhooks are HTTP requests sent by OpenAI to a URL you specify when certain
5289652896- events happen during the course of API usage.
5289652896+ events happen during the course of API usage.
52897528975289852898 [Learn more about webhooks](https://platform.openai.com/docs/guides/webhooks).
5289952899 navigationGroup: webhooks