@sdk-it/typescript 0.33.3 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { template as template2 } from "lodash-es";
3
3
  import { readdir } from "node:fs/promises";
4
4
  import { join as join2 } from "node:path";
5
5
  import { npmRunPathEnv } from "npm-run-path";
6
- import { camelcase as camelcase5, spinalcase as spinalcase4 } from "stringcase";
6
+ import { camelcase as camelcase6, spinalcase as spinalcase4 } from "stringcase";
7
7
  import { methods, pascalcase as pascalcase5, toLitObject as toLitObject2 } from "@sdk-it/core";
8
8
  import {
9
9
  createWriterProxy,
@@ -19,34 +19,58 @@ import {
19
19
  } from "@sdk-it/spec";
20
20
 
21
21
  // packages/typescript/src/lib/agent/ai-sdk.ts
22
- import { camelcase, spinalcase } from "stringcase";
22
+ import { camelcase } from "stringcase";
23
23
  import {
24
24
  forEachOperation
25
25
  } from "@sdk-it/spec";
26
- function generateAISDKTools(spec) {
26
+ function generateAISDKTools(ir) {
27
27
  const groups = {};
28
- forEachOperation(spec, (entry, operation) => {
29
- groups[entry.tag] ??= [];
30
- groups[entry.tag].push(createTool(entry, operation));
28
+ forEachOperation(ir, (entry, operation) => {
29
+ const tagDef = ir.tags.find((tag) => tag.name === entry.tag);
30
+ if (!tagDef) {
31
+ console.warn(`No tag details found for tag: ${entry.tag}`);
32
+ return;
33
+ }
34
+ groups[entry.tag] ??= {
35
+ tools: [],
36
+ instructions: "",
37
+ displayName: "",
38
+ name: ""
39
+ };
40
+ groups[entry.tag].tools.push(createTool(entry, operation));
41
+ groups[entry.tag].instructions = tagDef["x-instructions"];
42
+ groups[entry.tag].name = tagDef.name;
43
+ groups[entry.tag].displayName = tagDef["x-name"];
31
44
  });
32
45
  const imports = [
33
46
  `import { z } from 'zod';`,
34
47
  `import { tool } from 'ai';`,
35
48
  `import * as schemas from './inputs/index.ts';`
36
49
  ];
37
- const tools = Object.entries(groups).map(([group, tools2]) => {
38
- return `export const ${spinalcase(group)} = (context: { client: any }) => ({ ${tools2.join(", ")} });`;
39
- });
40
- return [...imports, ...tools].join("\n\n");
50
+ const agent = Object.entries(groups).map(
51
+ ([group, { instructions, tools, displayName }]) => {
52
+ return `export const ${camelcase(group)} = {
53
+ name: '${displayName}',
54
+ instructions: \`${instructions}\`,
55
+ tools: { ${tools.join(", ")} }
56
+ }`;
57
+ }
58
+ );
59
+ const handoffs = `export const triage = {
60
+ name: 'Triage Agent',
61
+ tools:{${Object.entries(groups).map(([, { name }]) => {
62
+ return createTransferTool(name);
63
+ })}}}`;
64
+ return [...imports, ...agent, handoffs].join("\n\n");
41
65
  }
42
66
  function createTool(entry, operation) {
43
67
  const schemaName = camelcase(`${operation.operationId} schema`);
44
68
  return `'${operation["x-fn-name"]}': tool({
45
69
  description: \`${operation.description || operation.summary}\`,
46
- type: 'function',
47
70
  inputSchema: schemas.${schemaName},
48
- execute: async (input) => {
71
+ execute: async (input, options) => {
49
72
  console.log('Executing ${operation.operationId} tool with input:', input);
73
+ const context = coerceContext(options.experimental_context);
50
74
  const response = await context.client.request(
51
75
  '${entry.method.toUpperCase()} ${entry.path}' ,
52
76
  input as any,
@@ -55,6 +79,54 @@ function createTool(entry, operation) {
55
79
  },
56
80
  })`;
57
81
  }
82
+ function createTransferTool(agentName) {
83
+ return `transfer_to_${agentName}: tool({
84
+ type: 'function',
85
+ description: 'Transfer the conversation to the ${agentName}.',
86
+ inputSchema: z.object({}),
87
+ execute: async () => ({ agent: '${agentName}' }),
88
+ })`;
89
+ }
90
+
91
+ // packages/typescript/src/lib/agent/openai-agents.ts
92
+ import { camelcase as camelcase2, spinalcase } from "stringcase";
93
+ import {
94
+ forEachOperation as forEachOperation2
95
+ } from "@sdk-it/spec";
96
+ function generateOpenAIAgentTools(spec) {
97
+ const groups = {};
98
+ forEachOperation2(spec, (entry, operation) => {
99
+ groups[entry.tag] ??= [];
100
+ groups[entry.tag].push(createTool2(entry, operation));
101
+ });
102
+ const imports = [
103
+ `import { z } from 'zod';`,
104
+ `import { tool } from '@openai/agents';`,
105
+ `import * as schemas from './inputs/index.ts';`
106
+ ];
107
+ const tools = Object.entries(groups).map(([group, tools2]) => {
108
+ return `export const ${spinalcase(group)} = [${tools2.join(", ")}];`;
109
+ });
110
+ return [...imports, ...tools].join("\n\n");
111
+ }
112
+ function createTool2(entry, operation) {
113
+ const schemaName = camelcase2(`${operation.operationId} schema`);
114
+ return `tool({
115
+ description: \`${operation.description || operation.summary}\`,
116
+ name: '${operation["x-fn-name"]}',
117
+ parameters: makeOptionalPropsNullable(schemas.${schemaName}),
118
+ execute: async (input, maybeContext) => {
119
+ console.log('Executing ${operation.operationId} tool with input:', input);
120
+ const context = coerceContext(maybeContext?.context);
121
+ const client = context.client;
122
+ const response = await client.request(
123
+ '${entry.method.toUpperCase()} ${entry.path}' ,
124
+ input as any,
125
+ );
126
+ return JSON.stringify(response);
127
+ },
128
+ })`;
129
+ }
58
130
 
59
131
  // packages/typescript/src/lib/agent/utils.txt
60
132
  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}";
@@ -350,6 +422,9 @@ var client_default = (spec, style) => {
350
422
  },
351
423
  baseUrl: {
352
424
  schema: spec.servers.length ? `z.enum(servers).default(servers[0])` : "z.string()"
425
+ },
426
+ headers: {
427
+ schema: "z.record(z.string()).optional()"
353
428
  }
354
429
  };
355
430
  return `import z from 'zod';
@@ -361,7 +436,7 @@ import {
361
436
  createHeadersInterceptor,
362
437
  } from './http/${spec.makeImport("interceptors")}';
363
438
 
364
- import { parseInput, type ParseError } from './http/${spec.makeImport("parser")}';
439
+ import { type ParseError, parseInput } from './http/${spec.makeImport("parser")}';
365
440
 
366
441
  ${spec.servers.length ? `export const servers = ${JSON.stringify(spec.servers, null, 2)} as const` : ""}
367
442
  const optionsSchema = z.object(${toLitObject(specOptions, (x) => x.schema)});
@@ -436,7 +511,7 @@ export class ${spec.name} {
436
511
  }
437
512
 
438
513
  get defaultHeaders() {
439
- return ${defaultHeaders}
514
+ return { ...${defaultHeaders}, ...this.options.headers}
440
515
  }
441
516
 
442
517
  get #defaultInputs() {
@@ -625,14 +700,14 @@ function appendOptional2(type, isRequired) {
625
700
  // packages/typescript/src/lib/generator.ts
626
701
  import { merge, template } from "lodash-es";
627
702
  import { join } from "node:path";
628
- import { camelcase as camelcase3, spinalcase as spinalcase2 } from "stringcase";
703
+ import { camelcase as camelcase4, spinalcase as spinalcase2 } from "stringcase";
629
704
  import { followRef as followRef3, isEmpty as isEmpty2, isRef as isRef3, resolveRef } from "@sdk-it/core";
630
705
  import {
631
- forEachOperation as forEachOperation2
706
+ forEachOperation as forEachOperation3
632
707
  } from "@sdk-it/spec";
633
708
 
634
709
  // packages/typescript/src/lib/sdk.ts
635
- import { camelcase as camelcase2 } from "stringcase";
710
+ import { camelcase as camelcase3 } from "stringcase";
636
711
  import { isEmpty, pascalcase as pascalcase3 } from "@sdk-it/core";
637
712
  import {
638
713
  isStreamingContentType,
@@ -672,8 +747,8 @@ var status_map_default = {
672
747
 
673
748
  // packages/typescript/src/lib/sdk.ts
674
749
  function toEndpoint(groupName, spec, specOperation, operation, utils) {
675
- const schemaName = camelcase2(`${specOperation.operationId} schema`);
676
- const schemaRef = `${camelcase2(groupName)}.${schemaName}`;
750
+ const schemaName = camelcase3(`${specOperation.operationId} schema`);
751
+ const schemaRef = `${camelcase3(groupName)}.${schemaName}`;
677
752
  const schemas = [];
678
753
  specOperation.responses ??= {};
679
754
  const outputs = Object.keys(specOperation.responses).flatMap(
@@ -939,7 +1014,7 @@ function generateCode(config) {
939
1014
  });
940
1015
  const groups = {};
941
1016
  const endpoints = {};
942
- forEachOperation2(config.spec, (entry, operation) => {
1017
+ forEachOperation3(config.spec, (entry, operation) => {
943
1018
  console.log(`Processing ${entry.method} ${entry.path}`);
944
1019
  groups[entry.tag] ??= [];
945
1020
  endpoints[entry.tag] ??= [];
@@ -987,8 +1062,8 @@ function generateCode(config) {
987
1062
  });
988
1063
  });
989
1064
  const allSchemas = Object.keys(endpoints).map((it) => ({
990
- import: `import ${camelcase3(it)} from './${config.makeImport(spinalcase2(it))}';`,
991
- use: ` ...${camelcase3(it)}`
1065
+ import: `import ${camelcase4(it)} from './${config.makeImport(spinalcase2(it))}';`,
1066
+ use: ` ...${camelcase4(it)}`
992
1067
  }));
993
1068
  return {
994
1069
  groups,
@@ -1024,7 +1099,7 @@ ${allSchemas.map((it) => it.use).join(",\n")}
1024
1099
  `import * as outputs from '${config.makeImport("../outputs/index")}';`,
1025
1100
  `import { toRequest, json, urlencoded, empty, formdata, type HeadersInit } from '${config.makeImport("../http/request")}';`,
1026
1101
  `import { chunked, buffered } from "${config.makeImport("../http/parse-response")}";`,
1027
- `import * as ${camelcase3(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`,
1102
+ `import * as ${camelcase4(name)} from '../inputs/${config.makeImport(spinalcase2(name))}';`,
1028
1103
  `import { createBaseUrlInterceptor, createHeadersInterceptor, type Interceptor } from '${config.makeImport("../http/interceptors")}';`,
1029
1104
  `import { Dispatcher, fetchType, type InstanceType } from '${config.makeImport("../http/dispatcher")}';`,
1030
1105
  `import { Pagination, OffsetPagination, CursorPagination } from "${config.makeImport("../pagination/index")}";`
@@ -1609,7 +1684,7 @@ var page_pagination_default = "type InferPage<T> = T extends Page<infer U> ? U :
1609
1684
 
1610
1685
  // packages/typescript/src/lib/readme/readme.ts
1611
1686
  import { isEmpty as isEmpty3 } from "@sdk-it/core";
1612
- import { forEachOperation as forEachOperation3 } from "@sdk-it/spec";
1687
+ import { forEachOperation as forEachOperation4 } from "@sdk-it/spec";
1613
1688
 
1614
1689
  // packages/typescript/src/lib/readme/prop.emitter.ts
1615
1690
  import { followRef as followRef4, isRef as isRef4 } from "@sdk-it/core";
@@ -1920,7 +1995,7 @@ function toReadme(spec, generator) {
1920
1995
  markdown.push("");
1921
1996
  markdown.push("## API Reference");
1922
1997
  markdown.push("");
1923
- forEachOperation3(spec, (entry, operation) => {
1998
+ forEachOperation4(spec, (entry, operation) => {
1924
1999
  const { method, path } = entry;
1925
2000
  markdown.push(
1926
2001
  `### ${operation["x-fn-name"]} | ${`_${method.toUpperCase()} ${path}_`}`
@@ -1993,11 +2068,11 @@ ${l}`));
1993
2068
  }
1994
2069
 
1995
2070
  // packages/typescript/src/lib/typescript-snippet.ts
1996
- import { camelcase as camelcase4, spinalcase as spinalcase3 } from "stringcase";
2071
+ import { camelcase as camelcase5, spinalcase as spinalcase3 } from "stringcase";
1997
2072
  import { isEmpty as isEmpty4, pascalcase as pascalcase4, resolveRef as resolveRef3 } from "@sdk-it/core";
1998
2073
  import "@sdk-it/readme";
1999
2074
  import {
2000
- forEachOperation as forEachOperation4,
2075
+ forEachOperation as forEachOperation5,
2001
2076
  patchParameters,
2002
2077
  securityToOptions
2003
2078
  } from "@sdk-it/spec";
@@ -2018,7 +2093,7 @@ var SnippetEmitter = class {
2018
2093
  for (const [propName, propSchema] of Object.entries(properties)) {
2019
2094
  const isRequired = (schemaObj.required ?? []).includes(propName);
2020
2095
  const resolvedProp = resolveRef2(this.spec, propSchema);
2021
- if (isRequired || resolvedProp.example !== void 0 || resolvedProp.default !== void 0 || Math.random() > 0.5) {
2096
+ if (isRequired || resolvedProp.example !== void 0 || resolvedProp.default !== void 0) {
2022
2097
  result[propName] = this.handle(propSchema);
2023
2098
  }
2024
2099
  }
@@ -2320,7 +2395,7 @@ var TypeScriptSnippet = class {
2320
2395
  };
2321
2396
  }
2322
2397
  #toRequest(entry, payload) {
2323
- return `await ${camelcase4(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
2398
+ return `await ${camelcase5(this.#clientName)}.request('${entry.method.toUpperCase()} ${entry.path}', ${payload});`;
2324
2399
  }
2325
2400
  snippet(entry, operation, config = {}) {
2326
2401
  const payload = this.succinct(entry, operation, config);
@@ -2361,7 +2436,7 @@ ${client.use}`;
2361
2436
  #constructClient(options = {}) {
2362
2437
  return {
2363
2438
  import: `import { ${this.#clientName} } from '${this.#packageName}';`,
2364
- use: `const ${camelcase4(this.#clientName)} = new ${this.#clientName}({
2439
+ use: `const ${camelcase5(this.#clientName)} = new ${this.#clientName}({
2365
2440
  ${Object.entries(
2366
2441
  options
2367
2442
  ).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(",\n ")}
@@ -2896,7 +2971,7 @@ function availablePaginationTypes(spec) {
2896
2971
  let offset = false;
2897
2972
  let page = false;
2898
2973
  let cursor = false;
2899
- forEachOperation4(spec, (entry, operation) => {
2974
+ forEachOperation5(spec, (entry, operation) => {
2900
2975
  if (operation["x-pagination"]) {
2901
2976
  switch (operation["x-pagination"].type) {
2902
2977
  case "offset":
@@ -3087,12 +3162,19 @@ ${template2(dispatcher_default, {})({ throwError: !style.errorAsValue, outputTyp
3087
3162
  "models/index.ts": modelsIndex
3088
3163
  // ...(modelsImports.length ? { 'models/index.ts': modelsIndex } : {}),
3089
3164
  });
3090
- if (settings.agentTools) {
3091
- await settings.writer(output, {
3092
- "agents.ts": `${generateAISDKTools(spec)}
3165
+ switch (settings.agentTools) {
3166
+ case "openai-agents":
3167
+ await settings.writer(output, {
3168
+ "agents.ts": `${generateOpenAIAgentTools(spec)}
3093
3169
  ${utils_default}`
3094
- // 'agents.ts': `${generateOpenAIAgentTools(spec)}\n${utilsTxt}`,
3095
- });
3170
+ });
3171
+ break;
3172
+ case "ai-sdk":
3173
+ await settings.writer(output, {
3174
+ "agents.ts": `${generateAISDKTools(spec)}
3175
+ ${utils_default}`
3176
+ });
3177
+ break;
3096
3178
  }
3097
3179
  await settings.writer(output, {
3098
3180
  "index.ts": await getFolderExports(
@@ -3217,7 +3299,7 @@ function toInputs(operationsSet, commonZod, makeImport) {
3217
3299
  const output = [];
3218
3300
  const imports = /* @__PURE__ */ new Set(['import { z } from "zod";']);
3219
3301
  for (const operation of operations) {
3220
- const schemaName = camelcase5(`${operation.operationId} schema`);
3302
+ const schemaName = camelcase6(`${operation.operationId} schema`);
3221
3303
  const schema = `export const ${schemaName} = ${Object.keys(operation.schemas).length === 1 ? Object.values(operation.schemas)[0] : toLitObject2(operation.schemas)};`;
3222
3304
  for (const it of commonImports) {
3223
3305
  if (schema.includes(it)) {