feat(ai+interop): AIFunction schema auto-generation + A2A protocol adapter#126
feat(ai+interop): AIFunction schema auto-generation + A2A protocol adapter#126
Conversation
… support Introduce AgentToolSchemaGenerator, AgentToolBase<TParams>, and LLMResponseFormat to eliminate hand-written JSON Schema maintenance and enable structured LLM output. Closes #98 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Propagate ResponseFormat in TornadoLLMProvider request rebuild - Add ConcurrentDictionary caching to AgentToolSchemaGenerator - Fix JSON injection in AgentToolBase error path - Revert unintentional global.json SDK version change Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea0a0eeab9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| string? schemaDescription = null) => | ||
| new LLMResponseFormatJsonSchema( | ||
| AgentToolSchemaGenerator.GenerateSchema<T>(), | ||
| schemaName ?? typeof(T).Name, |
There was a problem hiding this comment.
Sanitize inferred schema names for generic formats
ForJsonSchema<T>() uses typeof(T).Name directly, which produces invalid identifiers for common CLR types (for example generic types become names like MyType\1). That value is then forwarded unchanged into ChatResponseFormat.ForJsonSchema(...), so structured-output requests can fail for these types when providers validate schema names. Please sanitize/normalize the inferred name (or pass nullto let the downstream layer infer safely) before constructingLLMResponseFormatJsonSchema`.
Useful? React with 👍 / 👎.
| string? schemaDescription = null) | ||
| { | ||
| Kind = LLMResponseFormatKind.JsonSchema; | ||
| Schema = schema; |
There was a problem hiding this comment.
Clone JsonElement schema before storing it
The constructor stores the incoming JsonElement by reference, so callers who pass JsonDocument.Parse(...).RootElement without Clone() end up with a schema tied to a disposed document. When the provider later reads Schema, this can throw ObjectDisposedException at runtime. Clone the element at assignment time to decouple LLMResponseFormatJsonSchema from caller document lifetimes.
Useful? React with 👍 / 👎.
…nt interoperability Implement the A2A (Agent-to-Agent) protocol adapter with three-layer architecture: - Abstractions: A2A protocol types (AgentCard, A2ATask, Message, Part, JSON-RPC) - Application: A2AAdapterService (protocol conversion) + InMemoryA2ATaskStore - Hosting: HTTP endpoints (/.well-known/agent.json, /a2a JSON-RPC, /a2a/subscribe SSE) Closes #99 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace [JsonDerivedType] with custom PartJsonConverter that uses A2A-spec "type" field discriminator for Part deserialization - Replace SSE polling (Task.Delay) with channel-based subscription via IA2ATaskStore.SubscribeAsync / ChannelReader - Add 6 new tests for Part serialization round-trip and TaskSendParams deserialization from JSON-RPC format Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix subscribe-after-terminal race: SubscribeAsync now checks current task state under lock and immediately delivers final status + completes - Fix index-after-removal in NotifySubscribers: separate write and complete paths to avoid accessing wrong subscriber after RemoveAt - Add 3 subscription tests including subscribe-after-terminal-state Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sanitize generic CLR type names in ForJsonSchema<T>() to avoid invalid schema names like MyType`1 - Clone JsonElement in LLMResponseFormatJsonSchema constructor to decouple from caller's JsonDocument lifetime Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolve leftover merge conflict markers — keep dev-side content with frontmatter and updated docs paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover edge cases: SanitizeTypeName generic suffix, concurrent schema caching, whitespace/extra-property deserialization, multi-text-part joining, negative historyLength, terminal-state cancel rejection, multiple subscribers, artifact notifications, JSON-RPC model round-trips, and DataPart serialization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Issue #98: AIFunction Schema Auto-Generation
AgentToolSchemaGenerator— auto-generate JSON Schema from C# types using .NETJsonSchemaExporterAgentToolBase<TParams>— typed base class with auto-derived schema and typedExecuteAsyncLLMResponseFormat(Text / JsonObject / JsonSchema) withForJsonSchema<T>()for structured outputResponseFormatpropagated through all internal request rebuild pathsIssue #99: A2A Protocol Adapter Layer
A2AAdapterServiceconverts A2A JSON-RPC toIActorDispatchPort.DispatchAsyncviaEventEnvelope/.well-known/agent.json,/a2a(JSON-RPC),/a2a/subscribe/{taskId}(SSE)InMemoryA2ATaskStorewith interface for future persistenceTest plan
AgentToolSchemaGeneratorTests— 10 testsAgentToolBaseTests— 8 testsLLMResponseFormatTests— 6 testsInMemoryA2ATaskStoreTests— 8 testsA2AAdapterServiceTests— 12 testsJsonRpcModelTests— 5 testsdotnet build aevatar.slnx— 0 errorsCloses #98
Closes #99
🤖 Generated with Claude Code