| @@ -282,6 +282,67 @@ describe("codemode-core", () => { · 281 unmodified lines |
| 282 | 282 | }), |
| 283 | 283 | ); |
| 284 | 284 | |
| 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 | + |
| 285 | 346 | it.effect("hydrates dynamic discover results via tool catalog", () => |
| 286 | 347 | Effect.gen(function* () { |
| 287 | 348 | const descriptors: Record<string, ToolDescriptor> = { |
| @@ -373,6 +434,17 @@ describe("codemode-core", () => { · 85 unmodified lines |
| 373 | 434 | expect(discovered.bestPath).toBe("source.issues.create"); |
| 374 | 435 | expect(discovered.results[0]?.path).toBe("source.issues.create"); |
| 375 | 436 | 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 | + ); |
| 376 | 448 | }), |
| 377 | 449 | ); |
| 378 | 450 | |