History

Register standard JSON Schema formats

Rhys Sullivan committed 7 months ago

Commit 2b1e1401 parent f7749984 files · +78 −1Browse files

Unified · Split

4 files
  1. bun.lock +2 −1
  2. packages/kernel/core/package.json +1 −0
  3. packages/kernel/core/src/index.test.ts +72 −0
  4. packages/kernel/core/src/json-schema.ts +3 −0
bun.lock+2−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
1919 },
2020 "apps/executor": {
2121 "name": "executor",
22− "version": "1.3.0-beta.0",
22+ "version": "1.3.0-beta.3",
2323 "bin": {
2424 "executor": "bin/executor",
2525 },
@@ -239,6 +239,7 @@ · 213 unmodified lines
239239 "dependencies": {
240240 "@standard-schema/spec": "^1.0.0",
241241 "ajv": "^8.17.1",
242+ "ajv-formats": "^3.0.1",
242243 "effect": "catalog:",
243244 },
244245 "devDependencies": {
packages/kernel/core/package.json+1−0
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 "dependencies": {
1414 "@standard-schema/spec": "^1.0.0",
1515 "ajv": "^8.17.1",
16+ "ajv-formats": "^3.0.1",
1617 "effect": "catalog:"
1718 },
1819 "devDependencies": {
packages/kernel/core/src/index.test.ts+72−0
@@ -282,6 +282,67 @@ describe("codemode-core", () => { · 281 unmodified lines
282282 }),
283283 );
284284
285+ it.effect("enforces standard JSON Schema string formats", () =>
286+ Effect.gen(function* () {
287+ const tools = {
288+ "events.create": {
289+ inputSchema: standardSchemaFromJsonSchema({
290+ type: "object",
291+ required: ["dateFrom", "issueId", "email", "documentationUrl"],
292+ properties: {
293+ dateFrom: { type: "string", format: "date-time" },
294+ issueId: { type: "string", format: "uuid" },
295+ email: { type: "string", format: "email" },
296+ documentationUrl: { type: "string", format: "uri" },
297+ },
298+ additionalProperties: false,
299+ }),
300+ execute: (input: unknown) => input,
301+ },
302+ } satisfies ToolMap;
303+
304+ const invoker = makeToolInvokerFromTools({ tools });
305+
306+ const success = yield* invoker.invoke({
307+ path: "events.create",
308+ args: {
309+ dateFrom: "2026-03-30T12:00:00Z",
310+ issueId: "2c981f4a-7318-47a3-a3d3-8c145ee8ca1f",
311+ email: "rhys@example.com",
312+ documentationUrl: "https://example.com/docs",
313+ },
314+ });
315+
316+ expect(success).toEqual({
317+ dateFrom: "2026-03-30T12:00:00Z",
318+ issueId: "2c981f4a-7318-47a3-a3d3-8c145ee8ca1f",
319+ email: "rhys@example.com",
320+ documentationUrl: "https://example.com/docs",
321+ });
322+
323+ const failure = yield* Effect.either(
324+ invoker.invoke({
325+ path: "events.create",
326+ args: {
327+ dateFrom: "not-a-date",
328+ issueId: "not-a-uuid",
329+ email: "not-an-email",
330+ documentationUrl: "not-a-uri",
331+ },
332+ }),
333+ );
334+
335+ assertTrue(Either.isLeft(failure));
336+ assertInstanceOf(failure.left, Error);
337+ expect(failure.left.message).toContain('dateFrom: format: must match format "date-time"');
338+ expect(failure.left.message).toContain('issueId: format: must match format "uuid"');
339+ expect(failure.left.message).toContain('email: format: must match format "email"');
340+ expect(failure.left.message).toContain(
341+ 'documentationUrl: format: must match format "uri"',
342+ );
343+ }),
344+ );
345+
285346 it.effect("hydrates dynamic discover results via tool catalog", () =>
286347 Effect.gen(function* () {
287348 const descriptors: Record<string, ToolDescriptor> = {
@@ -373,6 +434,17 @@ describe("codemode-core", () => { · 85 unmodified lines
373434 expect(discovered.bestPath).toBe("source.issues.create");
374435 expect(discovered.results[0]?.path).toBe("source.issues.create");
375436 expect(discovered.results[0]?.interaction).toBe("required");
437+
438+ const executeDescription = yield* dynamic.executeDescription;
439+ expect(executeDescription).toContain(
440+ 'const { results, bestPath } = await tools.discover({ query: "<intent>", limit: 12 });',
441+ );
442+ expect(executeDescription).toContain(
443+ 'const path = bestPath ?? results[0]?.path; if (!path) return "No matching tools found.";',
444+ );
445+ expect(executeDescription).toContain(
446+ "Object.keys(tools) is not a useful way to discover capabilities.",
447+ );
376448 }),
377449 );
378450
packages/kernel/core/src/json-schema.ts+3−0
@@ -1,5 +1,6 @@
11 import type { ErrorObject } from "ajv";
22 import Ajv2020 from "ajv/dist/2020";
3+import addFormats from "ajv-formats";
34
45 import type { StandardSchema } from "./types";
56 import { unknownInputSchema } from "./types";
@@ -11,6 +12,8 @@ const ajv = new Ajv2020({ · 5 unmodified lines
1112 allowUnionTypes: true,
1213 });
1314
15+addFormats(ajv);
16+
1417 const decodePointerSegment = (segment: string): PropertyKey => {
1518 const decoded = segment.replaceAll("~1", "/").replaceAll("~0", "~");
1619 return /^\d+$/.test(decoded) ? Number(decoded) : decoded;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t