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