Skip to content

Commit 6b3ec48

Browse files
tylergibbs1claude
andcommitted
Upgrade to Zod 4, add 55 tests, bump to v0.8.0
- Replace hand-rolled zodToJsonSchema (94 lines) with Zod 4's built-in z.toJSONSchema() — covers all schema types, zero maintenance - Peer dep bumped from zod@^3 to zod@^4 (breaking) - 55 new unit tests across 6 files: - stream-edge-cases: abort, event ordering, usage accumulation - handoff-chains: A→B→C, system prompts, guardrail interactions - concurrent-tool-calls: parallel execution, failure isolation, ordering - tool-validation: malformed args, type mismatches, sync throws - model-errors: 429 retry, 401/503, content filter, exhausted retries - tracing-extended: multi-call spans, errors, concurrency, metadata Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9a096bc commit 6b3ec48

9 files changed

Lines changed: 1718 additions & 94 deletions

bun.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "stratus-sdk",
3-
"version": "0.7.6",
3+
"version": "0.8.0",
44
"type": "module",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",
@@ -28,12 +28,12 @@
2828
"test": "bun test"
2929
},
3030
"peerDependencies": {
31-
"zod": "^3.23.0"
31+
"zod": "^4.0.0"
3232
},
3333
"devDependencies": {
3434
"@biomejs/biome": "^1.9.0",
3535
"@types/bun": "^1.3.9",
3636
"typescript": "^5.6.0",
37-
"zod": "^3.23.0"
37+
"zod": "^4.0.0"
3838
}
3939
}

src/core/utils/zod.ts

Lines changed: 5 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,9 @@
1-
import type { z } from "zod";
1+
import { type ZodTypeAny, toJSONSchema } from "zod";
22

33
type JsonSchema = Record<string, unknown>;
44

5-
export function zodToJsonSchema(schema: z.ZodTypeAny): JsonSchema {
6-
return convertSchema(schema);
7-
}
8-
9-
function convertSchema(schema: z.ZodTypeAny): JsonSchema {
10-
const def = schema._def;
11-
const typeName = def.typeName as string;
12-
13-
switch (typeName) {
14-
case "ZodObject":
15-
return convertObject(schema as z.ZodObject<z.ZodRawShape>);
16-
case "ZodString":
17-
return withDescription({ type: "string" }, def.description);
18-
case "ZodNumber":
19-
return withDescription({ type: "number" }, def.description);
20-
case "ZodBoolean":
21-
return withDescription({ type: "boolean" }, def.description);
22-
case "ZodArray":
23-
return withDescription(
24-
{ type: "array", items: convertSchema(def.type) },
25-
def.description,
26-
);
27-
case "ZodEnum":
28-
return withDescription(
29-
{ type: "string", enum: def.values as string[] },
30-
def.description,
31-
);
32-
case "ZodNativeEnum":
33-
return withDescription(
34-
{ type: "string", enum: Object.values(def.values as Record<string, string>) },
35-
def.description,
36-
);
37-
case "ZodOptional":
38-
return convertSchema(def.innerType);
39-
case "ZodNullable":
40-
return { ...convertSchema(def.innerType), nullable: true };
41-
case "ZodDefault":
42-
return convertSchema(def.innerType);
43-
case "ZodLiteral":
44-
return withDescription({ type: typeof def.value, const: def.value }, def.description);
45-
case "ZodUnion": {
46-
const options = (def.options as z.ZodTypeAny[]).map(convertSchema);
47-
return withDescription({ anyOf: options }, def.description);
48-
}
49-
default:
50-
return {};
51-
}
52-
}
53-
54-
function convertObject(schema: z.ZodObject<z.ZodRawShape>): JsonSchema {
55-
const shape = schema.shape;
56-
const properties: Record<string, JsonSchema> = {};
57-
const required: string[] = [];
58-
59-
for (const [key, value] of Object.entries(shape)) {
60-
const fieldSchema = value as z.ZodTypeAny;
61-
properties[key] = convertSchema(fieldSchema);
62-
63-
if (!isOptional(fieldSchema)) {
64-
required.push(key);
65-
}
66-
}
67-
68-
const result: JsonSchema = {
69-
type: "object",
70-
properties,
71-
additionalProperties: false,
72-
};
73-
74-
if (required.length > 0) {
75-
result.required = required;
76-
}
77-
78-
return withDescription(result, schema._def.description);
79-
}
80-
81-
function isOptional(schema: z.ZodTypeAny): boolean {
82-
const typeName = schema._def.typeName as string;
83-
if (typeName === "ZodOptional") return true;
84-
if (typeName === "ZodDefault") return true;
85-
return false;
86-
}
87-
88-
function withDescription(schema: JsonSchema, description?: string): JsonSchema {
89-
if (description) {
90-
return { ...schema, description };
91-
}
92-
return schema;
5+
export function zodToJsonSchema(schema: ZodTypeAny): JsonSchema {
6+
const result = toJSONSchema(schema) as JsonSchema;
7+
delete result.$schema;
8+
return result;
939
}

0 commit comments

Comments
 (0)