@sdk-it/typescript 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -13,11 +13,15 @@ import {
13
13
  import {
14
14
  augmentSpec,
15
15
  cleanFiles,
16
+ forEachOperation as forEachOperation4,
16
17
  readWriteMetadata,
17
18
  sanitizeTag as sanitizeTag4,
18
19
  securityToOptions as securityToOptions2
19
20
  } from "@sdk-it/spec";
20
21
 
22
+ // packages/typescript/src/lib/agent/utils.txt
23
+ var utils_default = "function coerceContext(context?: any) {\n if (!context) {\n throw new Error('Context is required');\n }\n return context as {\n client: any\n };\n}\n/**\n * Takes a Zod object schema and makes all optional properties nullable as well.\n * This is useful for APIs where optional fields can be explicitly set to null.\n *\n * @param schema - The Zod object schema to transform\n * @returns A new Zod schema with optional properties made nullable\n */\nfunction makeOptionalPropsNullable<T extends z.ZodRawShape>(\n schema: z.ZodObject<T>,\n) {\n const shape = schema.shape;\n const newShape = {} as Record<string, z.ZodTypeAny>;\n\n for (const [key, value] of Object.entries(shape)) {\n if (value instanceof z.ZodOptional) {\n // Make optional properties also nullable\n newShape[key] = value._def.innerType.nullable().optional();\n } else {\n // Keep non-optional properties as they are\n newShape[key] = value;\n }\n }\n\n return z.object(newShape);\n}";
24
+
21
25
  // packages/typescript/src/lib/client.ts
22
26
  import { toLitObject } from "@sdk-it/core";
23
27
 
@@ -1639,7 +1643,7 @@ var PropEmitter = class {
1639
1643
  const defaultVal = !isRef4(schema) && schema.default !== void 0 ? ` default: ${JSON.stringify(schema.default)}` : "";
1640
1644
  const reqMark = required ? " required" : "";
1641
1645
  const summary = `- \`${name}\` ${rawType}${reqMark}${defaultVal}:`;
1642
- const detailLines = docs.slice(1).filter((l) => !l.startsWith("**Default:**")).map((l) => ` ${l}`);
1646
+ const detailLines = docs.slice(1).filter((it) => !it.startsWith("**Default:**")).map((it) => ` ${it}`);
1643
1647
  return [summary, ...detailLines];
1644
1648
  }
1645
1649
  /**
@@ -1849,35 +1853,29 @@ var PropEmitter = class {
1849
1853
  * Process a request body and return markdown documentation
1850
1854
  */
1851
1855
  requestBody(requestBody) {
1852
- if (!requestBody) return [];
1853
1856
  const lines = [];
1854
- lines.push(`##### Request Body`);
1855
- if (requestBody.description) {
1856
- lines.push(requestBody.description);
1857
- }
1858
- if (requestBody.content) {
1859
- const contentEntries = Object.entries(requestBody.content);
1860
- if (contentEntries.length === 1) {
1861
- const [contentType, mediaType] = contentEntries[0];
1862
- lines.push(`**Content Type:** \`${contentType}\``);
1857
+ lines.push(`#### Input`);
1858
+ lines.push(requestBody.description || "");
1859
+ const contentEntries = Object.entries(requestBody.content);
1860
+ const multipleContentTypes = contentEntries.length > 1;
1861
+ if (multipleContentTypes) {
1862
+ for (const [contentType, mediaType] of contentEntries) {
1863
+ lines.push(`<details>`);
1864
+ lines.push(`<summary>Content Type: \`${contentType}\`</summary>`);
1865
+ lines.push("");
1863
1866
  if (mediaType.schema) {
1864
1867
  const schemaDocs = this.handle(mediaType.schema);
1865
- lines.push(...schemaDocs);
1866
- }
1867
- } else {
1868
- for (const [contentType, mediaType] of contentEntries) {
1869
- lines.push(`<details>`);
1870
- lines.push(
1871
- `<summary><b>Content Type:</b> \`${contentType}\`</summary>`
1872
- );
1873
- lines.push("");
1874
- if (mediaType.schema) {
1875
- const schemaDocs = this.handle(mediaType.schema);
1876
- lines.push(...schemaDocs.map((l) => l));
1877
- }
1878
- lines.push("");
1879
- lines.push(`</details>`);
1868
+ lines.push(...schemaDocs.map((l) => l));
1880
1869
  }
1870
+ lines.push("");
1871
+ lines.push(`</details>`);
1872
+ }
1873
+ } else {
1874
+ const [contentType, mediaType] = contentEntries[0];
1875
+ lines.push(`Content Type: \`${contentType}\``);
1876
+ if (mediaType.schema) {
1877
+ const schemaDocs = this.handle(mediaType.schema);
1878
+ lines.push(...schemaDocs);
1881
1879
  }
1882
1880
  }
1883
1881
  return lines;
@@ -1915,37 +1913,49 @@ function toReadme(spec, generator) {
1915
1913
  forEachOperation2(spec, (entry, operation) => {
1916
1914
  const { method, path } = entry;
1917
1915
  markdown.push(
1918
- `#### ${operation["x-fn-name"]} | ${`_${method.toUpperCase()} ${path}_`}`
1916
+ `### ${operation["x-fn-name"]} | ${`_${method.toUpperCase()} ${path}_`}`
1919
1917
  );
1920
1918
  markdown.push(operation.summary || "");
1921
1919
  const snippet = generator.snippet(entry, operation);
1922
- markdown.push(`##### Example usage`);
1920
+ markdown.push(`#### Example usage`);
1923
1921
  markdown.push(snippet);
1924
1922
  const requestBodyContent = propEmitter.requestBody(operation.requestBody);
1925
1923
  if (requestBodyContent.length > 1) {
1926
1924
  markdown.push(requestBodyContent.join("\n\n"));
1927
1925
  }
1928
- markdown.push(`##### Responses`);
1926
+ markdown.push(`#### Output`);
1929
1927
  for (const status in operation.responses) {
1930
1928
  const response = operation.responses[status];
1931
- markdown.push(`<details>`);
1932
- markdown.push(
1933
- `<summary><b>${status}</b> <i>${response.description}</i></summary>`
1934
- );
1935
1929
  if (!isEmpty3(response.content)) {
1936
- for (const [contentType, mediaType] of Object.entries(
1937
- response.content
1938
- )) {
1930
+ const contentEntries = Object.entries(response.content);
1931
+ if (contentEntries.length === 1) {
1932
+ const [contentType, mediaType] = contentEntries[0];
1933
+ markdown.push(`**${status}** - ${response.description}`);
1939
1934
  markdown.push(`
1940
1935
  **Content Type:** \`${contentType}\``);
1941
1936
  if (mediaType.schema) {
1942
1937
  const schemaDocs = propEmitter.handle(mediaType.schema);
1943
- markdown.push(...schemaDocs.map((l) => `
1938
+ markdown.push(...schemaDocs);
1939
+ }
1940
+ } else {
1941
+ markdown.push(`<details>`);
1942
+ markdown.push(
1943
+ `<summary><b>${status}</b> <i>${response.description}</i></summary>`
1944
+ );
1945
+ for (const [contentType, mediaType] of contentEntries) {
1946
+ markdown.push(`
1947
+ **Content Type:** \`${contentType}\``);
1948
+ if (mediaType.schema) {
1949
+ const schemaDocs = propEmitter.handle(mediaType.schema);
1950
+ markdown.push(...schemaDocs.map((l) => `
1944
1951
  ${l}`));
1952
+ }
1945
1953
  }
1954
+ markdown.push(`</details>`);
1946
1955
  }
1956
+ } else {
1957
+ markdown.push(`**${status}** - ${response.description}`);
1947
1958
  }
1948
- markdown.push(`</details>`);
1949
1959
  }
1950
1960
  });
1951
1961
  if (spec.components?.schemas) {
@@ -3070,6 +3080,12 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3070
3080
  "models/index.ts": modelsIndex
3071
3081
  // ...(modelsImports.length ? { 'models/index.ts': modelsIndex } : {}),
3072
3082
  });
3083
+ if (settings.agentTools) {
3084
+ await settings.writer(output, {
3085
+ "agents.ts": `${generateAgentTools(spec)}
3086
+ ${utils_default}`
3087
+ });
3088
+ }
3073
3089
  await settings.writer(output, {
3074
3090
  "index.ts": await getFolderExports(
3075
3091
  output,
@@ -3228,9 +3244,44 @@ function toInputs(operationsSet, commonZod, makeImport) {
3228
3244
  ...inputs
3229
3245
  };
3230
3246
  }
3247
+ function generateAgentTools(spec) {
3248
+ const groups = {};
3249
+ forEachOperation4(spec, (entry, operation) => {
3250
+ groups[entry.tag] ??= [];
3251
+ groups[entry.tag].push(createTool(entry, operation));
3252
+ });
3253
+ const imports = [
3254
+ `import { z } from 'zod';`,
3255
+ `import { tool } from '@openai/agents';`,
3256
+ `import * as schemas from './inputs/index.ts';`
3257
+ ];
3258
+ const tools = Object.entries(groups).map(([group, tools2]) => {
3259
+ return `export const ${spinalcase3(group)} = [${tools2.join(", ")}];`;
3260
+ });
3261
+ return [...imports, ...tools].join("\n\n");
3262
+ }
3263
+ function createTool(entry, operation) {
3264
+ const schemaName = camelcase4(`${operation.operationId} schema`);
3265
+ return `tool({
3266
+ description: \`${operation.description || operation.summary}\`,
3267
+ name: '${operation["x-fn-name"]}',
3268
+ parameters: makeOptionalPropsNullable(schemas.${schemaName}),
3269
+ execute: async (input, maybeContext) => {
3270
+ console.log('Executing ${operation.operationId} tool with input:', input);
3271
+ const context = coerceContext(maybeContext?.context);
3272
+ const client = context.client;
3273
+ const response = await client.request(
3274
+ '${entry.method.toUpperCase()} ${entry.path}' ,
3275
+ input as any,
3276
+ );
3277
+ return JSON.stringify(response);
3278
+ },
3279
+ })`;
3280
+ }
3231
3281
  export {
3232
3282
  TypeScriptGenerator,
3233
3283
  generate,
3284
+ generateAgentTools,
3234
3285
  toInputs
3235
3286
  };
3236
3287
  //# sourceMappingURL=index.js.map